據(jù)接入實(shí)戰(zhàn):一套 API 搞定多市場(chǎng)量化數(shù)據(jù)管道)
做量化這幾年我踩過(guò)最多的坑不是策略而是數(shù)據(jù)。最早接美股的時(shí)候用的某家老牌數(shù)據(jù)商文檔寫得像天書SDK 只支持 Python 2光調(diào)通一個(gè)歷史K線接口就花了我三天。后來(lái)業(yè)務(wù)擴(kuò)展到港股和A股又分別接了兩個(gè)不同的數(shù)據(jù)源三套接口、三種鑒權(quán)方式、兩套字段命名每天光維護(hù)數(shù)據(jù)同步腳本就要占掉半天。上個(gè)月團(tuán)隊(duì)要做一個(gè)覆蓋全球主要市場(chǎng)的選股策略我實(shí)在不想再維護(hù)第四套數(shù)據(jù)接入了花了一周時(shí)間調(diào)研選型最后用一套統(tǒng)一的 REST WebSocket API 搭好了跨市場(chǎng)數(shù)據(jù)管道。這篇文章記錄一下整個(gè)接入過(guò)程和技術(shù)細(xì)節(jié)給同樣在折騰多市場(chǎng)數(shù)據(jù)的朋友一個(gè)參考。選型思路選數(shù)據(jù)源我主要看三點(diǎn)覆蓋市場(chǎng)夠不夠廣、接口是不是統(tǒng)一、延遲穩(wěn)不穩(wěn)定。我最終選的這套方案覆蓋的市場(chǎng)比較全美股、港股、A股、臺(tái)灣、新加坡、日本、印度、泰國(guó)、德國(guó)、英國(guó)、荷蘭這些主流市場(chǎng)都有外加外匯、指數(shù)、期貨、基金、加密貨幣基本上一個(gè) API 就能搞定大部分場(chǎng)景。接口統(tǒng)一這點(diǎn)對(duì)我來(lái)說(shuō)是最大的痛點(diǎn)解決。不管是股票還是外匯REST API 的調(diào)用方式、參數(shù)結(jié)構(gòu)、返回字段都是一套規(guī)范不用每個(gè)市場(chǎng)都重新學(xué)一遍。WebSocket 也是統(tǒng)一的發(fā)布訂閱模式連上之后訂閱什么品種就收什么數(shù)據(jù)。延遲方面我實(shí)測(cè)了一周美股盤口數(shù)據(jù)推送基本在毫秒級(jí)至少我這一周沒(méi)遇到過(guò)斷連。第一步REST API 拉歷史K線先從最簡(jiǎn)單的開(kāi)始。這套 API 用 header 傳 token 鑒權(quán)注冊(cè)賬號(hào)后在控制臺(tái)生成一個(gè) token 就能用。拉港股騰訊控股700和阿里巴巴9988最近5根5分鐘K線直接一個(gè) GET 請(qǐng)求importrequests urlhttps://api.itick.org/stock/klines?regionHKcodes700,9988kType2limit5headers{accept:application/json,token:你的token}responserequests.get(url,headersheaders)print(response.json())參數(shù)說(shuō)幾個(gè)關(guān)鍵點(diǎn)region是市場(chǎng)代碼HK是港股US是美股SH/SZ是滬深codes支持批量逗號(hào)分隔kType是K線周期11分鐘25分鐘315分鐘430分鐘51小時(shí)8日線9周線10月線返回的數(shù)據(jù)結(jié)構(gòu)是這樣的{code:0,msg:null,data:{700:[{o:535,h:536,l:534.5,c:534.5,v:104799385,tu:56119888070.5,t:1741239000000}],9988:[{o:139.9,h:140.3,l:139.8,c:140.1,v:538602171,tu:75404622753.1,t:1741239000000}]}}標(biāo)準(zhǔn)的 OHLCV 結(jié)構(gòu)t是毫秒級(jí)時(shí)間戳tu是成交額。拿到數(shù)據(jù)后直接丟進(jìn) pandas 就能算指標(biāo)了不用做任何字段映射。我對(duì)比了一下同樣的日線數(shù)據(jù)復(fù)權(quán)處理是對(duì)的拆股和分紅都自動(dòng)調(diào)整過(guò)了不用自己再算復(fù)權(quán)因子。第二步WebSocket 訂閱實(shí)時(shí)行情歷史數(shù)據(jù)搞定了接下來(lái)是實(shí)時(shí)行情。做策略的都知道輪詢 REST API 既浪費(fèi)調(diào)用次數(shù)又有延遲WebSocket 才是正道。這套 API 的 WebSocket 是發(fā)布訂閱模式連上之后發(fā)一條訂閱消息就行。我用 Python SDK 來(lái)演示比自己手寫 websocket 連接省事很多fromitick.sdkimportClientimporttime# 初始化客戶端token你的tokenclientClient(token)# 設(shè)置消息回調(diào)defon_message(message):print(f收到行情:{message})defon_error(error):print(f連接錯(cuò)誤:{error})client.set_message_handler(on_message)client.set_error_handler(on_error)# 連接股票WebSocketclient.connect_stock_websocket()# 訂閱騰訊控股實(shí)時(shí)行情client.send_websocket_message({action: subscribe, codes: [700]})# 保持連接try:whileTrue:time.sleep(1)exceptKeyboardInterrupt:client.close_websocket()SDK 內(nèi)置了自動(dòng)重連和心跳維護(hù)斷網(wǎng)后會(huì)自動(dòng)重連并恢復(fù)訂閱不用自己寫重連邏輯。重連間隔5秒最多重試10次心跳30秒一次這些參數(shù)對(duì)大多數(shù)場(chǎng)景都?jí)蛴昧?。?shí)時(shí)推送的數(shù)據(jù)包含最新價(jià)、買賣盤口、成交量這些做盤中策略完全夠用。我同時(shí)訂閱了20只股票推送頻率很穩(wěn)沒(méi)有遇到丟數(shù)據(jù)的情況。第三步SDK 與直接調(diào) API 的選擇這套方案提供了 Python SDK 和 Java SDK我兩個(gè)都試了一下。如果你的項(xiàng)目是 Python用 SDK 會(huì)方便一些pip install itick-sdk裝好封裝了所有 REST 接口和 WebSocket 連接fromitick.sdkimportClient clientClient(你的token)# 股票實(shí)時(shí)報(bào)價(jià)quoteclient.get_stock_quote(US,AAPL)print(f蘋果最新價(jià):{quote[ld]})# 歷史K線klineclient.get_stock_kline(US,AAPL,kType8,limit30)# 外匯實(shí)時(shí)tickforex_tickclient.get_forex_tick(GB,EURUSD)# 加密貨幣深度crypto_depthclient.get_crypto_depth(BA,BTCUSDT)方法命名比較直觀get_stock_quote、get_stock_kline、get_forex_tick看名字就知道干嘛的。如果你用的語(yǔ)言沒(méi)有官方 SDK直接調(diào) REST API 也很簡(jiǎn)單就是標(biāo)準(zhǔn)的 HTTP 請(qǐng)求加 header 鑒權(quán)沒(méi)有什么復(fù)雜的簽名算法。數(shù)據(jù)質(zhì)量驗(yàn)證做量化的對(duì)數(shù)據(jù)質(zhì)量都很敏感我重點(diǎn)驗(yàn)證了幾個(gè)方面復(fù)權(quán)處理美股拆股、港股供股、A股分紅這些場(chǎng)景下的前復(fù)權(quán)數(shù)據(jù)都是對(duì)的我抽了幾只歷史上有拆股的股票對(duì)比過(guò)沒(méi)有出現(xiàn)價(jià)格斷層。時(shí)間戳對(duì)齊不同市場(chǎng)的交易時(shí)間不一樣返回的時(shí)間戳都是 UTC 毫秒自己轉(zhuǎn)成本地時(shí)間就行不會(huì)出現(xiàn)時(shí)區(qū)混亂的問(wèn)題。缺失數(shù)據(jù)停牌期間的K線會(huì)跳過(guò)不會(huì)用0或者上一個(gè)價(jià)格填充這點(diǎn)比有些數(shù)據(jù)商處理得好不用自己再過(guò)濾異常值。盤口深度能拿到5檔盤口普通趨勢(shì)策略夠用了。接入踩坑記錄最后說(shuō)幾個(gè)我接入時(shí)遇到的小問(wèn)題幫大家省點(diǎn)時(shí)間region 參數(shù)別寫錯(cuò)美股是US不是USA港股是HK不是HKG剛開(kāi)始我寫錯(cuò)了返回空數(shù)據(jù)查了半天才發(fā)現(xiàn)。WebSocket 訂閱 codes 是數(shù)組別傳字符串要傳[700, 9988]這種數(shù)組格式。注意調(diào)用頻率限制寫循環(huán)的時(shí)候記得加 sleep不然會(huì)被限流。歷史數(shù)據(jù)深度不同市場(chǎng)的歷史數(shù)據(jù)深度不一樣美股能到十幾年一些小市場(chǎng)可能只有幾年回測(cè)前先確認(rèn)數(shù)據(jù)量夠不夠。token 別硬編碼放環(huán)境變量里代碼上傳到 Git 之前檢查一下別把 token 提交上去了??偨Y(jié)用了這套方案一個(gè)月最大的感受就是省時(shí)間。以前接三個(gè)市場(chǎng)的數(shù)據(jù)要維護(hù)三套代碼現(xiàn)在一個(gè) SDK 全搞定省下來(lái)的時(shí)間能多研究幾個(gè)策略。如果你也在做多市場(chǎng)量化或者正在為數(shù)據(jù)源的事情頭疼建議在選型時(shí)重點(diǎn)關(guān)注接口統(tǒng)一性和市場(chǎng)覆蓋度這兩點(diǎn)直接決定了后期維護(hù)成本。