2. Tick数据基础
在量化交易与行情系统中,Tick数据是最细粒度的市场记录,通常指交易所逐笔推送的成交或委托变动事件。它不同于K线,K线是聚合结果,而Tick是原始事实。理解Tick数据的字段结构、时间戳精度以及逐笔成交与委托快照的区别,是后续分区、索引与冷热分层设计的前提。
一、Tick数据的定义与核心字段
Tick数据描述的是某一时刻市场上发生的一次事件。常见字段包括:标的代码、交易所、事件时间、价格、数量、方向、买卖盘口等。不同数据源字段命名不同,但语义基本一致。以下是一个典型的逐笔成交Tick结构:
{
"symbol": "600519.SH",
"exchange": "SSE",
"event_time": "2024-06-03 09:30:00.123456",
"price": 1680.50,
"volume": 200,
"amount": 336100.00,
"side": "BUY",
"trade_id": "T20240603093000123",
"seq_no": 10023871
}
其中 event_time 是事件发生时间,seq_no 是交易所序列号,用于去重与排序。字段设计直接影响存储成本与查询效率,例如价格用定点数还是浮点、时间戳用字符串还是整数,都会影响后续分区与索引策略。
二、时间戳精度:从秒到纳秒
时间戳精度是Tick数据的关键属性。国内A股逐笔成交通常为毫秒级,部分期货交易所提供微秒级,而海外市场如纳斯达克ITCH可达纳秒级。精度越高,数据量越大,对分区粒度要求越细。
| 精度级别 | 典型场景 | 存储影响 | 分区建议 |
|---|---|---|---|
| 秒级 | 部分指数快照 | 低 | 按天分区 |
| 毫秒级 | A股逐笔成交 | 中 | 按天+小时 |
| 微秒级 | 期货、期权 | 高 | 按小时+分钟 |
| 纳秒级 | ITCH | 极高 | 按分钟或更细 |
三、逐笔成交与委托快照的区别
逐笔成交(Trade Tick)记录的是已经发生的成交事件,包含成交价、成交量、买卖方向。委托快照(Order Book Snapshot)记录的是某一时刻的盘口状态,通常包含买一至买十、卖一至卖十的价格与挂单量。两者在数据流中角色不同:成交是“结果”,快照是“状态”。
- 逐笔成交:事件驱动,增量更新,用于计算成交量、VWAP、资金流向。
- 委托快照:状态驱动,全量或增量推送,用于重建订单簿、计算买卖压力。
- 时间对齐:成交与快照时间戳可能不完全一致,需按交易所序列号对齐。
四、常见数据源与格式
不同数据源提供的Tick格式差异较大。国内常见的有上交所Level-2、深交所Level-2、中金所Level-2;海外有纳斯达克ITCH、纽交所TAQ、CME MDP等。格式上,二进制协议(如ITCH)解析效率高但可读性差,文本格式(如CSV、JSON)易调试但体积大。
# 常见数据源格式对比
SSE Level-2: 二进制 + 逐笔成交/委托
SZSE Level-2: 二进制 + 逐笔成交/委托
CME MDP: 二进制 + 增量快照
NASDAQ ITCH: 二进制 + 逐笔成交/委托
CSV/JSON: 文本 + 易读但体积大
实际工程中,通常先将原始二进制解析为结构化记录,再写入列式存储(如Parquet)或时序数据库。解析阶段需注意字节序、字段偏移、消息类型区分。
五、案例:从原始Tick到可查询数据
假设我们接收上交所逐笔成交二进制流,每条消息包含消息类型、序列号、时间戳、价格、数量、方向。解析后写入Parquet,按trade_date和hour分区。查询某只股票某分钟成交量时,只需扫描对应分区,避免全表扫描。
# 伪代码:解析并写入分区
for msg in stream:
tick = parse_sse_trade(msg)
partition = f"date={tick.date}/hour={tick.hour}"
writer.write(tick, partition)
该流程中,时间戳精度决定了分区粒度,字段结构决定了索引选择。若时间戳为微秒级,按小时分区可能仍过大,需进一步按分钟分区。
六、误区与复盘
- 误区一:忽略交易所序列号,导致乱序数据无法正确排序。
- 误区二:时间戳用字符串存储,查询时解析开销大,且无法做范围裁剪。
- 误区三:将快照与成交混存同一表,字段语义冲突,索引失效。
- 复盘建议:先明确数据语义,再设计Schema;时间戳统一为整数;分区字段选择高基数且查询频繁的维度。