halo 的技术博客

返回

你以 100 块「市价」买入一只股票,但市场上真实的买方报价(bid)可能是 99.9、卖方报价(ask)是 100.1。中间那 0.2 块就是买卖价差(bid-ask spread)——你交易时实际付出的隐性成本。机构每天在数十只标的上进进出出,价差累积起来就是实打实的磨损。

结论先放这:

Corwin & Schultz (2012) 证明:不需要逐笔成交明细,只靠每日的最高价 H 和最低价 L,对比「单日高低区间」与「相邻两日重叠高低区间」,就能把隐藏的买卖价差反演出来。本质是解一个二元一次方程组——价差 s 和日波动率 σ 被encode在这两个区间里,对比二者即可分离。

实战里,H/L 从任意行情源(Tushare、Yahoo、交易所日线)都能直接拿到;对 A 股还要注意用「未复权」或统一「前复权」的 H/L,避免除权日的高低跳变污染区间。

实战里,H/L 从任意行情源(Tushare、Yahoo、交易所日线)都能直接拿到;对 A 股还要注意用「未复权」或统一「前复权」的 H/L,避免除权日的高低跳变污染区间。


一、为什么每日高低价里藏着价差#

1. 一个朴素的直觉#

一天之内,价格不会只停在中间价(mid)上。它在买卖价之间上蹿下跳:最高价接近当日的 ask 上沿,最低价接近 bid 下沿。于是:

ln(Ht/Lt)s+日内波动率带来的区间\ln(H_t / L_t) \approx s + \text{日内波动率带来的区间}

其中 s 就是相对价差(spread,取对数后)。如果某天价格波动很小(低波动),但高低区间依然很宽——那宽出来的部分,大概率就是价差。

2. 关键技巧:用「两日区间」分离波动率#

难点是:单日区间同时混着「价差」和「波动率」。Corwin-Schultz 的巧思是再看相邻两日重叠的高低区间 ln(max(H_{t-1},H_t)/min(L_{t-1},L_t))。两日区间里,波动率按 √2 累积放大,但价差只加一次(两日共用同一套买卖价逻辑)。于是:

  • 单日区间:h1 = s + c1·σ
  • 两日区间:h2 = s + c2·σ ,其中 c2 > c1

两个未知数(s, σ)、两个方程——直接可解:

σ=h2h1c2c1,s=h1c1σ\sigma = \frac{h_2 - h_1}{c_2 - c_1}, \quad s = h_1 - c_1 \cdot \sigma

c1, c2 是「区间对该波动率的敏感度常数」,由日内采样结构决定,可用蒙特卡洛标定(下文详做)。


二、从零实现:标定区间常数 c1、c2#

我们先造一个「纯噪声、无价差」的日线,统计单日与两日高低区间对波动率的敏感度,得到 c1, c2。这一步在 s=0 下做,避免价差与波动率在数据里混在一起难以分离。

c2-c1≈1.796 是这套方法的「对比杠杆」:两日区间比单日区间多出来的波动率敏感度。c1≈4.46 表示单日高低区间约等于 4.46 × 日波动率(这是 48 个日内采样点下的经验常数)。


三、反演估计器#

拿到 c1, c2 后,对任意一段真实日线,滚动地对比单日与两日区间即可反演出价差。

价格路径与日内高低价差带如下——价差带越宽,隐性买卖价差越大。

价格路径与日内高低价差带(价差带越宽 = 隐性买卖价差越大)


四、验证:估计能还原价差的时间变化吗?#

我们造一段「已知真实价差」的模拟日线:平静期 80bps、温和压力 150bps、高压期 250bps,日内波动率压低到 0.6%,让价差成为区间里「有意义的成分」(这一点很关键,见第六节陷阱)。把真实价差与估计价差摆在一起:

CS 估计 vs 真实价差:忠实地还原 80→250 bps 的走阔

分区间核对(取每个区间的均值估计,比滚动噪声更稳):

分区间验证:CS 估计对价差水平与排序的还原

区间真实价差CS 估计还原度
平静80 bps~44 bps方向对、偏小
温和压力150 bps~101 bps67%
高压250 bps~254 bps几乎精确

排序完美(平静 < 温和 < 高压),高压窗口几乎 1:1 还原。这说明 CS 估计最核心的价值——捕捉价差的时间变化与相对排序——是真实有效的。

滚动估计的分布也明显右移:压力期估计整体高于平静期。

平静 vs 压力:滚动估计分布明显右移


五、滚动窗口越长的稳定性#

价差估计本质在用「区间差」反推,单日噪声很大。用更长滚动窗口平均,能显著压低噪声:

窗口越长越稳:噪声随窗口下降

这也是 Corwin-Schultz 原论文的建议:实际估计时用 1 个月(约 21 个交易日)的滚动窗口做平均,而不是逐日估计。


六、五个不能忽略的真实陷阱#

别把上面的「还原」当成万能。以下每一条都会让估计翻车:

  1. 低频数据病态条件(最大陷阱):本文的标定里 c2-c1≈1.8,而 c1≈4.46。价差 s 是从「大范围里抠出的小残差」反推的——s = h1 - 4.46·σ。一旦 h2-h1(用来估 σ 的量)有 5% 误差,s 就会被放大约 4.46/1.8≈2.5 倍。当价差相对波动率极小时(比如大盘股 1–2 bps 价差 vs 1% 日波动),s 几乎被噪声淹没,估计会严重失真。这也是为什么本文用「宽价差/低波动」的较不活跃标的来演示——CS 方法在流动性差、价差占比大的资产上才稳。

  2. 日收益自相关稀释对比杠杆:上面的 c2-c1≈1.8 假设相邻日收益近似独立。若日收益有自相关(趋势市、连续涨跌),两日区间不会按 √2 累积波动率,实际 c2-c1 会被压小,进一步恶化病态条件。真实实现需先检验/修正自相关。

  3. 小价差系统性低估:表中平静期(80 bps)只还原出 44 bps,而高压期(250 bps)近乎精确——小价差被低估、大价差还原好。这是反演法固有的非线性:残差越小,相对误差越大。应用时不能把估计值当绝对真值,应看其相对变化

  4. 窗口长度主观:用 10 日、20 日还是 30 日窗口,估计水平会漂移。应报告敏感性(如第五节),而非给一个「标准答案」。

  5. 微观结构噪声:真实日线的高/低可能受盘中熔断、集合竞价、临时停牌污染;且若用复权价,高低区间会混入除权跳变。应用前需清洗高低价、统一复权口径。


七、小结#

Corwin-Schultz 把「看不见的买卖价差」变成了一个只用每日最高/最低价就能算的量化指标。它的优雅在于:不需要任何逐笔成交数据,对比单日与两日的高低区间,解一个二元一次方程组就分离出价差和波动率。

但它的有效是有条件的:价差必须是当日区间里「有意义的成分」——流动性越差、价差占比越大,估计越稳;而对大盘股那种「价差淹没在波动里」的场景,它本质上是病态条件的,结果只能看相对变化、不能当绝对真值。

把它当作「价差相对水平的温度计」而非「精密卡尺」——这才是工程上诚实的用法。

买卖价差 Corwin-Schultz 估计:只用每日最高最低价,把「隐性成本」算出来
https://blog.halo26812.eu.org/blog/corwin-schultz-spread
Author halo
Published at 2026年7月21日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨