halo 的技术博客

返回

最小方差对冲(minimum-variance hedge)的教科书解法干净利落:把被套保资产收益 y 对一组候选对冲工具 X 做 OLS 回归,β̂ = (X'X)⁻¹X'y,残差 y − Xβ̂ 就是『对冲掉系统性暴露后』的净收益。残差方差越小,对冲越干净。

但这段公式藏着一个前提:X 里的工具真的携带了和 y 相关的信息,而且 X'X 是可稳稳求逆的高维矩阵。 当对冲工具数量逼近甚至超过样本量、且大部分工具只是噪声时,OLS 会把噪声也『完美拟合』进去——样本内 R² 冲到 1.0,样本外一塌糊涂。本文用 numpy 从零实现 PCA 降维对冲:只保留承载真实信息的少数几个主成分,在 200 工具 / 150 样本 / 3 真实因子的合成设定下,把样本外 R² 从 OLS 的 −322(过拟合塌方)救回到 0.97。附完整 Python 与三张真实计算图。

对冲后残余方差随主成分个数变化;越过真实因子数后下降几乎停止

一、为什么 OLS 在高维会『假装对冲成功』#

设被套保资产由 3 个不可观测公因子驱动,候选对冲工具共 K=200 个,但只有前几个主成分真正承载这 3 个因子的信息,其余 197 个主要是特异性噪声。样本只有 T=150 天。

OLS 解 β̂ = (X'X)⁻¹X'yK≥TX'X 接近奇异,解会疯狂放大噪声;即便 K<T,200 个参数去拟合 150 个样本点,也会把训练集里的随机波动当成『可对冲的规律』。代价在样本外暴露:残差方差被估得极低(甚至 0),但换一批数据就崩。

PCA 的思路是:先对 X 做主成分分解,只取前 p 个主成分(它们压缩了大部分方差、承载了真实因子),再用这 p 个正交成分去回归 y 噪声主成分被直接扔掉,相当于给对冲工具做了一次『信号提纯』。

二、合成实验:200 工具、3 真实因子、150 样本#

完全可复现设定:

T, K = 150, 200
F = rng.standard_normal((T, 3))                       # 3 个真实公因子
B_hedge = rng.standard_normal((K, 3)) * 0.7
B_target = rng.standard_normal((1, 3)) * 0.7
eps_t = rng.standard_normal((T, K)) * 0.6             # 工具特异性噪声(强)
eps_y = rng.standard_normal((T, 1)) * 0.2
X = F @ B_hedge.T + eps_t                            # T×K 高维噪声工具
y = (F @ B_target.T + eps_y).ravel()                 # 被套保资产
python

注意:单个工具和被套保资产的真实相关只来自那 3 个因子,但 X 的 200 列里绝大多数列是纯噪声。这正是对冲实务里常见的高维困境——候选工具一大堆,真正有用的没几个。

三、结果:OLS 过拟合塌方,PCA 保住样本外#

方法残余方差对冲率样本内 R²样本外 R²过拟合差
OLS 全工具0.0000100.0%*1.0000−322.8+323.8
PCA 前 59 主成分0.024099.0%0.99710.9737+0.023

*OLS 的『100% 对冲』是假的:残余方差被噪声拟合压到 0,但样本外 R²=−322 说明它完全学到了训练集的随机扰动。

这张对比图直观到不需要多解释:OLS 样本内 R² 顶到 1.0,样本外直接掉到负几百;PCA 两个 R² 几乎贴在一起,说明它没在记忆噪声

样本内 vs 样本外 R²:高维下 OLS 过拟合塌方,PCA 降维保住样本外

残余方差随主成分个数 p 的变化也佐证了这一点:随着 p 增加,残余方差在 p 越过真实因子数(3 附近)后几乎不再下降,说明信号已经被前几个主成分吃完了,再加主成分只是把噪声搬进来。

四、关键的诚实提醒#

# 样本内 / 样本外切分验证
split = T // 2
X_tr, X_te = X[:split], X[split:]
y_tr, y_te = y[:split], y[split:]
U_tr, S_tr, Vt_tr = np.linalg.svd(X_tr - X_tr.mean(0), full_matrices=False)
# OLS 在训练集上拟合,直接扔测试集
b_tr = np.linalg.solve(X_tr.T @ X_tr, X_tr.T @ y_tr)
r2_ols_oos = 1 - np.var(y_te - X_te @ b_tr) / np.var(y_te)
# PCA:用训练集载荷投影测试集
pc_tr = U_tr[:, :p] * S_tr[:p]
P_tr  = np.linalg.solve(pc_tr.T @ pc_tr, pc_tr.T @ y_tr)
pc_te = (X_te - X_tr.mean(0)) @ Vt_tr[:p].T
r2_pca_oos = 1 - np.var(y_te - pc_te @ P_tr) / np.var(y_te)
python

对冲滤掉大部分波动;OLS 残余在小样本上反而更抖

五、三个真实陷阱(高阶)#

  • p 选多少? 本文用『累计解释方差 95%』自动定 p(本例取到 59,因噪声列也贡献了一点方差)。更稳的做法是 cross-validation 直接选使 OOS 残余方差最小的 p,而不是看解释方差——解释方差高不等于对冲好。
  • PCA 不是万能银弹。 如果真实因子是『稀疏的少数工具』而非『弥散在所有工具里的共同模式』,PCA 会把它冲淡。此时该用稀疏 PCA 或直接做变量选择(如 Lasso 选对冲工具)。PCA 假设信息是『低秩、弥散』的,这个前提要验。
  • 它只管『方差』不管『方向』。 最小方差对冲的目标是残余方差最小,但残差的均值(基差风险)可能非零。如果 yX 之间有稳定但非对称的暴露,单纯压方差会留下系统性偏移。实务里常再加一个『残余均值中性』约束。

六、小结#

最小方差对冲的 OLS 解在高维噪声环境下会『假装 100% 对冲』——样本内 R²=1.0、样本外 R²=−322 就是铁证。PCA 降维对冲用一行 SVD 把噪声主成分扔掉,残余方差回到诚实的 99%、样本外 R² 稳在 0.97。它不改变对冲的本质,只是先提纯工具、再回归,代价几乎为零,收益是躲开了一场过拟合塌方。完整可复现代码见文末生成脚本。

主成分套期保值:用少数公因子把组合暴露降到最低方差对冲
https://blog.halo26812.eu.org/blog/pca-minimum-variance-hedge
Author halo
Published at 2026年8月30日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨