2. 数据源接入:交易所API、第三方数据商与WebSocket

好,咱们进入第二章。数据源接入,说白了就是解决一个问题——Tick数据从哪来

我个人习惯把数据源分成三类:交易所直连、第三方数据商、WebSocket流式推送。这三条路我都走过,各有各的坑。今天我把它们掰开揉碎了讲清楚。

2.1 交易所API:最原始,也最折腾

先聊交易所直连。这是最正统的方式,也是我最早接触的方式。

交易所API通常提供两种接口:REST和WebSocket。REST用来拉历史数据,WebSocket用来收实时行情。

举个例子,币安的REST接口长这样:

GET /api/v3/klines?symbol=BTCUSDT&interval=1m&limit=1000

返回的是K线数据。但你要Tick数据?抱歉,大部分交易所不直接给。你得自己从深度快照里算。

注意: 交易所API有频率限制。币安是1200次/分钟,火币是100次/秒。超了直接封IP。我在项目中遇到过,半夜跑脚本忘了限流,第二天发现IP被拉黑了整整24小时。

所以,接入交易所API时,我建议你做好三件事:

  • 限流器:用令牌桶算法控制请求频率
  • 重试机制:网络抖动是常态,指数退避重试是标配
  • 数据校验:交易所返回的数据偶尔会丢字段,校验不能省

2.2 第三方数据商:花钱买省心

如果你不想跟交易所的API死磕,第三方数据商是个好选择。

市面上主流的几家:

数据商 覆盖市场 数据精度 价格
彭博 全球股票、期货、外汇 Tick级 贵到离谱
路透 全球股票、期货、外汇 Tick级 也很贵
聚宽 A股、期货 分钟级 中等
CoinGecko 加密货币 分钟级 免费/付费

第三方数据商的好处是数据干净、格式统一。你想想看,交易所的字段命名五花八门,有的叫lastPrice,有的叫close,有的叫tradePrice。第三方帮你做了标准化。

但坏处也很明显——延迟。数据从交易所到数据商,再到你手里,中间至少多了一跳。做高频交易的话,这几十毫秒的延迟可能让你亏掉裤子。

我的建议: 如果你做的是中低频策略,第三方数据商完全够用。但如果是高频,老老实实直连交易所。

2.3 WebSocket:实时推送的王者

WebSocket是目前实时数据推送的主流方案。为什么?因为它解决了HTTP轮询的低效问题。

HTTP轮询是客户端每隔几秒问一次「有新数据吗?」,WebSocket是服务端主动说「有新数据了,给你」。

一个典型的WebSocket连接代码:

import websocket

def on_message(ws, message):
    # 收到Tick数据
    tick = parse_tick(message)
    save_to_buffer(tick)

def on_error(ws, error):
    # 断线重连
    reconnect()

ws = websocket.WebSocketApp(
    "wss://stream.binance.com:9443/ws/btcusdt@trade",
    on_message=on_message,
    on_error=on_error
)
ws.run_forever()

这段代码看起来简单,但实际生产环境里,坑多着呢。

我曾经遇到过一个问题:WebSocket连接在凌晨3点准时断开,查了三天才发现是云服务商的NAT超时设置。嗯,这种问题你光看代码是看不出来的。

2.4 数据源接入的核心架构

说了这么多,咱们画张图把整体逻辑串起来。

数据源接入核心架构 交易所API 第三方数据商 WebSocket流 数据接入层(限流、重试、校验、标准化) 内存缓冲队列(RingBuffer / Disruptor) 持久化层(InfluxDB / Parquet / ClickHouse)

这张图里,数据从左边三个源头进来,经过接入层处理,进入内存缓冲,最后落地到持久化存储。每个环节都有讲究。

2.5 接入层的三个关键点

接入层是数据源和存储之间的桥梁。我总结三个关键点:

  1. 协议适配:不同数据源协议不同,REST、WebSocket、FIX协议...你得写适配器把它们统一成内部格式。
  2. 断线重连:WebSocket断线是家常便饭。我建议用指数退避策略,第一次等1秒,第二次等2秒,第三次等4秒...最大间隔别超过5分钟。
  3. 数据去重:同一个Tick可能从多个数据源收到,或者因为重连重复推送。你得用时间戳+交易ID做唯一键去重。

核心原则: 接入层要做到「不丢数据、不重复数据、不乱序数据」。这三点做到,后面的存储和计算就轻松了。

2.6 实战中的避坑指南

最后,分享几个我踩过的坑:

  • 时间戳问题:交易所返回的时间戳是UTC还是本地时间?我见过有人直接用本地时间存,结果回测时数据对不上。统一用UTC+0存储。
  • 数据缺失:交易所偶尔会丢Tick。我建议用心跳包检测,如果超过5秒没收到数据,主动发一个ping。
  • 内存泄漏:WebSocket的on_message回调里如果处理太慢,消息会堆积在内存里。用异步处理或者背压机制解决。

我曾经在接入火币的WebSocket时,发现连接会在每天下午4点准时断开。查了日志才发现是火币的服务器端主动断开,原因是我的订阅频道数超过了限制。嗯,这种问题不看文档是永远猜不到的。

好了,数据源接入这块就聊到这。记住一句话:数据源是量化系统的命门,接入层是数据源的第一道防线。把这道防线守住了,后面的工作才能顺利展开。


专注资料整理