2. 行情数据基础

在动手实现断点续传与数据补录之前,必须先厘清“采什么、从哪采、按什么格式采”这三个问题。行情数据的类型、粒度、时间语义、来源与协议,直接决定了断点判定、去重策略和补录窗口的设计方式。本节将围绕这些基础概念展开,为后续实战打下统一的数据认知。

一、行情数据的类型与粒度:Tick与K线

行情数据按粒度可分为两大类:Tick级快照/逐笔数据与K线(蜡烛)数据。Tick数据是市场最细粒度的记录,通常包含最新价、成交量、买卖盘口、成交方向等字段;K线则是对Tick按固定时间窗口聚合后的结果,包含开、高、低、收、成交量等。

  • Tick快照(Snapshot):按固定频率(如每500ms)推送市场当前状态,字段稳定,适合做实时监控与盘口分析。
  • 逐笔成交(Trade):每笔成交触发一条记录,含成交价、成交量、成交方向,数据量大,适合做微观结构研究。
  • 逐笔委托(Order):记录每一笔委托的挂单与撤单,是还原订单簿的基础。
  • K线(Bar):按1分钟、5分钟、日线等周期聚合,字段少、体积小,适合策略回测与长期存储。

采集系统通常同时订阅Tick与K线:Tick用于实时计算与补录校验,K线用于快速回补与策略消费。理解两者的生成关系,是判断“数据是否完整”的前提。

二、时间戳:行情数据的“身份证”

时间戳是断点续传中最关键的字段。行情数据通常涉及三类时间:

时间类型含义典型用途
交易所时间交易所撮合系统生成的时间判断交易时段、对齐K线
采集时间本地程序收到数据的时刻监控延迟、排查丢包
入库时间数据写入存储的时刻审计、补录去重

断点续传应以交易所时间为主键进行偏移量记录,因为采集时间和入库时间会因网络抖动、程序重启而漂移。若用采集时间做断点,重启后极易漏采或重复。实践中建议在存储层同时保留三类时间,但断点游标只认交易所时间。

提示:不同交易所时间精度不同,有的到秒,有的到毫秒甚至微秒。补录时需统一到同一精度,避免因截断导致重复或遗漏。

三、交易所与数据源:从哪里采

行情数据源可分为三类:

  1. 交易所直连:如上期所、大商所、郑商所、中金所等提供的官方行情网关,数据权威、延迟低,但接入成本高,需专线或授权。
  2. 第三方数据商:如Wind、同花顺、聚宽、Tushare等,接口友好、覆盖广,但存在延迟和字段差异,适合研究与小规模采集。
  3. 券商/期货公司柜台:通过CTP、恒生等柜台系统获取行情,是实盘交易系统最常见的来源。

不同数据源的字段命名、时间格式、推送频率差异很大。采集层应做标准化适配,将各源数据统一为内部Schema,再交给断点续传模块处理。否则补录逻辑会被源差异污染,难以维护。

四、常见采集协议与接口

行情采集协议主要分为推送式与拉取式两类:

  • TCP私有协议:如CTP的行情API,基于TCP长连接,推送频率高,需处理心跳与重连。
  • WebSocket:常见于数字货币交易所与部分股票接口,全双工、易穿透防火墙。
  • HTTP/REST:拉取式接口,适合历史K线补录,通常有频率限制。
  • FIX/FAST:机构级协议,字段紧凑、延迟低,但解析复杂。

下面是一个典型的CTP行情订阅与断点记录伪代码,展示采集循环中如何维护时间游标:

# 伪代码:采集循环中维护断点游标
last_ts = load_checkpoint("ctp_tick")  # 从存储加载上次断点

def on_tick(tick):
    global last_ts
    if tick.exchange_time <= last_ts:
        return  # 重复数据,跳过
    save_tick(tick)
    last_ts = tick.exchange_time
    save_checkpoint("ctp_tick", last_ts)  # 实时持久化断点

# 断线重连后,从last_ts开始补录
def on_reconnect():
    history = query_history(start=last_ts, end=now())
    for bar in history:
        if bar.exchange_time > last_ts:
            save_tick(bar)
            last_ts = bar.exchange_time
    save_checkpoint("ctp_tick", last_ts)
注意:断点持久化必须与数据写入在同一事务或至少保证“先写数据、后写断点”。若先写断点后写数据,程序崩溃会导致断点前移而数据丢失。

五、案例:一次因时间戳误用导致的补录重复

某团队用采集时间作为断点游标,程序重启后从采集时间恢复,结果同一批Tick被重复写入两次。复盘发现:交易所时间在重启前后有重叠,而采集时间因重启被重置。修正方案是改用交易所时间做主游标,并在入库时对(symbol, exchange_time)建唯一索引,重复数据直接忽略。这一案例说明:时间戳的选择不是细节,而是断点续传正确性的基石。

行情数据采集链路与断点游标关系 交易所直连 CTP / 官方网关 第三方数据商 HTTP / WebSocket 券商柜台 FIX / 私有协议 采集适配层:字段标准化 + 时间戳统一 Tick / K线 / 逐笔 → 内部统一Schema 断点续传模块 游标:交易所时间 | 去重:唯一索引 存储层:Tick / K线 / 断点记录 历史补录 HTTP拉取 / 按时间窗口 数据源 适配层 断点模块 补录

六、常见误区与复盘清单

  • 误区一:用采集时间做断点。重启后时间漂移,导致漏采或重复。应统一使用交易所时间。
  • 误区二:忽略K线与Tick的生成关系。补录K线时未校验Tick完整性,导致K线数据与Tick对不上。
  • 误区三:断点与数据写入非原子。崩溃后断点前移,数据丢失。应先写数据、后写断点。
  • 误区四:不同源时间精度混用。秒级与毫秒级混存,去重失效。应统一精度并做归一化。
  • 误区五:补录无窗口限制。一次性拉取全量历史,触发限流或超时。应按时间窗口分批补录。
核心结论:行情采集的断点续传,本质是“以交易所时间为游标、以标准化Schema为输入、以原子写入为保障”的工程问题。数据类型、时间戳、数据源与协议,是设计补录策略前必须锁定的四个基础变量。