2. 行情数据接口与获取:主流Level2数据源、API接口类型与数据订阅机制
在量化交易中,Level2(二级)行情数据是区别于传统Level1(五档)行情的深度市场数据。它提供逐笔成交、十档买卖盘口、委托队列、资金流向等核心信息,是高频策略与日内交易的基础。本章将系统梳理主流数据源、API接口类型以及数据订阅与推送机制,帮助你在策略推演中正确选择数据通道。
2.1 主流Level2数据源对比
目前国内Level2行情数据主要来自两大渠道:券商自研数据服务与第三方专业数据商。下表从数据质量、延迟、费用、适用场景四个维度进行对比。
| 数据源类型 | 代表机构 | 数据质量 | 典型延迟 | 费用模式 | 适用场景 |
|---|---|---|---|---|---|
| 券商自研 | 华泰、中信、国泰君安等 | 交易所直连,完整度高 | 50-200ms | 按年/按流量收费,通常与交易账户绑定 | 实盘交易、机构级策略 |
| 第三方数据商 | 万得(Wind)、聚宽(JoinQuant)、米筐(RiceQuant)、恒生聚源 | 经过清洗与校验,历史数据丰富 | 200-1000ms | 按API调用次数或月度订阅 | 回测研究、策略开发、量化平台 |
| 交易所官方 | 上交所、深交所授权服务商 | 最原始、无中间处理 | 10-50ms | 高额年费,需专线接入 | 极高频交易、做市商 |
选型建议:对于策略推演与回测,优先选择第三方数据商(如聚宽、米筐),它们提供标准化API和丰富的历史快照数据;若需实盘低延迟,则必须使用券商或交易所直连数据。
2.2 API接口类型:REST vs WebSocket
Level2行情数据的获取方式主要分为两种接口类型:REST(请求-响应)与WebSocket(全双工推送)。它们在数据获取模式、实时性、资源消耗上存在本质差异。
2.2.1 REST接口
- 工作模式:客户端主动发起HTTP请求,服务端返回当前快照数据。
- 适用场景:历史数据查询、定时快照拉取、非实时策略。
- 优点:实现简单,兼容性好,适合一次性批量获取。
- 缺点:无法实时推送,轮询延迟高,浪费带宽。
2.2.2 WebSocket接口
- 工作模式:客户端与服务端建立长连接,服务端主动推送增量数据。
- 适用场景:实时逐笔成交、十档盘口变化、委托队列更新。
- 优点:低延迟(毫秒级),数据实时性强,节省带宽。
- 缺点:实现复杂度高,需处理心跳、重连、数据校验。
| 对比维度 | REST | WebSocket |
|---|---|---|
| 连接方式 | 短连接,每次请求独立 | 长连接,保持持久通道 |
| 数据推送 | 客户端轮询拉取 | 服务端主动推送 |
| 典型延迟 | 500ms-2s(含轮询间隔) | 10-100ms |
| 资源消耗 | 高(频繁建立连接) | 低(连接复用) |
| 数据完整性 | 快照级,可能丢失中间变化 | 增量级,逐笔还原 |
核心原则:策略推演中,回测阶段使用REST获取历史快照;实盘模拟或实盘交易阶段,必须使用WebSocket接收实时推送,否则无法捕捉毫秒级行情变化。
2.3 数据订阅与推送机制
无论是券商还是第三方数据商,其Level2行情推送都遵循一套标准化的订阅-推送模型。理解这一机制,是正确编写数据接收代码的前提。
2.3.1 订阅流程
- 认证与鉴权:客户端使用API Key或Token向数据服务端发起连接请求。
- 订阅主题:指定需要接收的股票代码(如“600519.SH”)及数据类型(如“snapshot”、“tick”、“orderbook”)。
- 确认订阅:服务端返回订阅成功确认消息,包含订阅ID与心跳间隔。
- 数据推送:服务端按市场事件(如逐笔成交、盘口变动)实时推送数据帧。
- 取消订阅:客户端可随时发送取消指令,释放资源。
2.3.2 推送数据帧结构
一个典型的Level2快照推送数据帧(JSON格式)包含以下字段:
{
"type": "snapshot",
"symbol": "600519.SH",
"timestamp": 1699000000123,
"bid": [
{"price": 185.20, "volume": 1200},
{"price": 185.19, "volume": 800}
],
"ask": [
{"price": 185.21, "volume": 900},
{"price": 185.22, "volume": 1100}
],
"last_trade": {"price": 185.20, "volume": 200, "direction": "buy"},
"total_volume": 12345678,
"total_amount": 2280000000.00
}
注意:不同数据商的字段命名与精度可能不同(如“bid”可能写作“bids”或“buy_orders”),务必查阅对应API文档进行字段映射。同时,时间戳通常为毫秒级Unix时间戳,需转换为本地时间用于策略逻辑。
2.4 数据订阅与推送架构图
下图展示了从客户端到数据源之间的完整订阅与推送架构,包含认证、订阅、推送、心跳与重连机制。
2.5 代码示例:使用WebSocket订阅Level2快照
以下是一个基于Python的WebSocket客户端示例,演示如何连接第三方数据商(以聚宽为例)并订阅Level2快照数据。实际使用时需替换为真实API地址与Token。
import websocket
import json
import threading
# 配置参数
WS_URL = "wss://api.joinquant.com/level2"
API_KEY = "your_api_key_here"
SYMBOLS = ["600519.SH", "000001.SZ"]
def on_message(ws, message):
"""收到推送数据时的回调函数"""
data = json.loads(message)
# 处理快照数据,例如更新本地订单簿
print(f"收到快照: {data['symbol']} 时间戳: {data['timestamp']}")
def on_error(ws, error):
"""连接出错时的回调"""
print(f"WebSocket错误: {error}")
def on_close(ws, close_status_code, close_msg):
"""连接关闭时的回调"""
print("WebSocket连接已关闭")
def on_open(ws):
"""连接建立后的回调:发送订阅请求"""
subscribe_msg = {
"action": "subscribe",
"type": "snapshot",
"symbols": SYMBOLS,
"api_key": API_KEY
}
ws.send(json.dumps(subscribe_msg))
print(f"已订阅: {SYMBOLS}")
# 启动WebSocket连接
ws = websocket.WebSocketApp(
WS_URL,
on_open=on_open,
on_message=on_message,
on_error=on_error,
on_close=on_close
)
# 在独立线程中运行,避免阻塞主线程
wst = threading.Thread(target=ws.run_forever, kwargs={"ping_interval": 30})
wst.daemon = True
wst.start()
# 主线程可继续执行其他任务
print("WebSocket客户端已启动,等待数据推送...")
关键点:WebSocket客户端必须实现心跳机制(ping_interval),防止连接因长时间无数据而被服务端断开。同时,建议在on_error和on_close中实现自动重连逻辑,确保行情数据不中断。
2.6 数据源选择与接口类型决策树
在实际项目中,你可以根据以下决策树快速确定数据源与接口类型:
2.7 常见问题与避坑指南
- 数据延迟不一致:不同数据源的时间戳精度可能不同(毫秒 vs 微秒),策略中需统一时间基准,避免因时间错位导致信号误判。
- WebSocket断线重连:务必实现指数退避重连策略(如首次重连1秒,后续加倍至30秒),防止频繁重连被服务端封禁。
- 订阅数量限制:多数数据商对单连接订阅的股票数量有限制(如500只),超限时需拆分多个连接或使用通配符订阅。
- 数据校验:接收到的快照数据应进行完整性校验(如检查买卖盘档位数量、价格合理性),避免脏数据进入策略逻辑。
最佳实践:在策略推演阶段,建议先使用第三方数据商的REST接口获取历史快照数据,验证策略逻辑;待策略稳定后,再切换至券商WebSocket接口进行实盘模拟,逐步降低延迟敏感度。