2. Level2 行情数据获取:主流数据源对比与接入实践

Level2 行情数据的获取是整个策略评估与推演体系的基石。数据源的稳定性、实时性、字段完整度以及接入成本,直接决定了后续策略回测与沙盘推演的可靠性。本章将从数据源对比、API 认证鉴权、实时流与历史数据拉取三个维度,系统梳理主流接入方案。

2.1 主流数据源对比:券商 vs 第三方数据商

目前国内 Level2 行情数据的主要提供方分为两类:券商自研数据服务(如华泰、中信、国泰君安)与第三方数据商(如万得 Wind、聚宽、Tushare、掘金量化)。两者在数据质量、延迟、费用与开发友好度上存在显著差异。

对比维度 券商自研数据服务 第三方数据商
数据源权威性 直接来自交易所授权,原始报文级 多数为二次加工或转售,存在字段裁剪
实时性(延迟) 通常 < 50ms(极速交易通道可达 10ms) 100ms ~ 500ms,受中间链路影响
字段完整度 全量逐笔委托、逐笔成交、十档行情 部分仅提供快照级数据,缺少逐笔还原
历史数据深度 通常仅保留近 1~3 个月 可提供 3~5 年甚至全量历史
接入门槛 需开通券商交易账户,部分要求资产门槛 注册即用,部分提供免费额度
费用模式 按年收取行情费(约 3000~8000 元/年) 按调用量或订阅套餐(免费~数万元/年)
开发文档质量 偏内部接口,文档晦涩,示例少 文档完善,SDK 丰富,社区活跃
选型建议: 高频策略(Tick 级、逐笔还原)优先选择券商直连;中低频策略或研究型场景,第三方数据商在历史数据深度与开发效率上更具优势。

2.2 API 接口认证与鉴权机制

无论选择哪种数据源,接入 Level2 行情 API 都必须通过认证与鉴权。主流方案分为 Token 令牌 与 双向 SSL 证书 两类。

2.2.1 Token 令牌模式(第三方数据商为主)

  • 获取方式: 注册后从控制台生成固定 Token,或通过 OAuth2.0 动态获取。
  • 传递方式: 通常放在 HTTP Header 的 Authorization: Bearer <token> 中。
  • 有效期: 固定 Token 长期有效;动态 Token 通常 24h 过期,需定时刷新。
  • 安全建议: Token 不要硬编码在代码中,建议通过环境变量或密钥管理服务注入。
# Python 示例:使用 Token 请求 Level2 快照数据
import requests

TOKEN = "your_level2_token_here"
headers = {"Authorization": f"Bearer {TOKEN}"}
url = "https://api.datasource.com/v2/level2/snapshot?symbol=000001.SZ"

response = requests.get(url, headers=headers)
if response.status_code == 200:
    data = response.json()
    print("最新卖一价:", data["ask_price"][0])
else:
    print("鉴权失败:", response.status_code, response.text)

2.2.2 双向 SSL 证书模式(券商直连为主)

  • 原理: 客户端与服务端各持一份数字证书,建立 TLS 双向认证通道。
  • 文件组成: 客户端证书(.p12 或 .pem)、私钥密码、CA 根证书。
  • 适用场景: 极速交易柜台、券商内部量化平台,安全性最高。
  • 注意事项: 证书到期前需手动续期,否则行情流会中断。
# Python 示例:使用双向 SSL 连接券商 WebSocket 行情
import ssl
import websocket

ssl_context = ssl.create_default_context()
ssl_context.load_cert_chain(
    certfile="client_cert.pem",
    keyfile="client_key.pem",
    password="your_key_password"
)
ssl_context.load_verify_locations("ca_cert.pem")

ws = websocket.WebSocket(sslopt={"context": ssl_context})
ws.connect("wss://quote.broker.com/level2")
ws.send('{"action":"subscribe","symbols":["000001.SZ"]}')
print("WebSocket 双向认证连接成功")
避坑提示: 部分券商要求同时提供交易密码或动态口令(OTP)作为二次鉴权。务必在代码中处理鉴权失败的重试与告警逻辑,避免因 Token 过期导致策略空跑。

2.3 WebSocket 实时流与 RESTful 历史数据拉取

Level2 行情数据接入通常采用 双通道架构:WebSocket 负责实时流推送,RESTful API 负责历史数据补全与快照查询。两者在延迟、数据量与使用场景上互补。

2.3.1 WebSocket 实时流:订阅与推送

  • 协议: 基于 WebSocket 全双工通信,支持二进制(Protocol Buffers)或 JSON 文本帧。
  • 订阅模式: 客户端发送订阅请求(如 {"op":"subscribe","args":["tick.000001.SZ"]}),服务端持续推送增量数据。
  • 心跳维持: 每 15~30 秒发送 Ping 帧,服务端回复 Pong,防止连接断开。
  • 重连机制: 必须实现指数退避重连,避免断线后数据丢失。
# Python 示例:WebSocket 实时订阅 Level2 逐笔成交
import websocket
import json

def on_message(ws, message):
    data = json.loads(message)
    if data["type"] == "tick":
        print(f"时间:{data['time']} 价格:{data['price']} 量:{data['volume']}")

def on_error(ws, error):
    print("WebSocket 错误:", error)

def on_close(ws, close_status_code, close_msg):
    print("连接关闭,准备重连...")

def on_open(ws):
    subscribe_msg = {
        "op": "subscribe",
        "args": ["tick.000001.SZ", "tick.600519.SH"]
    }
    ws.send(json.dumps(subscribe_msg))
    print("订阅请求已发送")

ws = websocket.WebSocketApp(
    "wss://quote.datasource.com/level2/ws",
    on_open=on_open,
    on_message=on_message,
    on_error=on_error,
    on_close=on_close
)
ws.run_forever(ping_interval=20, ping_timeout=10)

2.3.2 RESTful 历史数据拉取:补全与回测

  • 接口类型: 历史 Tick 数据、历史快照(1 分钟/5 分钟)、逐笔还原数据。
  • 请求参数: 股票代码、起始时间、结束时间、数据粒度(tick / 1min / 5min)。
  • 限流策略: 多数数据商限制每秒请求次数(如 5 次/秒),超出返回 429 状态码。
  • 分页拉取: 单次返回数据量有限(如 1000 条),需通过 page_token 或 offset 循环拉取。
# Python 示例:RESTful 拉取历史 Tick 数据(带分页)
import requests
import time

TOKEN = "your_token"
BASE_URL = "https://api.datasource.com/v2/level2/history"
headers = {"Authorization": f"Bearer {TOKEN}"}

def fetch_ticks(symbol, start, end, page_size=1000):
    all_ticks = []
    page_token = None
    while True:
        params = {
            "symbol": symbol,
            "start": start,
            "end": end,
            "page_size": page_size,
            "page_token": page_token
        }
        resp = requests.get(BASE_URL, headers=headers, params=params)
        if resp.status_code == 429:
            time.sleep(1)  # 限流等待
            continue
        data = resp.json()
        all_ticks.extend(data["ticks"])
        if not data.get("next_page_token"):
            break
        page_token = data["next_page_token"]
        time.sleep(0.2)  # 控制请求频率
    return all_ticks

# 拉取 2025-01-10 当天全部 Tick
ticks = fetch_ticks("000001.SZ", "2025-01-10 09:30:00", "2025-01-10 15:00:00")
print(f"共获取 {len(ticks)} 条 Tick 数据")

2.3.3 双通道架构对比

特性 WebSocket 实时流 RESTful 历史数据
数据延迟 毫秒级推送 秒级~分钟级(取决于查询时间范围)
数据量 仅推送增量,带宽占用低 单次可拉取数千条,适合批量处理
使用场景 实时监控、策略信号触发、沙盘推演 回测初始化、数据补全、盘后分析
连接状态 长连接,需心跳与重连 短连接,无状态
错误处理 断线重连 + 数据序列号校验 HTTP 状态码 + 重试机制
最佳实践: 策略运行期间,WebSocket 负责接收实时行情驱动决策引擎;每日收盘后,通过 RESTful 接口拉取当日完整 Tick 数据,用于沙盘推演复盘与模型校准。两者结合可构建完整的数据闭环。
Level2 行情双通道接入架构 Level2 行情数据源 认证与鉴权层(Token / SSL) 数据分发 WebSocket 实时流 • 全双工长连接 • 增量推送(Tick / 快照) • 心跳维持 + 自动重连 RESTful 历史数据 • 短连接请求/响应 • 批量拉取 Tick / 快照 • 分页 + 限流控制 实时策略引擎 / 沙盘推演 回测系统 / 盘后分析 说明: WebSocket 实时流驱动盘中策略执行与沙盘推演;RESTful 历史数据用于回测初始化与盘后数据补全。两者通过统一的数据模型层解耦。

2.4 数据质量校验与异常处理

无论数据源多么可靠,网络抖动、交易所异常或数据商处理故障都可能导致数据质量问题。建议在接入层内置以下校验逻辑:

  • 序列号连续性: 逐笔成交数据通常携带递增序列号,检测跳号即表示丢包。
  • 时间戳单调性: 后一条数据的时间戳必须 ≥ 前一条,否则视为乱序。
  • 价格/量合理性: 价格在 [0.01, 10000] 区间,单笔成交量不超过流通盘的 1%。
  • 断线重连补偿: 重连后通过 RESTful 接口拉取缺失时间窗口的数据进行回补。
工程要点: 建议将数据校验结果写入独立日志文件,并设置告警阈值(如连续 10 次序列号跳号触发邮件/钉钉通知)。在沙盘推演中,数据质量日志也是复盘的重要依据。