3. 价差计算口径与时间对齐
在买卖价差异常扩大的识别中,最容易出错的地方往往不是判断逻辑,而是计算口径和时间对齐。同一段行情,用绝对价差还是相对价差、用快照价差还是有效价差、用左对齐还是右对齐重采样,得到的曲线形态可能完全不同,甚至会把正常波动误判为异常扩大。本节围绕三个口径和一套对齐流程展开,目标是产出一条口径明确、时间戳可信、可直接进入异常检测的价差时间序列。
一、三种价差口径的定义与适用场景
先统一符号约定:设某时刻最优买价为 Bid,最优卖价为 Ask,中间价为 Mid = (Bid + Ask) / 2。全文价差均以“卖价减买价”为正方向,即价差扩大表现为数值上升。
- 绝对价差:
Spread_abs = Ask − Bid,单位与报价一致(如元、美元)。它直接反映“立即买入再立即卖出”的即时成本,适合同一标的、同一价格量级下的横向比较,也适合做固定阈值的监控,例如“价差超过 0.05 元即告警”。缺点是无法跨标的、跨价位比较。 - 相对价差:
Spread_rel = (Ask − Bid) / Mid,通常以基点(bp)表示,乘以 10000 即Spread_bp。它把价差归一化到价格水平上,适合跨标的、跨时段比较,也适合做统计型异常检测,因为不同价位的标的在相对口径下分布更接近。 - 有效价差:
Spread_eff = 2 × |Trade_Price − Mid|,其中Trade_Price为实际成交价。它衡量成交价相对中间价的偏离程度,反映真实成交付出的成本,能捕捉“报价价差不大但成交价明显偏离”的情形。有效价差依赖逐笔成交数据,且需要与成交时刻的中间价对齐,计算复杂度最高。
三者的关系可以这样理解:绝对价差看“名义报价宽度”,相对价差看“归一化后的报价宽度”,有效价差看“实际成交的偏离”。在异常扩大识别中,建议以相对价差为主监控口径,绝对价差作为辅助阈值,有效价差用于事后归因和验证。
二、时间戳对齐:不同频率数据的核心难点
实际数据往往来自不同频率:盘口快照可能是 3 秒一笔或 500 毫秒一笔,逐笔成交是事件驱动、时间间隔不规则,而日频或分钟频数据又是另一套节奏。直接把这些序列拼在一起计算,会出现“用 10:00:03 的中间价去匹配 10:00:01 的成交价”这类错配,导致有效价差被系统性放大或缩小。
对齐的基本原则是:以低频序列为基准,把高频序列聚合或取值到低频时间点上,并明确每个时间点的取值规则。常用做法有三种:
- 最近邻取值(as-of):对每个基准时间点,取该时刻之前(或之前最近)的一条高频记录。适合盘口快照与成交匹配,能保证“用的是当时已知的信息”,避免未来函数。
- 区间聚合:把高频数据按基准时间区间分组,取均值、最大值或最后值。例如把 500 毫秒快照聚合成 3 秒一根,取区间内价差均值,能平滑噪声但会损失极值信息。
- 重采样(resample):把不规则时间序列映射到固定频率网格上,常用
last、mean、max等聚合函数,并配合前向填充处理空缺。重采样后必须记录每个格点实际覆盖的原始记录数,记录数过少的格点应标记为低置信度。
三、实战计算流程与示例
下面给出一段可复现的计算流程,示例参数均为教学假设,不代表真实市场数据。假设某标的盘口快照间隔 3 秒,逐笔成交不规则,我们以 3 秒为基准网格。
# 示例:以 3 秒网格对齐并计算三种价差(伪代码)
grid = resample_3s(start="09:30:00", end="11:30:00")
# 1) 盘口快照:每个格点取区间内最后一条快照
snap = snapshots.resample(grid, how="last")
snap["mid"] = (snap.bid + snap.ask) / 2
snap["spread_abs"] = snap.ask - snap.bid
snap["spread_bp"] = (snap.ask - snap.bid) / snap.mid * 10000
# 2) 逐笔成交:按成交时间归入格点,取该格点内成交量加权成交价
trade = trades.resample(grid, how="vwap")
trade["spread_eff"] = 2 * abs(trade.vwap - snap.mid)
# 3) 记录覆盖度,低覆盖格点打标
snap["snap_cnt"] = snapshots.count(grid)
snap["low_conf"] = snap.snap_cnt < 1
假设某格点快照为 Bid=10.00、Ask=10.04,则该格点 Mid=10.02,Spread_abs=0.04,Spread_bp≈39.92bp。若该格点内成交 VWAP 为 10.03,则 Spread_eff=2×|10.03−10.02|=0.02。可以看到,报价价差 0.04 与有效价差 0.02 并不相等,这正是两种口径的差异所在:成交发生在中间价附近时,有效价差会小于名义报价价差。
完成对齐后,应做三项基本校验:一是检查时间序列是否存在重复时间戳或倒序;二是统计每个格点的原始记录覆盖数,剔除覆盖度为 0 的格点;三是比较对齐前后价差的均值与分位数,若对齐后分布明显偏移,说明取值规则或时区设置有问题。只有通过校验的序列,才适合进入下一步的异常扩大识别。
四、口径选择与结果判读
形成序列后,如何选择主口径取决于监控目标。若目标是“发现报价突然变宽”,用相对价差做主序列,配合滚动分位数(如过去 20 个交易日同时段 95 分位)判断是否异常;若目标是“发现成交成本异常”,用有效价差做主序列,并注意有效价差在成交稀疏时样本不足,需要设置最小成交笔数门槛。绝对价差则适合作为硬阈值兜底,例如价差绝对值超过某档位时直接触发人工复核。
需要强调的是,三种口径的异常信号并不总是一致。报价价差扩大但成交仍集中在中间价附近时,相对价差会上升而有效价差可能平稳,这提示“报价变宽但成交未恶化”;反之,报价价差正常但成交价频繁偏离中间价,有效价差会先于相对价差发出信号。把三条序列放在同一时间轴上对照,比只看单一指标更能区分“真实流动性恶化”和“报价噪声”。
spread_abs、spread_bp、spread_eff 三列以及 snap_cnt、trade_cnt 两个覆盖度字段。后续做异常识别时,任何一条价差记录都应能追溯到它对应的原始记录数和取值规则,这样异常告警才具备可解释性,也便于复盘时判断是市场真的变了,还是对齐环节出了问题。至此,价差序列已经具备“口径明确、时间可信、覆盖度可查”三个条件,可以进入下一步的异常扩大识别。后续所有阈值设定、窗口选择和告警规则,都应建立在本节确定的这套口径与对齐规则之上,避免中途更换口径导致前后结果不可比。