第三章:委托单流数据获取——从Level-2行情到可用数据

做量化交易的朋友都知道,数据是命根子。但说实话,很多人第一步就栽了——拿到的委托单数据根本不能用。我刚开始做高频策略时,就吃过这个亏。今天咱们聊聊怎么用Python把Level-2行情数据拿到手,洗干净,存起来。

3.1 Level-2行情到底多了什么?

普通行情(Level-1)每3秒推送一次,只有五档买卖盘。Level-2呢?

  • 逐笔成交:每一笔真实成交,精确到毫秒
  • 十档行情:买卖各10档,不是5档
  • 委托队列:前50笔挂单的明细
  • 逐笔委托:每一笔撤单、挂单的记录

嗯,这里要注意:不同券商的Level-2数据格式不一样。我遇到过最坑的一次,某券商把委托队列的买卖方向搞反了,害我回测亏了三天才发现。

核心结论:Level-2的核心价值在于「逐笔」数据。没有逐笔,你看到的都是聚合后的结果,很多微观信号就丢了。

3.2 数据获取:两种主流方案

我个人习惯用两种方式获取Level-2数据。你想想看,选哪种取决于你的策略频率和预算。

方案一:通过券商API直连

适合做高频的团队。延迟低,但门槛高。

# 以某券商API为例(伪代码)
from broker_api import Level2Client

client = Level2Client(api_key='your_key', secret='your_secret')

# 订阅逐笔成交
def on_tick(data):
    print(f"时间:{data['time']}, 价格:{data['price']}, 量:{data['volume']}")

client.subscribe('600519.SH', 'tick', on_tick)
client.start()

我的经验:API直连的坑在于网络抖动。我曾经因为机房网络波动,丢了3秒的逐笔数据,回测结果直接偏了5%。建议做本地缓存+断线重连机制。

方案二:通过数据服务商购买

适合大多数个人交易者。比如万得、聚宽、Tushare等。延迟稍高,但省心。

# 以Tushare为例
import tushare as ts

pro = ts.pro_api('your_token')

# 获取某只股票的逐笔成交
df = pro.tick(
    ts_code='600519.SH',
    trade_date='20240115',
    start_time='093000',
    end_time='150000'
)
print(df.head())

避坑指南:我曾经用某免费数据源做回测,发现它的逐笔数据是「模拟」的——把3秒快照拆成了逐笔。这种数据做策略,结果就是纸上富贵。一定要确认数据是真实逐笔还是合成逐笔。

3.3 数据清洗:脏数据比没数据更可怕

拿到原始数据后,别急着跑策略。先洗一洗。我总结了三步走:

第一步:去重

Level-2数据经常有重复推送。尤其是网络重连后,会补发历史数据。

# 去重逻辑
df = df.drop_duplicates(subset=['time', 'price', 'volume'])
print(f"去重后剩余 {len(df)} 条")

第二步:异常值过滤

价格突变、成交量异常大,这些很可能是数据错误。

# 价格异常过滤
price_mean = df['price'].mean()
price_std = df['price'].std()
df = df[(df['price'] > price_mean - 3*price_std) & 
        (df['price'] < price_mean + 3*price_std)]

注意:3倍标准差过滤对高频数据可能太激进。我一般用中位数绝对偏差(MAD),对极端值更鲁棒。

第三步:时间对齐

不同数据源的时间戳精度不一样。有的精确到毫秒,有的只到秒。必须统一。

# 统一时间格式
df['time'] = pd.to_datetime(df['time'], unit='ms')
df = df.set_index('time').resample('1S').agg({
    'price': 'last',
    'volume': 'sum'
})

3.4 数据存储:CSV还是数据库?

这个问题我纠结了很久。直接说结论:

存储方案 优点 缺点 适用场景
CSV 简单、可读性强、方便分享 查询慢、不支持并发、占用空间大 小规模回测、个人研究
SQLite 轻量、支持SQL查询、单文件 并发写入差、不适合大规模 中等规模、单机策略
ClickHouse 列式存储、查询极快、支持高并发 部署复杂、需要运维 生产环境、高频策略

我个人习惯:研究阶段用CSV,上线后用ClickHouse。为什么?CSV方便我肉眼检查数据质量,ClickHouse能支撑每秒几万条的写入。

# CSV存储示例
df.to_csv('level2_600519_20240115.csv', index=False)

# SQLite存储示例
import sqlite3
conn = sqlite3.connect('level2.db')
df.to_sql('tick_data', conn, if_exists='append', index=False)
conn.close()

小技巧:CSV文件建议按日期分片存储。比如每天一个文件,文件名带日期。这样查询某一天的数据时,不用加载全部。

3.5 知识体系总览

下面这张图是我自己画的,把整个数据获取流程串起来了。你保存下来,以后做数据管道时对照着看。

委托单流数据获取流程 Level-2行情源 券商API / 数据商 逐笔成交/委托 数据清洗与预处理 去重 异常值过滤 时间对齐 方向校验 CSV(研究阶段) SQLite(中等规模) ClickHouse(生产) 可用委托单流数据 → 策略回测/实盘

3.6 避坑总结

最后,把我踩过的坑列出来,你少走弯路:

  1. 数据源校验:拿到数据后,先随机抽几条,跟行情软件对比。我吃过亏,某数据商把买一卖一搞反了。
  2. 时间戳精度:不同交易所精度不同。上交所精确到毫秒,深交所精确到微秒。合并数据时一定要对齐。
  3. 存储性能:CSV写入速度慢,一天的数据可能几百万行。建议用二进制格式(如Parquet)替代CSV。
  4. 数据完整性:网络波动会导致数据缺失。我习惯在采集端做心跳检测,超过1秒没数据就报警。

一句话总结:数据获取不是简单的「调API、存文件」。从源头校验到清洗再到存储,每一步都可能埋坑。你想想看,如果数据本身是错的,再牛逼的策略也是白搭。


公众号:蓝海数据掘金营,微信deep3321