第二章 逐笔成交与Tick数据:数据结构的底层逻辑
做量化交易这些年,我越来越觉得——数据是交易的血液。而逐笔成交和Tick数据,就是最原始的血液样本。
很多人喜欢看K线,觉得那才是交易。但说实话,K线是加工过的信息。它把几万笔交易压缩成了四个价格。你想想看,中间丢失了多少细节?
我个人习惯,每天开盘前先看15分钟的逐笔成交。不是为了找交易机会,而是为了感受市场的「呼吸节奏」。这比任何指标都真实。
2.1 逐笔成交数据的结构
逐笔成交数据,说白了就是每一笔真实成交的记录。交易所撮合一次,就产生一条数据。
它的核心字段其实不多,但每个字段都藏着信息量:
| 字段名 | 含义 | 我的理解 |
|---|---|---|
| 时间戳 | 精确到毫秒或微秒 | 这是最容易被忽视的维度。毫秒级的差异,往往意味着不同的交易意图 |
| 成交价 | 该笔交易的撮合价格 | 注意:不是报价,是真实成交价 |
| 成交量 | 该笔交易的股数/手数 | 大单还是小单?这里能看出资金性质 |
| 成交额 | 成交价 × 成交量 | 有些交易所直接给,有些需要自己算 |
| 买卖方向 | 主动买还是主动卖 | 这是订单流分析的核心中的核心 |
| 成交编号 | 交易所生成的唯一ID | 用来去重和排序,比时间戳更可靠 |
核心认知:逐笔成交数据是「结果」,不是「过程」。它告诉你发生了什么,但不直接告诉你为什么会发生。后者需要结合订单簿数据来分析。
我在项目中遇到过一个问题:某只股票突然放量拉升,逐笔成交显示全是主动买。但后来复盘发现,那些「主动买」其实是量化资金在对倒。怎么发现的?看成交编号的连续性——正常交易会有间隔,对倒的成交编号是连续的。
2.2 Tick数据的采集与清洗
Tick数据,很多人把它和逐笔成交混为一谈。其实不一样。
Tick数据是快照,它记录的是某个时间点上,市场状态的完整切片。包括最新价、买卖盘口、成交量、持仓量等。而逐笔成交是事件流,每成交一笔就产生一条。
嗯,这里要注意:不同交易所对Tick的定义不同。有的交易所1秒拍一张快照,有的500毫秒。你如果做高频策略,这个差异会直接影响你的回测精度。
2.2.1 数据采集的坑
我曾经自己搭过一套数据采集系统,踩过的坑可以写本书了。这里挑几个重点说:
- 时间同步问题:交易所的时钟和你的服务器时钟可能有偏差。我建议用NTP协议同步,偏差控制在1毫秒以内。
- 数据丢失:网络抖动会导致丢包。我习惯在采集端做本地缓存,每5秒批量上传一次。即使网络断了,数据也不会丢。
- 重复数据:有些数据源会推送重复的Tick。一定要用成交编号或时间戳+价格+成交量的组合做去重。
避坑指南:我曾经因为没处理好时间同步,导致回测结果和实盘差了0.3秒。0.3秒在Tick级别交易里,就是天堂和地狱的区别。从那以后,我每套系统都会加一个时间校准模块。
2.2.2 数据清洗流程
数据清洗这件事,80%的时间花在20%的脏数据上。我的清洗流程是这样的:
- 格式校验:检查字段类型、长度、范围。比如价格不能为负,成交量不能为0。
- 时间排序:按时间戳升序排列。注意处理同一毫秒内的多条数据。
- 去重处理:基于成交编号或关键字段组合去重。
- 异常值过滤:价格超过当日涨跌停板、成交量超过正常范围等,标记出来人工复核。
- 缺失值填充:对于Tick数据,如果某秒没有快照,我一般用前向填充(forward fill)。
给你看一段我常用的清洗代码片段:
def clean_tick_data(df):
"""
清洗Tick数据
"""
# 1. 格式校验
df = df[(df['price'] > 0) & (df['volume'] >= 0)]
# 2. 时间排序
df = df.sort_values('timestamp')
# 3. 去重
df = df.drop_duplicates(subset=['trade_id'])
# 4. 异常值过滤
df = df[df['price'] <= df['upper_limit']]
df = df[df['price'] >= df['lower_limit']]
# 5. 缺失值填充(前向填充)
df = df.fillna(method='ffill')
return df
小技巧:清洗后的数据,我习惯再跑一遍「完整性检查」。比如检查一天的数据条数是否在合理范围内。如果某天数据量突然少了30%,大概率是采集端出了问题。
2.3 逐笔成交与Tick的关系
这两者的关系,我用一张图来说明:
你看这张图就明白了。逐笔成交是流水账,Tick数据是快照。两者结合使用,才能还原市场的全貌。
我个人习惯的做法是:用Tick数据做策略回测,用逐笔成交做实时交易信号。为什么?因为Tick数据量小,回测快;逐笔成交细节多,适合捕捉瞬时机会。
2.4 实战中的注意事项
最后说几个实战中容易忽略的点:
- 数据源的选择:不同数据商的逐笔成交数据,在时间精度和字段完整性上差异很大。我建议至少对比两家数据源,交叉验证。
- 存储策略:逐笔成交数据量巨大。一只活跃股票一天可能产生几十万条。我习惯用列式存储(如Parquet),压缩比高,查询快。
- 实时处理 vs 离线处理:实时处理用流式计算框架(如Flink),离线分析用批处理(如Spark)。不要混用。
一句话总结:逐笔成交是显微镜,Tick数据是望远镜。做订单流分析,两者缺一不可。
好了,这一章的内容就到这里。数据结构的底层逻辑搞清楚了,后面讲买卖压力计算的时候,你才能理解每个数字背后的含义。