10. 高频数据下的深度分析:Tick级数据、逐笔成交与订单簿快照、数据清洗
做量化交易的朋友都知道,低频数据看的是趋势,高频数据看的是博弈。而博弈最真实的战场,就在Tick级数据里。
我个人习惯把高频数据比作市场的「心电图」。你想想看,日线级别的K线,就像医生每天给你量一次血压,能看出你有没有高血压,但看不出你心脏早搏了几次。而Tick级数据,就是24小时动态心电监护仪,每一跳都记录得清清楚楚。
这一章,我们就来拆解高频数据的三个核心要素:Tick数据、逐笔成交、订单簿快照。以及——嗯,这里要注意——数据清洗这个环节,我敢说80%的量化团队在这上面踩过坑。
10.1 Tick级数据:市场最原始的呼吸
Tick数据是什么?说白了,就是交易所每一次行情变动的最小记录单元。它不像分钟线那样做了聚合,而是「有变就记,不变不记」。
一个标准的Tick数据行,通常包含这些字段:
| 字段名 | 含义 | 示例值 |
|---|---|---|
| Symbol | 合约代码 | rb2410 |
| Timestamp | 时间戳(精确到毫秒或微秒) | 2024-09-15 09:30:00.123 |
| LastPrice | 最新成交价 | 3725 |
| Volume | 当前累计成交量 | 128450 |
| Turnover | 当前累计成交额 | 478562300 |
| BidPrice1 ~ BidPrice5 | 买一到买五价格 | 3724, 3723, ... |
| AskPrice1 ~ AskPrice5 | 卖一到卖五价格 | 3726, 3727, ... |
我在项目中遇到过一个问题:某家数据商提供的Tick数据,时间戳只精确到秒。你想想看,一秒内可能发生几十笔成交,这数据基本没法用。后来我换了一家精度到微秒的供应商,才真正开始做高频分析。
10.2 逐笔成交:看清每一笔交易的「真面目」
逐笔成交和Tick数据有什么区别?很多人搞混了。我简单解释一下:
- Tick数据:是行情快照,告诉你「现在价格是多少,买卖盘口长什么样」
- 逐笔成交:是每一笔实际成交的记录,告诉你「谁买了谁卖了,成交了多少手」
逐笔成交的核心字段包括:
TradeID: 202409150000123
Timestamp: 09:30:01.456
Price: 3725
Volume: 10
Side: B (买方主动吃单)
BuyOrderID: 12345678
SellOrderID: 87654321
为什么要区分买方主动还是卖方主动?这涉及到「订单流」的概念。买方主动吃单,说明买方更着急,市场情绪偏多;卖方主动砸单,说明卖方更强势。这个信号,在Tick数据里是看不出来的。
我记得有一次做股指期货的微观结构分析,发现某个品种在开盘前3分钟,逐笔成交中买方主动的比例突然从55%飙升到82%。我当时就觉得不对劲,果然,5分钟后一个大单砸下来,价格瞬间跳水。这就是逐笔成交数据的价值——它能提前暴露大资金的意图。
10.3 订单簿快照:市场的「实时地图」
订单簿快照,就是交易所每隔一段时间(通常是10毫秒、100毫秒或500毫秒)发布的当前所有挂单情况。它告诉你:
- 买一到买十(或更深)的价格和挂单量
- 卖一到卖十的价格和挂单量
- 总买量、总卖量
订单簿快照的核心用途有两个:
- 计算市场深度:比如你想买100手,需要吃掉几个价位?成本是多少?
- 计算价格弹性:一个大单进来,价格会滑点多少?市场能「消化」多大的订单?
下面这张图,是我自己画的高频数据知识体系结构,帮你理清这三者的关系:
10.4 数据清洗:高频分析中最脏最累的活
做高频分析,80%的时间花在数据清洗上,这话一点都不夸张。我见过太多团队,策略逻辑写得漂漂亮亮,结果数据一进来全是坑。
高频数据常见的「脏数据」问题,我列几个典型的:
- 时间戳错乱:某笔成交的时间戳比前一笔还早,明显是数据源搞错了
- 价格异常:突然出现一个0元成交,或者价格比前一秒跳了10%
- 重复数据:同一笔成交被推送了两次
- 缺失数据:某个时间段的订单簿快照丢了
- 订单簿不一致:买一价高于卖一价,这明显是数据错位了
我分享一个我自己常用的数据清洗流程:
# 伪代码:高频数据清洗流水线
def clean_tick_data(df):
# 1. 时间戳排序与去重
df = df.sort_values('Timestamp')
df = df.drop_duplicates(subset=['Timestamp', 'LastPrice', 'Volume'])
# 2. 价格合理性检查
# 剔除价格 <= 0 的记录
df = df[df['LastPrice'] > 0]
# 3. 价格跳变检测(超过3个标准差视为异常)
price_changes = df['LastPrice'].pct_change()
abnormal = price_changes.abs() > 0.03 # 3%阈值
df.loc[abnormal, 'LastPrice'] = np.nan
df['LastPrice'] = df['LastPrice'].ffill() # 向前填充
# 4. 订单簿一致性检查
mask = df['BidPrice1'] < df['AskPrice1']
df = df[mask]
return df
你可能会问:为什么不用插值法填充异常价格?嗯,这里要注意——高频数据里,价格跳变可能是真实的「闪崩」或「拉升」,你把它插值平滑掉了,真实的市场信号就丢了。我建议的做法是:标记异常,但不修改,让策略自己去决定怎么处理。
10.5 实战中的几个坑
最后,我总结几个高频数据清洗中容易踩的坑:
好了,这一章的内容就到这里。高频数据是微观结构分析的基石,数据清洗是基石上的基石。下一章我们会深入讨论如何从这些清洗后的数据中,提取出真正有交易价值的市场深度指标。