3. 数据获取与清洗:Level2行情数据、Tick级数据获取、数据清洗与对齐
做报价驱动市场的价差预测,说白了就是跟数据打交道。我个人习惯把数据获取比作「做饭前的买菜」——菜买得不好,厨艺再高也白搭。这一章咱们就聊聊怎么把「菜」买对、洗干净。
3.1 Level2行情数据:到底比Level1多了什么?
很多新手问我:「Level2和Level1有啥区别?」我通常会反问一句:「你想看冰山全貌,还是只看露出水面的那一角?」
Level1行情只给你五档买卖盘口、最新价、成交量这些基础信息。而Level2数据,说白了就是「深度透视」——它把整个订单簿的细节都摆在你面前。
| 对比项 | Level1 | Level2 |
|---|---|---|
| 买卖盘口 | 5档 | 10档(甚至更多) |
| 逐笔成交 | 无 | 有(每笔交易的详细记录) |
| 委托队列 | 无 | 有(前50笔挂单明细) |
| 更新频率 | 3秒快照 | 实时推送(毫秒级) |
我在项目中遇到过最典型的场景:用Level1数据做价差预测,模型准确率死活上不去。后来换成Level2的逐笔成交数据,准确率直接提升了15%。为什么?因为Level2能看到「大单拆单」的痕迹,这是价差变化的前兆。
3.2 Tick级数据获取:别被「实时」两个字骗了
Tick级数据,就是每一笔行情变动的记录。听起来简单,但实际获取时坑不少。
我个人建议用WebSocket连接交易所的行情推送接口。以国内某主流交易所为例,伪代码大概是这样的:
import websocket
import json
def on_message(ws, message):
data = json.loads(message)
# 这里拿到的是逐笔成交或盘口变动
process_tick(data)
def on_error(ws, error):
print(f"连接异常: {error}")
# 我曾经在这里吃过亏——忘记重连逻辑
reconnect()
ws = websocket.WebSocketApp(
"wss://api.exchange.com/market/tick",
on_message=on_message,
on_error=on_error
)
ws.run_forever()
你想想看,如果模型训练时缺了那5分钟的数据,预测出来的价差能准吗?
3.3 数据清洗:脏数据比没数据更可怕
拿到原始Tick数据后,千万别急着喂给模型。我见过太多人直接拿原始数据跑回测,结果收益曲线漂亮得不像话——后来发现是数据里有「未来函数」。
常见的脏数据问题:
- 时间戳错乱:交易所的时钟和你的服务器时钟不同步
- 重复数据:同一笔成交被推送了两次
- 缺失数据:某几秒的盘口数据完全空白
- 异常价格:比如卖一价突然比买一价还低(这明显不合理)
我的清洗流程一般分三步:
- 去重:按「时间戳+成交编号」做唯一性校验
- 排序:按时间戳升序排列,检查是否有乱序
- 插值:对于缺失的秒级数据,用前后Tick做线性插值
def clean_ticks(raw_ticks):
# 去重
unique_ticks = raw_ticks.drop_duplicates(subset=['timestamp', 'trade_id'])
# 排序
sorted_ticks = unique_ticks.sort_values('timestamp')
# 检查时间间隔
time_gaps = sorted_ticks['timestamp'].diff()
abnormal_gaps = time_gaps[time_gaps > pd.Timedelta(seconds=5)]
if len(abnormal_gaps) > 0:
print(f"发现{len(abnormal_gaps)}处异常时间间隔")
return sorted_ticks
3.4 数据对齐:让不同频率的数据「对上话」
做价差预测时,你通常需要同时用到多个数据源:Tick级的逐笔成交、秒级的盘口快照、分钟级的K线。这些数据的时间频率不一样,怎么对齐?
嗯,这里要注意一个核心原则:以最细粒度的时间戳为基准。
举个例子:
- 逐笔成交数据:时间戳精确到毫秒,但时间间隔不固定
- 盘口快照数据:每500毫秒推送一次
- K线数据:每分钟一根
我的做法是:先把所有数据都重采样到同一个时间轴上。通常我会选100毫秒作为基准间隔——太细了数据量太大,太粗了会丢失Tick级的信息。
import pandas as pd
# 假设tick_data是逐笔成交,snapshot_data是盘口快照
tick_resampled = tick_data.resample('100ms').agg({
'price': 'last',
'volume': 'sum'
})
snapshot_resampled = snapshot_data.resample('100ms').last()
# 对齐合并
aligned_data = pd.concat([tick_resampled, snapshot_resampled], axis=1)
aligned_data = aligned_data.dropna() # 去掉对齐后仍有缺失的行
🔑 关键点:对齐时最容易犯的错误是「向前看」——用未来的数据填充当前的空缺。这在回测里是致命的。一定要用「向后填充」或「插值」,千万别用未来的信息。
3.5 知识体系总览
下面这张图是我自己总结的数据处理流程,你可以把它当作一个检查清单:
这张图把整个流程串起来了。从数据获取到清洗再到对齐,每一步都马虎不得。我刚开始做的时候,总觉得清洗这一步浪费时间,后来被坑过几次才明白——数据质量决定了模型的天花板。
好了,数据获取和清洗就聊到这儿。记住一句话:好数据是好模型的一半。下一章咱们会基于这些干净的数据,开始构建真正的价差预测特征。