Skip to main content

開始使用

本頁重點
  • 富邦行情期貨 WebSocket API(富邦新一代 API 期貨行情服務)提供期貨即時行情訂閱。
  • 支援 Speed / Normal 兩種行情模式。
  • 需登入後建立行情連線並訂閱頻道。
  • 下一步可前往各頻道說明頁。
項目說明
介面WebSocket API
市場期貨 / 期權
模式Speed / Normal
SDKPython / Node.js / C#
訂閱方式連線後訂閱頻道

富邦行情 WebSocket API 提供期貨即時行情服務。透過 WebSocket API 可以滿足您想要接收即時行情的需求。

使用 SDK​

富邦行情 WebSocket API 提供 Python 、 Node.js 與 C# SDK。您可以透過以下方式存取 WebSocket API、並透過行情 Mode 模式切換要訂閱的行情:

訂閱 WebSocket Callback 方法獲得下方 Callback 訊息。

info

行情 Mode 提供 Low Latency Speed Mode 以及完整資訊的 Normal Mode

期權行情連線版本

期權行情 WebSocket 提供 v1.0 與 v1.1 兩個連線版本,建立連線時未指定版本即連到 v1.1。trades 與 books 頻道的試撮訊息(isTrial)僅 v1.1 連線推送,指定連到 v1.0 則不會收到;aggregates 頻道在兩個版本都會推送試撮期間的更新。股票行情僅提供 v1.0。此參數 v2.2.9 起提供。

from fubon_neo.sdk import FubonSDK, Mode

def handle_message(message):
print(message)

sdk = FubonSDK()
accounts = sdk.login("Your ID", "Your password", "Your cert path", "Your cert password") # 需登入後,才能取得行情權限

sdk.init_realtime() # 建立行情連線
# 可指定行情連線的Mode , Default 為Speed
# sdk.init_realtime(Mode.Speed) or sdk.init_realtime(Mode.Normal)
# 可指定期權行情連線版本,未指定為 v1.1;連到 v1.0 則不接收 trades/books 試撮訊息
# sdk.init_realtime(Mode.Speed, version={"futopt": "v1.0"})
# 連線後可由 sdk.marketdata.websocket_client.futopt.url 確認實際連上的版本

futopt = sdk.marketdata.websocket_client.futopt
futopt.on('message', handle_message)
futopt.connect()

身份驗證​

當驗證成功後,會收到以下訊息:

{
"event": "authenticated",
"data": {
"message": "Authenticated successfully"
}
}

若驗證失敗,則收到以下訊息:

{
"event": "error",
"data": {
"message": "Invalid authentication credentials"
}
}

Heartbeat​

每隔 30 秒 WebSocket server 會送出一個 heartbeat 訊息:

{
"event": "heartbeat",
"data": {
"time": "<Timestamp>"
}
}

Ping/Pong​

SDK 每 30 秒會自動發送一次 ping 到伺服器;您也可以自行發送 ping,並可額外自訂 state(選填):

futopt.ping({
'state' : '<ANY>'
})

WebSocket Server 會回應以下訊息 (若 ping 未送 state 則不會有該欄位):

{
"event": "pong",
"data": {
"time": "<TIMESTAMP>",
"state": "<ANY>"
}
}

Channels​

富邦行情 WebSocket API 目前提供以下可訂閱頻道:

期貨/選擇權行情功能一覽​

自 v2.2.9 起提供下列行情功能:

  • 連續月行情:可用 {ROOT}1!/2!/3! 訂閱近月別名;請見下方 連續月別名。
  • 價差合約行情:先以 Intraday Tickers 的 isSpread=true 取得價差合約代碼,再將回傳的 symbol 用於 WebSocket 訂閱;請見下方 價差契約訂閱。
  • 延伸一檔報價:books 頻道的 derivedBid/derivedAsk 提供衍生最佳一檔報價,主要適用於價差合約。
  • 試撮資訊:books 的 isTrial 與 aggregates 的 lastTrial 用於揭示試撮階段資訊。

訂閱頻道​

要訂閱一個頻道可用下方範例進行訂閱:

futopt.subscribe({
"channel" : "<CHANNEL_NAME>",
"symbol" : "<SYMBOL_ID>"
#"afterHours" : True 若要訂閱夜盤行情,可再額外加入此參數
})

訂閱成功後,會收到以下事件回應:

{
"event": "subscribed",
"data": {
"id": "<CHANNEL_ID>",
"channel": "<CHANNEL_NAME>",
"symbol": "<SYMBOL_ID>"
}
}

支援訂閱同頻道的多檔商品:

futopt.subscribe({
"channel" : "<CHANNEL_NAME>",
"symbols" : ["<SYMBOL_ID>","<SYMBOL_ID>"]
#"afterHours" : True 若要訂閱夜盤行情,可再額外加入此參數
})

訂閱成功後,會收到以下事件回應:

{
"event": "subscribed",
"data": [
{
"id": "<CHANNEL_ID>",
"channel": "<CHANNEL_NAME>",
"symbol": "<SYMBOL_ID_1>"
},
{
"id": "<CHANNEL_ID>",
"channel": "<CHANNEL_NAME>",
"symbol": "<SYMBOL_ID_2>"
}
]
}

連續月別名​

訂閱時的 symbol 除了具體合約代碼(如 TXFG6),也可使用連續月別名 {ROOT}1!/2!/3! 訂閱第 1/2/3 近月合約(如 TXF1! 為最近月臺股期貨)。系統會於送出訂閱的當下解析為對應的具體合約,data 事件回傳的 symbol 為解析後的具體合約代碼。詳見 Web API — 商品代碼與連續月別名。

別名只在訂閱當下解析一次

別名只在送出訂閱的當下解析一次,之後訂閱固定綁在該合約,跨結算日不會自動轉倉(舊合約結算後將收不到資料)。長效連線請於換月後重新訂閱(先 unsubscribe 再 subscribe)或改用具體合約代碼;Web API 每次呼叫都重新解析,不受影響。

futopt.subscribe({
"channel": "trades",
"symbol": "TXF1!" # 連續月別名,訂閱最近月臺股期貨
#"afterHours" : True 若要訂閱夜盤行情,可再額外加入此參數
})

價差契約訂閱​

價差契約(如 TXFJ6/K6)同樣以 symbol 欄位訂閱,代碼原樣放入即可,訂閱成功後會收到該價差契約的行情資料。價差契約代碼格式詳見 價差契約。

futopt.subscribe({
"channel": "books",
"symbol": "TXFJ6/K6"
})

取消訂閱​

要取消頻道可用下方範例進行取消:

futopt.unsubscribe({
'id':'<CHANNEL_ID>'
})

取消訂閱成功後,會收到以下事件回應:

{
"event": "unsubscribed",
"data": {
"id": "<CHANNEL_ID>",
"channel" : "<CHANNEL_NAME>",
"symbol" : "<SYMBOL_ID>"
}
}

支援取消訂閱多個頻道:

futopt.unsubscribe({
'ids':['<CHANNEL_ID>','<CHANNEL_ID>']
})

取消訂閱成功後,會收到以下事件回應:

{
"event": "unsubscribed",
"data": [
{
"id": "<CHANNEL_ID_1>",
"channel" : "<CHANNEL_NAME>",
"symbol" : "<SYMBOL_ID>"
},
{
"id": "<CHANNEL_ID_2>",
"channel" : "<CHANNEL_NAME>",
"symbol" : "<SYMBOL_ID>"
}
]
}

訂閱資訊​

要取得目前連線已訂閱的頻道清單,可用下方範例查詢:

futopt.subscriptions()

會收到以下事件回應:

{
"event": "subscriptions",
"data": [
{
"id": "<CHANNEL_ID>",
"channel": "<CHANNEL_NAME>",
"symbol": "<SYMBOL_ID>"
}
]
}

錯誤處理​

當您所訂閱或處理的 WebSocket Callback 有異常時,您可補充處理錯誤訊息如下。

disconnect 事件在兩種情況觸發:伺服器關閉連線,以及連線健康檢查逾時(超過約 60 秒未收到伺服器任何訊息時,SDK 會主動關閉連線並發出此事件)。逾時斷線在各語言的通知形態,見各範例下方說明。

def handle_connect():
print('market data connected')


def handle_disconnect(code, message, *reason): # 連線健康檢查逾時斷線時會多帶一個參數
print(f'market data disconnect: {code}, {message}')


def handle_error(error):
print(f'market data error: {error}')

futopt.on("connect", handle_connect)
futopt.on("disconnect", handle_disconnect)
futopt.on("error", handle_error)

健康檢查逾時斷線時,disconnect 會多帶第三個參數 {'reason': 'health-check-timeout'},handler 以 *reason 接住即可。

斷線重連​

連線中斷後,SDK 不會自動重新連線,也不會保留原有訂閱;程式需在收到 disconnect 事件後重新連線,並重新送出所有訂閱。以下範例接續上方的登入與建立連線程式:收到斷線事件後在背景重新連線與訂閱,重試間隔逐次拉長(2、4、8、16、30 秒)並以 5 次為上限,避免網路尚未恢復時短時間內大量重連。訂閱清單每個頻道一筆、以 symbols 一次訂閱多檔,重連後重新訂閱的呼叫次數等於頻道數,不隨檔數增加。

# 接續 futopt = sdk.marketdata.websocket_client.futopt 之後,取代原本的 futopt.connect()
import threading
import time

SUBSCRIPTIONS = [ # 初次訂閱與重連後重新訂閱共用同一份清單;每個頻道一筆,多檔用 symbols
{'channel': 'trades', 'symbols': ['TXF1!', 'MXF1!'], 'afterHours': True},
]
reconnect_needed = threading.Event()

def handle_disconnect(code, message, *reason): # 連線健康檢查逾時斷線時會多帶一個參數,用 *reason 接住
print(f'market data disconnect: {code}, {message}')
reconnect_needed.set() # 只通知,不在此直接重連

def subscribe_all():
for params in SUBSCRIPTIONS:
futopt.subscribe(params)

def connect_with_timeout(seconds=10):
# 網路不通時 connect() 不會返回,另開執行緒加上逾時
result = {}
def run():
try:
futopt.connect()
except Exception as error:
result['error'] = error
worker = threading.Thread(target=run, daemon=True)
worker.start()
worker.join(seconds)
if worker.is_alive():
raise TimeoutError('connect timeout')
if 'error' in result:
raise result['error']

def reconnect_loop():
retries = 0
while reconnect_needed.wait():
reconnect_needed.clear()
retries += 1
if retries > 5:
print('Reconnect failed 5 times, please check the network')
return
time.sleep(min(2 ** retries, 30)) # 等 2、4、8、16、30 秒後再試
try:
futopt.disconnect() # 先重設連線狀態,否則 connect() 不會重新連線
connect_with_timeout()
subscribe_all()
retries = 0
print('Reconnected and resubscribed')
except Exception as error:
print(f'Reconnect failed: {error}')
reconnect_needed.set()

futopt.on('disconnect', handle_disconnect)
threading.Thread(target=reconnect_loop, daemon=True).start()

futopt.connect()
subscribe_all()