Corwin-Schultz 高低价价差估计:用两日高低价把价差与波动拆开
Corwin-Schultz(2012)的巧思:日最高价几乎总来自 ask、最低价几乎总来自 bid,所以高低价比里藏着价差;而波动随时间线性增长、价差不随时间变——单日高低比与两日高低比联立两个方程,恰好把价差 s 和波动 σ 同时解出。252 日模拟实测:真实价差 2% 时 CS 截零均值 2.05%,几乎无偏;但低价差区间正偏差显著(真值 0.2% 估出 0.83%),因为逐对负估计占比高达 40% 且截零只砍左尾。与 Roll 同台:信噪比低时 Roll 失效率 45% 直接弃赛,CS 至少给出有偏但可用的数字。隔夜跳空是最大污染源:隔夜波动 3% 时估计从 1% 被压到 0.69%(跳空撑大两日区间、γ 膨胀导致低估),平移修正能救回一半。60 日滚动 CS 危机温度计:平静期 0.79%、危机峰值 3.58%,形状完整还原。诚实边界:截零规则在截面比较中引入系统性正偏、非连续交易压低高低区间导致低估、加密/外汇等无隔夜市场反而是最优场景(中阶)。
Corwin-Schultz 高低价价差估计:用两日高低价把价差与波动拆开#
先说结论:Corwin-Schultz (2012) 只用日频的最高价和最低价就能估出买卖价差,核心杠杆是一个不对称:波动的贡献随时间长度线性增长,价差的贡献不随时间变。用单日与两日两个观测窗口联立方程,两个未知数(价差 s、波动 σ)恰好可解。模拟实测:真实价差 2% 时估计 2.05% 几乎无偏;但在低价差、高波动的区间它系统性高估,而隔夜跳空让它系统性低估——用之前必须知道这两个偏差往哪边拉。
上一篇《Roll 价差估计量》里我们用收盘价的自协方差反推价差,结局有点尴尬:越流动的股票越容易估出虚数。今天这个估计量用的是另一对被忽视的低频数据——每天的最高价和最低价——而且它对 Roll 失效的场景有明显改善。
一、两个观察,一个联立方程#
观察一:高低价比里藏着价差#
日最高价是全天成交的最高一笔——几乎必然是主动买单打在 ask 上;日最低价几乎必然是主动卖单打在 bid 上。所以观测到的高低价比:
观测高低比 = 真实高低比 × 价差因子。高低价区间被价差撑大了,撑大的幅度就是 s。问题是真实高低比我们不知道——它由日内波动决定,一个方程两个未知数,解不出。
观察二:波动随时间涨,价差不随时间涨#
Corwin-Schultz 的破局点:把观测窗口从一天拉长到两天。
- 波动的贡献:两日的真实高低区间来自两天的随机游走,期望上是单日的 2 倍(方差意义);
- 价差的贡献:两日区间的顶仍然只被一个 ask 撑高、底只被一个 bid 压低——价差的贡献和单日完全一样。
于是定义两个统计量:
β 是相邻两个单日高低比平方之和(价差被计入两次),γ 是两日联合区间的高低比平方(价差只计入一次)。两个方程、两个未知数,解出:
公式长得吓人,但骨架就一句话:β 里价差占两份、γ 里占一份,做差把波动消掉,剩下的就是价差。
import numpy as np
K = 3 - 2 * np.sqrt(2)
def corwin_schultz(H, L): # H, L 为对数最高/最低价序列
hl2 = (H - L) ** 2
beta = hl2[:-1] + hl2[1:] # 相邻两日各自区间平方和
H2 = np.maximum(H[:-1], H[1:]) # 两日联合最高
L2 = np.minimum(L[:-1], L[1:]) # 两日联合最低
gamma = (H2 - L2) ** 2
alpha = (np.sqrt(2*beta) - np.sqrt(beta)) / K - np.sqrt(gamma / K)
s = 2 * (np.exp(alpha) - 1) / (1 + np.exp(alpha))
return np.maximum(s, 0) # 负值截零(原文建议)python二、实验一:回收精度与负值陷阱#
模拟真实的日内路径:78 个 5 分钟中间价随机游走,观测高价 = 路径最高点 + s/2,低价 = 路径最低点 − s/2。日波动 2%,T=252,真实价差从 0.2% 扫到 5%:
| 真实价差 | CS 截零均值 | CS 原始均值 | 逐对负值占比 |
|---|---|---|---|
| 0.2% | 0.83% | 0.14% | 40.7% |
| 0.5% | 1.02% | 0.44% | 36.0% |
| 1.0% | 1.31% | 0.86% | 29.8% |
| 2.0% | 2.05% | 1.84% | 17.5% |
| 3.0% | 2.86% | 2.77% | 9.3% |
| 5.0% | 4.69% | 4.68% | 1.4% |

三个层次的读法:
- 中高价差区几乎无偏:s=2% 估出 2.05%,s=3% 估出 2.86%。信噪比(s/σ日)过 1 之后 CS 是个合格的点估计。
- 低价差区被截零规则拉高:真值 0.2% 估出 0.83%,偏差 4 倍。机制和 Roll 的虚数价差同源——逐对估计噪声大,40% 的样本落到负区;截零只砍左尾不砍右尾,均值必然上移。注意原始均值(不截零)反而低估(0.14%),说明”截零 vs 不截零”是在两个方向的偏差之间选边。
- 负值占比本身就是信息:它单调反映信噪比,类似 Roll 失效率——负值占比超过 30% 时,这只股票的 CS 点估计基本不可信,只能做截面排名。
三、实验二:与 Roll 同台#
同一批模拟数据(既有收盘价也有高低价),CS 对 Roll:
| 真实价差 | CS | Roll(失效剔除) | Roll 失效率 |
|---|---|---|---|
| 0.2% | 0.83% | 0.74% | 45% |
| 0.5% | 1.00% | 0.91% | 37% |
| 1.0% | 1.31% | 1.03% | 20% |
| 2.0% | 2.07% | 1.91% | 0% |
| 5.0% | 4.73% | 4.92% | 0% |

高信噪比区两者打平。差异全在低信噪比区:Roll 直接弃赛(45% 失效率,且失效非随机——上一篇讲过这是选择偏差),CS 至少给出一个有偏但存在的数字。原因在信息含量:收盘价只是日内路径的一个采样点,高低价是整条路径的两个极值统计量——同样一天数据,高低价对波动和价差的信息压缩效率高得多。这也是为什么 CS 用 T=252 就能工作,而 Roll 在同样窗口下大面积失效。
实务选择:两者都要低频数据,CS 的信息效率更高、无失效样本问题,默认优先 CS;Roll 的价值在于只需要收盘价(部分历史久远或另类资产只有收盘价)。
四、实验三:隔夜跳空——最大的污染源#
CS 的推导假设价格过程连续。但真实市场每天闭市 17.5 小时,隔夜信息在开盘瞬间跳进价格。跳空对两个统计量的污染不对称:单日区间 β 不含跳空(高低价都在盘中),两日联合区间 γ 却把跳空整个吞进去——γ 被撑大,而公式里 γ 前面是负号,结果是低估:
| 隔夜波动 | 不修正 | 平移修正后 | 真值 |
|---|---|---|---|
| 0% | 1.33% | 1.33% | 1% |
| 1% | 1.14% | 1.18% | 1% |
| 2% | 0.89% | 1.00% | 1% |
| 3% | 0.69% | 0.83% | 1% |

隔夜波动 3%(大约是 A 股受隔夜美股影响的量级)时,估计被压掉三成。Corwin-Schultz 原文的修正:如果今天的整个高低区间在昨收之上(跳空高开),就把今天的高低价整体平移下来贴住昨收,反之亦然。模拟里这个修正在隔夜波动 2% 时把 0.89% 救回 1.00%,完全命中真值;3% 时救回一半。
推论:没有隔夜的市场是 CS 的最优场景——加密货币 7×24、外汇周内连续,都不需要修正。反过来,对跳空频繁的品种(财报季个股、A 股受外盘驱动的时期),不做修正的 CS 会系统性低估价差,恰好在流动性最差的时候最失真。
五、实验四:滚动 CS 做危机温度计#
与上一篇 Roll 的同款实验:250 天平静(真实价差 0.6%)→ 120 天危机(3%,波动同步放大 3 倍)→ 250 天恢复(0.8%),60 日滚动均值:

平静期均值 0.79%(真值 0.6%,正偏来自截零),危机峰值 3.58%(真值 3.0%,滚动窗口平滑加噪声)。形状完整还原:进入危机的爬坡、峰值平台、恢复期的衰减都清晰可辨。作为不需要任何盘口数据的流动性监控指标,这个还原度足够做风控输入——重要的是相对变化(价差翻了 5 倍)而非绝对水平。
六、诚实边界#
截零规则在截面上不是无害的。 低流动性股票负值少、高流动性股票负值多,截零对不同股票的拉高幅度不同——和 Roll 的选择偏差异曲同工,只是表现形式从”样本缺失”变成”系统性正偏”。做截面回归时,负值占比应该作为控制变量或过滤条件。
非连续交易导致低估。 推导假设盘中连续成交,真实高价是”最后一笔主买”而非”理论最高 ask”。成交稀疏的股票观测区间小于理论区间,价差被低估——注意这与截零偏差方向相反,两个偏差部分抵消但不精确抵消,净方向取决于股票的具体特征。
波动率假设。 β 到 γ 的换算用了扩散过程的 √t 缩放。日内波动有 U 型结构、危机期有跳跃,都偏离扩散假设。CS 原文的模拟显示这些偏离的影响温和,但在极端行情下(涨跌停、熔断)单日估计可以完全失真——涨停日高低区间被人为压缩,CS 会把它读成”流动性极好”,实际恰恰相反。A 股使用时涨跌停日必须剔除。
它估的是有效价差的均值,不是挂单价差。 与 Roll 相同,CS 反映的是成交价相对中间价的偏离,报价价差、盘口深度它都看不到。
七、工程落地清单#
- 默认配置:对数高低价 → 逐对估计 → 隔夜平移修正 → 负值截零 → 21 日或 60 日滚动均值;
- A 股特化:剔除涨跌停日和停牌复牌首日;隔夜修正必做(外盘驱动的跳空频繁);
- 质量门槛:滚动窗口内负值占比 >30% 时降级为”仅截面排名可用”;
- 搭配使用:CS(价差)+ Zeros(交易活跃度)+ Amihud(价格冲击)三件套,全部只需日频数据,拼出流动性三维画像——分别对应”吃一口的成本、有没有人交易、连续吃的边际成本”;
- 用途分层:截面流动性因子(最稳)> 时序危机监控(滚动均值)> 绝对成本预算(偏差多、慎用)。
结语#
Roll (1984) 和 Corwin-Schultz (2012) 相隔 28 年,解决同一个问题:不用盘口数据估价差。Roll 用收盘价的时间序列性质(自协方差),CS 用高低价的截面性质(极值区间)——后者的信息效率高一个档次,代价是引入了对价格过程更强的假设(连续扩散、无跳空)。
方法论上的启示值得记住:高低价是被严重低估的数据。它们是日内整条路径的极值统计量,信息含量远超”又两个价格点”——从 Parkinson 波动率到 Garman-Klass,再到今天的 CS 价差,一条完整的研究线都建立在这个观察上。你的日频数据库里躺着的 High 和 Low 两列,比你以为的值钱得多。
参考文献:
- Corwin, S. A., & Schultz, P. (2012). A Simple Way to Estimate Bid-Ask Spreads from Daily High and Low Prices. Journal of Finance, 67(2), 719-760.
- Roll, R. (1984). A Simple Implicit Measure of the Effective Bid-Ask Spread in an Efficient Market. Journal of Finance, 39(4), 1127-1139.
- Parkinson, M. (1980). The Extreme Value Method for Estimating the Variance of the Rate of Return. Journal of Business, 53(1), 61-65.