4. 买卖盘口量价字段解析错误
盘口数据是高频与日内策略回测中最容易“看起来对、实际全错”的一类输入。与日线K线不同,盘口快照(Level-1/Level-2)往往以多列并排的形式给出买一至买十、卖一至卖十的价格与数量,字段名相似、顺序固定、单位各异。一旦字段映射错位、单位不统一或量纲混淆,回测不会报错,只会安静地产生一个“收益曲线很漂亮但实盘完全无法复现”的失真信号。本节围绕这三类典型错误,给出可落地的排查方法。
一、三类错误的本质区别
先厘清概念,避免排障时混为一谈:
- 字段映射错误:列与语义对不上。例如把
bid_px_01读成了ask_px_01,或把买盘数量列bid_vol_01与卖盘数量列ask_vol_01顺序颠倒。数据本身合法,但语义被交换。 - 单位不一致:同一语义在不同数据源或不同字段间单位不同。价格有的用“元”,有的用“分”;数量有的用“股”,有的用“手”(1手=100股)。
- 量纲混淆:把不同物理意义的量直接比较或运算。典型如把“委托量(挂单量)”当作“成交量”使用,或把“笔数”与“股数”混算,导致盘口不平衡指标(Order Imbalance)量纲错乱。
三者常叠加出现:映射错位后单位自然也对不上,量纲混淆则会让指标在数值上“看似合理”却方向相反。因此排查必须分层进行,不能一步到位地“改个参数试试”。
二、字段映射错误的定位方法
映射错误最可靠的检测手段是语义一致性校验,而非肉眼比对列名。核心思路:利用盘口本身必须满足的硬约束来反推映射是否正确。
约束一:买价必须严格小于卖价(同一档位 bid_px_01 < ask_px_01),且买盘价格随档位递减、卖盘价格随档位递增。若读入后发现大量 bid_px_01 > ask_px_01,几乎可以断定买卖价格列被交换。
约束二:价差(spread)应落在合理区间。若 ask_px_01 - bid_px_01 出现负值或异常大值,说明映射或单位有问题。
约束三:数量列应为非负,且买一量、卖一量通常处于同一数量级。若某一侧恒为 0 或量级相差百倍,需怀疑列错位。
实操中可写一段校验脚本,对全样本统计违规比例:
import pandas as pd
df = pd.read_parquet("snapshot.parquet")
# 约束一:买一价应小于卖一价
bad_spread = (df["bid_px_01"] >= df["ask_px_01"]).mean()
# 约束二:买盘价格应随档位递减
bad_bid_order = (df["bid_px_01"] < df["bid_px_02"]).mean()
# 约束三:数量非负
neg_vol = (df[["bid_vol_01","ask_vol_01"]] < 0).any(axis=1).mean()
print(f"价差异常比例: {bad_spread:.4%}")
print(f"买盘档位逆序比例: {bad_bid_order:.4%}")
print(f"负数量比例: {neg_vol:.4%}")
判断依据:正常数据下三项违规比例应接近 0(允许极少数集合竞价或异常快照)。若价差异常比例超过 1%,优先检查买卖列是否互换;若买盘档位逆序比例高,检查档位列顺序是否被整体反转。
三、单位与量纲的统一
单位问题不会触发约束违规,却会系统性放大或缩小信号。排查要点是建立字段字典并做量级抽样。对价格字段,抽取若干快照与交易所公开行情或行情软件对照,确认是“元”还是“分”;对数量字段,确认是“股”还是“手”。一个实用判据:A股个股买一量通常在数百至数万股之间,若读到的数值普遍在个位数到几十,极可能是“手”为单位,需乘以 100。
量纲混淆更隐蔽。以常用的盘口不平衡指标为例:
# 正确:同量纲(股数)之比
imbalance = (bid_vol_01 - ask_vol_01) / (bid_vol_01 + ask_vol_01)
# 错误示例:把“笔数”与“股数”混算
# bid_count_01 是委托笔数,bid_vol_01 是股数
wrong = (bid_count_01 - ask_vol_01) / (bid_count_01 + ask_vol_01)
错误写法在数值上仍落在 [-1, 1],不会报错,但含义已完全错乱,回测中会表现为信号方向随机或与真实盘口压力无关。排查时应检查每个指标公式中参与运算的字段是否属于同一量纲(价格对价格、股数对股数、笔数对笔数)。
四、一个完整的排查案例
假设某日内策略回测显示:基于买一卖一量不平衡的信号在样本内夏普 2.1,但实盘模拟仅 0.3。按上述三层排查:
- 映射校验:统计发现
bid_px_01 >= ask_px_01的比例为 0,档位顺序正常,映射无误。 - 单位校验:抽样发现
bid_vol_01中位数约 35,而同期行情软件显示买一量约 3500 股,判定数量单位为“手”,需 ×100。修正后量级对齐。 - 量纲校验:审查指标公式,发现不平衡指标中分母误用了
bid_cnt_01 + ask_cnt_01(笔数),而分子是股数差,量纲错配。改为同用股数后,信号方向与盘口压力一致。
修正后重跑,样本内夏普回落至 0.9,与实盘模拟的 0.3 差距显著缩小,剩余差异可归因于滑点与撮合假设,而非数据失真。这说明:回测指标“变差”往往是数据被修正正确的信号,不应因收益下降而回退修改。
五、可复用的字段校验清单
将上述方法固化为每次接入新盘口数据源时必跑的检查项,可显著降低返工成本:
| 检查项 | 判据 | 异常处置 |
|---|---|---|
| 买一价 < 卖一价 | 违规比例 ≈ 0 | 检查买卖列是否互换 |
| 买盘档位价格递减 | 逆序比例 ≈ 0 | 检查档位列顺序 |
| 数量非负 | 负值比例 = 0 | 检查列错位或缺失填充 |
| 价格量级 | 与行情软件同量级 | 元/分换算 |
| 数量量级 | 与行情软件同量级 | 手/股换算(×100) |
| 指标字段同量纲 | 公式内字段语义一致 | 重写公式,禁止跨纲运算 |
最后强调参照约定的一致性:若价格统一用“元”、数量统一用“股”,则全文与图示、指标公式、回测配置都必须保持这一约定,切换单位须在数据接入层一次性完成并记录,避免在策略代码中零散换算造成新的不一致。盘口数据的可靠性,决定了后续所有信号与回测结论的可信度,这一层做扎实,排障才有意义。