2. 行情数据基础
在动手实现断点续传与数据补录之前,必须先厘清“采什么、从哪采、按什么格式采”这三个问题。行情数据的类型、粒度、时间语义、来源与协议,直接决定了断点判定、去重策略和补录窗口的设计方式。本节将围绕这些基础概念展开,为后续实战打下统一的数据认知。
一、行情数据的类型与粒度:Tick与K线
行情数据按粒度可分为两大类:Tick级快照/逐笔数据与K线(蜡烛)数据。Tick数据是市场最细粒度的记录,通常包含最新价、成交量、买卖盘口、成交方向等字段;K线则是对Tick按固定时间窗口聚合后的结果,包含开、高、低、收、成交量等。
- Tick快照(Snapshot):按固定频率(如每500ms)推送市场当前状态,字段稳定,适合做实时监控与盘口分析。
- 逐笔成交(Trade):每笔成交触发一条记录,含成交价、成交量、成交方向,数据量大,适合做微观结构研究。
- 逐笔委托(Order):记录每一笔委托的挂单与撤单,是还原订单簿的基础。
- K线(Bar):按1分钟、5分钟、日线等周期聚合,字段少、体积小,适合策略回测与长期存储。
采集系统通常同时订阅Tick与K线:Tick用于实时计算与补录校验,K线用于快速回补与策略消费。理解两者的生成关系,是判断“数据是否完整”的前提。
二、时间戳:行情数据的“身份证”
时间戳是断点续传中最关键的字段。行情数据通常涉及三类时间:
| 时间类型 | 含义 | 典型用途 |
|---|---|---|
| 交易所时间 | 交易所撮合系统生成的时间 | 判断交易时段、对齐K线 |
| 采集时间 | 本地程序收到数据的时刻 | 监控延迟、排查丢包 |
| 入库时间 | 数据写入存储的时刻 | 审计、补录去重 |
断点续传应以交易所时间为主键进行偏移量记录,因为采集时间和入库时间会因网络抖动、程序重启而漂移。若用采集时间做断点,重启后极易漏采或重复。实践中建议在存储层同时保留三类时间,但断点游标只认交易所时间。
三、交易所与数据源:从哪里采
行情数据源可分为三类:
- 交易所直连:如上期所、大商所、郑商所、中金所等提供的官方行情网关,数据权威、延迟低,但接入成本高,需专线或授权。
- 第三方数据商:如Wind、同花顺、聚宽、Tushare等,接口友好、覆盖广,但存在延迟和字段差异,适合研究与小规模采集。
- 券商/期货公司柜台:通过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)建唯一索引,重复数据直接忽略。这一案例说明:时间戳的选择不是细节,而是断点续传正确性的基石。
六、常见误区与复盘清单
- 误区一:用采集时间做断点。重启后时间漂移,导致漏采或重复。应统一使用交易所时间。
- 误区二:忽略K线与Tick的生成关系。补录K线时未校验Tick完整性,导致K线数据与Tick对不上。
- 误区三:断点与数据写入非原子。崩溃后断点前移,数据丢失。应先写数据、后写断点。
- 误区四:不同源时间精度混用。秒级与毫秒级混存,去重失效。应统一精度并做归一化。
- 误区五:补录无窗口限制。一次性拉取全量历史,触发限流或超时。应按时间窗口分批补录。