2. 逐笔委托数据结构解析:Level2行情数据字段详解

好,咱们直接进入正题。上一章聊了订单流分析的价值,这一章就得动手了——先把数据搞清楚。

说实话,我刚开始接触Level2数据时,第一反应是「这玩意儿怎么这么乱?」。一堆字段,每个交易所的命名还不一样。但后来我发现,只要抓住几个核心字段,剩下的都是锦上添花。

今天咱们就拆解逐笔委托数据的核心结构。我会结合自己踩过的坑,帮你把这块啃下来。

2.1 逐笔委托的核心字段

逐笔委托数据,说白了就是交易所把每一笔挂单和撤单都记录下来了。每条记录包含以下几个关键字段:

字段名 类型 说明
OrderID 字符串 委托单的唯一标识
Price 浮点数 委托价格(单位:元)
Volume 整数 委托数量(单位:股/手)
Side 字符 买卖方向:'B' 买,'S' 卖
Time 时间戳 委托进入系统的时间(精确到毫秒)

嗯,就这五个字段。别小看它们,订单流分析的所有秘密都藏在这里。

OrderID:每笔订单的身份证

OrderID 是唯一的。同一个订单如果被部分成交,剩下的部分会保留同一个 OrderID。我在项目中遇到过一个问题:有些交易所的 OrderID 是递增的,有些则是随机生成的。如果你要做订单生命周期追踪,这个细节很关键。

Price 和 Volume:最直观的博弈数据

Price 和 Volume 组合起来,就是「有人在某个价位挂了多少钱」。举个例子,如果看到连续多个买单在 10.00 元挂了 1000 手,而卖单在 10.01 元只有 200 手,那说明买方在死守 10.00 这个价位。

关键点:Volume 的单位要搞清楚。A股是「股」,但有些数据商给的是「手」(1手=100股)。我吃过这个亏,算出来的资金流差了一个数量级。

Side:买卖方向,但没那么简单

Side 字段只有 'B' 和 'S' 两种值。但这里有个坑:有些数据源把主动买入标记为 'B',被动卖出标记为 'S';有些则反过来。你想想看,如果方向搞反了,你的订单流分析就全错了。

我个人习惯是:拿到数据后先做一个小样本验证。找一笔已知的主动买入,看看 Side 字段是不是 'B'。这一步花不了几分钟,但能避免后面的大麻烦。

Time:毫秒级的战争

Time 字段精确到毫秒。为什么这么重要?因为高频交易就是在毫秒级别抢单的。我曾经分析过一只股票的逐笔数据,发现某个大单在 09:30:00.000 到 09:30:00.500 这 500 毫秒内,被拆成了 20 笔小单。这就是典型的「冰山订单」——大资金在隐藏自己的真实意图。

2.2 数据清洗与预处理实战

原始数据拿到手,第一件事不是分析,而是清洗。我见过太多人直接拿原始数据跑模型,结果跑出来一堆垃圾。

下面是我总结的清洗流程,每一步都有血的教训。

第一步:处理缺失值

逐笔数据中,缺失值通常出现在 Volume 或 Price 字段。比如撤单记录,有些数据源会把 Volume 设为 0 或 null。

# 示例:处理缺失值
import pandas as pd

df = pd.read_csv('tick_data.csv')
# 检查缺失值
print(df.isnull().sum())

# 处理方式:删除或填充
# 我个人建议删除,因为逐笔数据量很大,缺失几条不影响统计
df = df.dropna(subset=['Price', 'Volume'])

注意:不要直接 dropna() 全部删除。先看看缺失值占比。如果超过 5%,说明数据源有问题,需要排查。

第二步:去重

同一个 OrderID 可能因为网络重传出现多次。去重时要注意:保留时间戳最早的那条记录。

# 去重:按 OrderID 去重,保留最早的时间
df = df.sort_values('Time').drop_duplicates(subset='OrderID', keep='first')

我曾经遇到过一个极端情况:某只股票在开盘瞬间,同一个 OrderID 出现了 3 次,时间戳相差不到 1 毫秒。如果不做去重,你的订单流统计会多出 2 倍的虚假数据。

第三步:时间戳对齐

不同数据源的时间戳格式可能不一样。有的是 '2024-01-01 09:30:00.123',有的是 1704061800123(毫秒级时间戳)。统一转换成 datetime 格式,方便后续分析。

# 时间戳转换
df['Time'] = pd.to_datetime(df['Time'], unit='ms')  # 如果是毫秒级时间戳

第四步:异常值过滤

Price 为负数、Volume 为 0、Side 不是 'B' 或 'S'——这些都属于异常值。直接过滤掉。

# 过滤异常值
df = df[(df['Price'] > 0) & (df['Volume'] > 0)]
df = df[df['Side'].isin(['B', 'S'])]

小技巧:过滤完后,打印一下数据量变化。如果过滤掉了超过 10% 的数据,说明原始数据质量堪忧,建议换数据源。

2.3 知识体系结构图

下面这张图是我自己整理的逐笔委托数据解析的知识结构。你可以把它当作一个检查清单,看看自己有没有遗漏。

逐笔委托数据解析知识体系 核心字段(5个) OrderID 唯一标识 Price 委托价格 Volume 委托数量 Side 买卖方向 Time 时间戳 数据清洗与预处理(4步) ① 缺失值处理 删除或填充 ② 去重 保留最早记录 ③ 时间戳对齐 统一格式 ④ 异常值过滤 价格/数量/方向 输出:干净的逐笔委托数据 可用于订单流分析、资金流计算、微观结构建模

2.4 实战:从原始数据到可用数据

光说不练假把式。咱们用一段真实数据走一遍流程。

假设原始数据长这样(CSV格式):

OrderID,Price,Volume,Side,Time
ORD001,10.00,1000,B,2024-01-01 09:30:00.123
ORD002,10.01,500,S,2024-01-01 09:30:00.456
ORD003,10.00,0,B,2024-01-01 09:30:00.789  # Volume为0,异常
ORD001,10.00,1000,B,2024-01-01 09:30:00.123  # 重复记录
ORD004,-1.00,200,S,2024-01-01 09:30:01.000  # 价格为负,异常

清洗后的结果:

OrderID,Price,Volume,Side,Time
ORD001,10.00,1000,B,2024-01-01 09:30:00.123
ORD002,10.01,500,S,2024-01-01 09:30:00.456

你看,5条原始数据,清洗后只剩2条。这就是现实——数据质量从来不会完美。

我的建议:把清洗流程写成函数,每次拿到新数据直接调用。别每次都手动处理,效率太低。

好了,这一章的内容就到这。逐笔委托数据的结构其实不复杂,但细节决定成败。下一章咱们会基于清洗后的数据,开始做真正的订单流分析。


专注资料整理