halo 的技术博客

返回

买卖价差(bid-ask spread)是金融市场里最被低估的”免费午餐”——你每笔交易实际付出的隐性成本。但它不是一个单一的东西。一个经典的拆解把价差写成三种经济成本的叠加:

St=ctinfo逆向选择+ctinv库存+γ指令处理+etS_t = \underbrace{c_t^{\rm info}}_{\text{逆向选择}} + \underbrace{c_t^{\rm inv}}_{\text{库存}} + \underbrace{\gamma}_{\text{指令处理}} + e_t

  • 逆向选择成本(adverse selection):你这笔交易对面,可能站着比你更懂行的”知情交易者”。做市商挂单被知情单吃掉时要亏钱,所以必须在价差里预先收一笔”信息税”。坏消息越多、信息不对称越严重,这项越高。
  • 库存成本(inventory):做市商刚跟你成交完,手里头寸就偏了。为了把库存调回中性、承担临时持有风险,他也要在报价里加价。
  • 指令处理成本(order processing):撮合、清算、监管等近似固定的运营成本,通常最稳定。

把这三块从一条观测到的价差序列里拆开,是微观结构研究的硬功夫。本文用状态空间模型 + 卡尔曼滤波做这个分解——关键技巧是:把价差当成观测,把逆向选择与库存当成两个动态不同的隐状态,靠它们”慢 vs 快”的节奏差异把彼此认出来。

一、为什么能从一个观测拆出两个隐状态#

直觉上,一个方程 St=xt+yt+γS_t = x_t + y_t + \gamma 有两个未知数,解不出来。但状态空间模型能解,靠的是结构识别(identification via dynamics)

  • 逆向选择成分是”慢变量”——信息不对称是黏性的,今天的信息优势会持续好多笔,所以建模成高持续性 AR(1):ϕinfo0.92\phi_{\rm info} \approx 0.92
  • 库存成分是”快变量”——做市商几笔之内就把库存调平了,所以建模成低持续性 AR(1):ϕinv0.55\phi_{\rm inv} \approx 0.55

观测方程只有一条,但两个隐状态的**时间签名(temporal signature)**不同:慢成分贡献的是低频漂移,快成分贡献的是高频抖动。卡尔曼滤波(连同 RTS 平滑)正是干这个的——它从单条噪声观测里,用动态结构把两个 latent 分离出来。

真实成分堆叠成价差:逆向选择(蓝)+库存(红)+指令处理(绿,近似常数),灰色细线是含噪观测

二、状态空间模型设定#

把第 tt 笔(或第 tt 分钟)的隐状态记为 xt=[ctinfo,  ctinv]x_t = [c_t^{\rm info},\; c_t^{\rm inv}]^\top,观测是报价价差 StS_t

状态转移(两个独立的 AR(1) 偏离项):

xt=Fxt1+wt,wtN(0,Q),F=[ϕinfo00ϕinv]x_t = F\,x_{t-1} + w_t,\qquad w_t \sim \mathcal N(0, Q),\quad F=\begin{bmatrix}\phi_{\rm info}&0\\0&\phi_{\rm inv}\end{bmatrix}

观测方程:

St=Hxt+γ+et,etN(0,R),H=[1,  1]S_t = H\,x_t + \gamma + e_t,\qquad e_t \sim \mathcal N(0,R),\quad H=[1,\;1]

γ=2.0\gamma=2.0 bps 是指令处理成本(常数),作为观测截距。下面给出完整的卡尔曼滤波器(2 维线性高斯,自己实现,不依赖黑箱):

注意几个工程细节:观测噪声方差 RR 要设得比隐状态过程噪声大,否则滤波会把噪声当信号;初始化用无条件方差能让前几十步更稳;RTS 平滑比单纯滤波在样本内复原上更干净,因为它利用了”未来”信息。

三、复原质量:滤波器真的拆开了吗#

我们用已知的真实成分合成数据(逆向选择均值 3 bps、库存均值 1.4 bps、指令处理 2 bps,加观测噪声),跑上面的滤波器,把平滑估计和真实值比:

  • 逆向选择成分复原相关 0.756,库存成分复原相关 0.675
  • 复原 RMSE 均为 ≈1.36 bps(相对 6.76 bps 的均值价差,误差约 20%,主要来自两个成分在单观测下的固有混淆)。

卡尔曼平滑(虚线估计)几乎贴合真实隐状态(实线):上=逆向选择,下=库存

这个”≈0.7 的相关 + ≈1.3 bps 误差”是诚实的结果:单观测下两个隐状态不可能 100% 分清,但经济结构(慢/快节奏)足以把大部分信息还原出来。如果你想更准,可以加第二个观测(比如同时用报价价差和成交价冲击),识别度会显著提升。

四、均值价差的成分构成#

把整段序列平均,得到这张”价差切片图”:

均值 6.76 bps 的价差被切成三块:逆向选择约 49%、库存约 22%、指令处理约 30%

在我们设定的参数下,逆向选择 ≈ 3.30 bps(约 49%)、库存 ≈ 1.46 bps(约 22%)、指令处理 = 2.00 bps(约 30%)。这说明:对流动性一般的标的,信息不对称的隐性税往往比很多人以为的更重——它才是价差的大头。这也是为什么”被知情交易者逆向选择”是做市商和被动挂单者最该防范的风险。

五、分解有经济学含义:信息事件窗口#

分解不是数学游戏,它有可解释的经济含义。我们在序列中段人造了一个”信息事件窗口”(比如财报、重大新闻),给逆向选择成分叠了一道冲击,库存成分保持平稳。看窗口放大图:

信息事件窗口里,逆向选择成本(蓝)明显跳升,库存成本(红)几乎不动,观测价差(灰)跟随上移

这正是我们想要的分离效果:逆向选择随信息事件跳升,库存成分稳如磐石。如果你在真实 tick 数据上看到”某只股票价差突然放大但库存指标没动”,基本可以判定是信息驱动而非流动性挤兑——这对事件驱动策略和做市风控是直接可用的信号。

六、真实数据怎么落地(不用假设 DGP)#

本文为了演示可控,直接用了生成数据的真实参数做滤波。真实落地时你不会知道 ϕ,σ\phi, \sigma,而且更常见的是反过来用交易数据估计成分,而不是先假设状态空间:

经典做法是 Huang–Stoll (1997) / MRR (1997) 的协方差分解。给定带符号的成交流水(买 = +1,卖 = −1)和价格变动 Δpt\Delta p_t,估计:

Δpt=αqt+βΔqt+γqt1+εt\Delta p_t = \alpha\,q_t + \beta\,\Delta q_t + \gamma\,q_{t-1} + \varepsilon_t

其中 2α2\alpha 就是逆向选择成分(信息),其余项对应库存与指令处理。另一种是从 Roll (1984) 有效价差出发,用 cov(Δpt,Δpt1)\text{cov}(\Delta p_t, \Delta p_{t-1}) 的负自协方差反推隐性有效价差。无论哪条路,思路一致:用”成交方向”和”价格冲击”的协方差结构反解成分,而不是凭空假设两个 AR(1)。

七、已知偏差与边界#

  • 识别靠的是动态结构:如果逆向选择和库存的真实持续性其实很接近,单观测分解会显著劣化——这正是为什么真实数据通常要引入第二个观测(成交价冲击)或多标的联合滤波。
  • 状态空间是线性高斯近似:极端行情下成分可能非平稳(比如闪崩时库存成本瞬时爆炸),这时要换 regime-switching 或 Student-t 噪声。
  • 本文结果是方法演示:用合成数据证明”能拆开”,真实幅度要按第六节的方法在你自己的 tick 数据上重估,不能直接搬 3.30/1.46/2.00 这几个数。
  • 指令处理成本设为常数:真实中它随成交量、交易所规则缓慢变化,精细建模应让它也随时间走。

结论#

买卖价差拆成”逆向选择 + 库存 + 指令处理”三块后,交易成本和做市风险才真正可读。状态空间 + 卡尔曼滤波提供了一条不靠强假设、可解释、可落地的分解路径:慢/快动态差异让单观测也能认出两个隐状态。对你而言,最实用的两点是——(1)逆向选择往往是价差大头,挂单者和做市商要优先防知情单;(2)价差在信息事件下的”只跳逆向选择、不跳库存”是可直接监控的微观结构信号。

买卖价差的状态空间分解:逆向选择成本与库存成本
https://blog.halo26812.eu.org/blog/spread-decomposition-ss
Author halo
Published at 2026年7月13日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨