2. 金融市场数据基础

在构建任何实时行情系统之前,必须先回答一个看似简单却极易被低估的问题:一条Tick到底是什么?很多开发者把Tick理解为“价格变动”,但在真实交易所数据链路中,Tick是带有明确语义、字段约束和时间归属的最小成交或盘口事件。理解它的定义与结构,是后续聚合、去重、对齐和K线生成正确性的根基。

一、Tick数据的定义与本质

Tick通常指交易所行情网关推送的一次市场状态变更事件,最常见的是逐笔成交(Trade)与逐笔委托(Order)以及盘口快照(Quote/Depth)。它不是一个“价格点”,而是一条带有事件类型、标的、时间、价格、数量、方向等属性的结构化记录。不同市场对Tick的定义差异很大:

  • 股票逐笔成交:一次撮合成交,包含成交价、成交量、买卖方向、成交编号。
  • 期货Level-1行情:常以固定频率快照推送,包含最新价、买卖一档、成交量、持仓量。
  • 期货Level-2行情:包含多档盘口与逐笔委托,数据量可达每秒数万条。
  • 加密货币Tick:通常为逐笔成交或增量深度更新,时间精度可达微秒甚至纳秒。

因此,在系统设计中不能笼统地说“处理Tick”,而要先明确数据源类型、事件语义和字段契约,否则聚合逻辑会出现方向错误、重复计数或时间错位。

二、Tick字段结构与时间戳类型

一条典型Tick的字段可分为四类:标识类、时间类、数值类、方向类。以下是一个通用化的字段结构示例:

{
  "symbol": "IF2406",
  "exchange": "CFFEX",
  "event_type": "trade",
  "exchange_ts": 1718000000123456789,
  "local_ts": 1718000000124000000,
  "price": 3850.2,
  "volume": 3,
  "turnover": 1155060.0,
  "direction": "buy",
  "seq": 88231007
}

其中时间戳是实战中最容易出问题的部分,常见有三类:

时间戳类型含义典型精度使用场景
交易所时间交易所撮合或发布时刻毫秒/微秒/纳秒K线归属、跨市场对齐
本地接收时间本机网卡或进程收到时刻微秒/纳秒延迟监控、乱序检测
业务时间交易日或结算日归属日期夜盘归属、日切处理
常见误区:直接用本地接收时间生成K线。网络抖动或批量补发会导致同一秒内Tick顺序错乱,K线的开高低收全部失真。正确做法是以交易所时间为准,本地时间仅用于监控与补偿。

三、交易所数据源与常见数据格式

不同交易所的数据接入方式差异显著,常见可分为三类:

  1. 二进制私有协议:如CTP、飞马、恒生UFT,字段紧凑、延迟低,但需要按结构体解析,字节序和对齐必须严格匹配。
  2. FIX/FAST协议:国际交易所常用,字段自描述,扩展性好,但解析开销较大。
  3. WebSocket/HTTP JSON:加密货币交易所主流,开发快,但延迟和吞吐不如二进制。

以CTP行情为例,解析后的Tick结构通常包含InstrumentID、LastPrice、Volume、BidPrice1、AskPrice1、UpdateTime、UpdateMillisec等字段。注意CTP的UpdateTime只有时分秒,毫秒在独立字段中,拼接时必须补零对齐,否则会出现时间跳变。

# 伪代码:拼接CTP时间戳
ts_str = f"{UpdateTime}.{UpdateMillisec:03d}"
exchange_ts = parse_datetime(ActionDay, ts_str)
实战建议:接入新数据源时,先做三件事——打印原始报文、核对字段单位(价格是元还是最小变动价位)、确认时间字段是否含日期。这三步能避免80%的后续聚合错误。

四、案例场景:从原始Tick到可聚合事件

假设我们接入某期货交易所的Level-1快照,原始数据每秒推送2次。若直接按“每条记录生成一根K线”,会得到大量重复且无意义的K线。正确流程是:先按symbol + exchange_ts去重,再按事件类型过滤,只保留成交类Tick进入聚合管道,盘口快照单独存入行情快照表。

下图展示了从多源Tick到统一事件模型的转换关系,重点体现字段映射与时间归属的判断路径:

多源Tick到统一事件模型 CTP二进制 UpdateTime+Millisec LastPrice/Volume WebSocket JSON ts(微秒) price/size/side FIX/FAST SendingTime MDEntryPx/Size 统一Tick事件模型 symbol | exchange_ts | price | volume | direction | seq 去重 → 排序 → 聚合 按exchange_ts对齐,进入K线生成

在这个模型中,seq字段用于检测丢包与乱序,direction用于判断主动买卖方向,exchange_ts用于K线归属。缺少任一字段,聚合结果都可能出现偏差。

五、误区复盘与检查清单

在实际项目中,Tick处理最常见的错误集中在时间与语义两个维度。以下清单可用于接入新数据源时的自检:

  • 是否确认了时间戳精度与单位(秒/毫秒/微秒/纳秒)?
  • 是否区分了交易所时间与本地接收时间?
  • 是否处理了夜盘与日盘的交易日归属?
  • 是否对重复推送做了去重?
  • 是否确认了价格单位与最小变动价位?
  • 是否保留了原始报文用于回放与对账?
核心结论:Tick不是简单的价格点,而是带有时间归属、事件语义和方向属性的结构化事件。只有先统一字段契约与时间基准,后续的聚合与K线生成才具备可验证的正确性。数据基础不牢,再精巧的聚合算法也只是在错误的地基上盖楼。