halo 的技术博客

返回

均值方差(MV)组合有个公开的秘密:它的崩坏几乎从来不是协方差估计不准,而是预期收益估计不准。你辛辛苦苦估出 Σ,然后把样本均值 μ̂ 直接喂进 w=Σ1μw = \Sigma^{-1}\mu,Σ⁻¹ 就像放大器,把任何一个被噪声放大的均值抖成几十倍的极端权重。一个常被引用的数字:哪怕你 Σ 估得完美,只要 μ̂ 里混了 5% 的估计噪声,MV 的样本外表现就可能不如闭着眼睛等权。本文用 numpy 从零实现层次先验(random-effects)贝叶斯收缩,把每个资产的预期收益往「所有资产的共同先验均值」上拉一拉,权重立刻从 ±4.6 回到 ±1.1,而样本外收益几乎不丢。

一、合成数据:有真实 α,但带噪声#

50 个资产、200 天训练、400 天测试。真实日收益均值 mu_true 有横截面离散(标准差 0.004),收益由 3 个共同因子加个股噪声生成——这样 Σ 是良态的,MV 不会被病态协方差本身搞崩,崩坏只来自均值估计。

import numpy as np
rng = np.random.default_rng(20260829)
N, T_in, T_total = 50, 200, 600
mu_true = rng.normal(0.0008, 0.004, N)          # 真实日均值(有横截面离散)
L = rng.normal(0.012, 0.006, (N, 3))            # 3 个共同因子载荷
f = rng.normal(0, 1, (T_total, 3))
R = mu_true + f @ L.T + 0.02*rng.normal(0, 1, (T_total, N))
Rin, Roos = R[:T_in], R[T_in:]
python

原始 MV / 贝叶斯收缩 / 等权 三种组合权重对比

左红是原始 MV 权重——几个资产被推到 ±4.6,意味着你要拿 4.6 倍仓位去赌一个带噪声的均值差;右蓝是收缩后的权重,全部压在 ±1.1 以内,和等权(灰)一样「人模人样」。这还不是审美问题:±4.6 的权重在实盘会被交易成本和冲击成本亲手打爆,而 ±1.1 才接近可成交。机理很简单:Σ1\Sigma^{-1} 的逆在资产高度相关时会把某个方向的杠杆放大几十倍,而 μ^\hat\mu 里哪怕只有一个资产被抽样噪声抬高 0.005,乘上这个杠杆就变成 4.6 倍权重——MV 的组合优化器对此毫无抵抗力,它只会忠实地「最大化」一个被噪声污染的目标。

二、层次先验:把均值往共同先验上拉#

核心假设是层次模型:每个资产的真实均值 μiN(μg,τ2)\mu_i \sim \mathcal{N}(\mu_g, \tau^2),即所有资产共享一个「全局先验均值」μg\mu_g,彼此只在 τ2\tau^2(资产间方差)上离散。于是 μi\mu_i 的后验均值是样本均值和全局先验的加权平均:

μ~i=wiμ^i+(1wi)μg,wi=τ2τ2+si2\tilde\mu_i = w_i\,\hat\mu_i + (1-w_i)\,\mu_g,\qquad w_i = \frac{\tau^2}{\tau^2 + s_i^2}

其中 si2s_i^2μ^i\hat\mu_i 的估计方差(= 资产收益方差 / 样本数)。wiw_i 就是「保留多少原始样本均值」——噪声越大(si2s_i^2 大)保留越少,资产间差异越明显(τ2\tau^2 大)保留越多。μg\mu_gτ2\tau^2 用矩估计(经验贝叶斯):

mu_hat = Rin.mean(0)
s2 = Rin.var(0) / T_in                       # 每个均值估计的方差
mu_g = np.sum(mu_hat/s2) / np.sum(1/s2)       # 逆方差加权全局先验均值
B = np.var(mu_hat)
tau2 = max(0.0, B - s2.mean())                # 资产间方差(矩估计)
w_i = tau2 / (tau2 + s2)                       # 保留比例
mu_tilde = w_i * mu_hat + (1 - w_i) * mu_g     # 收缩后的均值
python

样本均值 vs 收缩均值 vs 真实均值

绿点是真实均值,红点是噪声很大的样本均值(几个被甩到 ±0.01 以外),蓝点是收缩后均值——它们被明显往灰色虚线(全局先验 μg=0.0024\mu_g=0.0024)拉回。本例平均收缩强度 δˉ=0.35\bar\delta = 0.35,即平均把 35% 的「离群样本均值」抹平。诚实提醒:收缩强度完全由数据决定,不是拍脑袋——τ2\tau^2 估出来是 8.0×1068.0\times10^{-6},只比估计噪声 si2s_i^2 略大,所以收缩是温和的部分收缩,不是一刀切。

三、收缩到底省了多少估计误差#

合成数据里 mu_true 是已知的,直接比 MSE。层次收缩把均值估计 MSE 从 3.07×1063.07\times10^{-6} 降到 2.70×1062.70\times10^{-6}(省约 12%)。这正是不等式结论:只要真实均值确实共享一个共同先验(即 τ2\tau^2 有限),收缩估计在 MSE 上必然优于 MLE,多资产下几乎恒成立。

mse_raw   = np.mean((mu_hat   - mu_true)**2)   # 3.07e-6
mse_bayes = np.mean((mu_tilde - mu_true)**2)   # 2.70e-6
python

均值估计更准,喂进 Σ⁻¹ 的向量就更干净,极端权重自然消失——这是图一里 ±4.6→±1.1 的同一个故事的另一面。顺带一提,这 12% 不是本例专属:只要资产数 N3N\ge 3,James-Stein / 层次收缩在 MSE 上几乎必然压过 MLE,这是统计学里少有的「免费午餐」之一。

四、样本外:收缩保住了 MV 的红利#

协方差用同一个对角收缩估计(ρ=min(1,N/Tin)=0.25\rho=\min(1, N/T_{in})=0.25,只为 Σ⁻¹ 数值稳),唯一差别是均值用 μ̂ 还是 μ̃,公平对比。

样本外累计收益:原始 MV / 收缩 MV / 等权

组合样本外 Sharpe最大绝对权重
原始 MV(μ̂)16.104.63
贝叶斯收缩(μ̃)16.301.12
等权 1/N3.760.02

收缩组合的 OOS Sharpe(16.30)和原始 MV(16.10)基本贴平,却把最大权重从 4.63 砍到 1.12——同样的收益,不到一半的头寸波动。等权只有 3.76,因为本例 α 足够强,纯分散放弃了信号。需要泼盆冷水:16 这个 Sharpe 是合成数据刻意给足 α 的结果,真实市场会被打到 1–3;本文的重点不是「收缩让 Sharpe 翻倍」,而是「在协方差良态时,收缩几乎零成本地把不可成交的极端权重变成可成交的适中权重」。

五、收缩强度随样本退化:样本越多越不信先验#

把训练样本从 30 天扫到 190 天,看平均收缩强度 δˉ\bar\delta

收缩强度与 MSE 节省随样本 T 变化

δˉ\bar\delta 从 0.94(30 天,几乎全信先验)单调降到 0.38(190 天,越来越信数据)——这正是层次先验该有的行为:样本越少、每个均值越吵,越该往共同先验靠;样本越多、均值越准,越该放手让数据说话。绿线是 MSE 节省量,全程为正,说明无论样本多少,收缩都比裸 MLE 更稳

一个真实市场的延伸结论:当你的估计窗口很短(因子均值只有几十天样本)、Σ 也更病态时,原始 MV 的样本外 Sharpe 会直接转负被噪声吞噬,而收缩组合因为权重被先验摁住、跌幅小得多。本文合成数据的 Σ 偏良态,所以差距没撕开;但「短窗口 + 噪声大」才是实盘常态,那时收缩的红利远大于这 12% 的 MSE。

实战里这套机制通常跑在滚动窗口上:每个调仓日用过去 TinT_{in} 天重新估 μ̂ 和 Σ,算一遍 τ² 和 w_i,收缩均值后求权重,再归一化到净多头 100%。关键是 τ² 和 w_i 每期重估——市场 regime 切换时资产间离散度变了,收缩强度会自动跟着变,不用人工调参。如果某期 τ² 估成 0(资产太少或噪声太大),宁可退化到等权也别硬上裸 MV,这是比追求那 0.x 个 Sharpe 重要得多的风控开关。

六、三个容易踩的坑(诚实版)#

  1. τ² 估成 0 就退化成「全压先验」。

    矩估计 tau2 = max(0, B - s2.mean()) 在资产数少(<20)或一次随机种子下很容易因抽样误差变负,于是 w_i=0、所有均值被压成同一个 μ_g——等于放弃全部横截面信号。资产数 ≥50、或对 τ² 加一个正的先验下界才能稳住。本文用 50 资产才拿到可靠的 8e-6。

  2. 收缩的是均值,不是协方差。 本文 Σ 也做了对角收缩(ρ=0.25),但那是另一回事;图里的「权重变乖」100% 来自均值收缩,别把功劳算错账。如果 Σ 本身病态,得单独上 Ledoit-Wolf。

  3. 收缩救不了「真没 α」。 当真实均值全部≈0(没有横截面信号),任何 MV 都该让位给等权;收缩只是让「错误地重仓」轻一点,不会凭空造出超额收益。

结语#

贝叶斯收缩解决的是 MV 组合里最现实也最被低估的故障:把带噪声的因子预期收益直接喂给 Σ⁻¹,会炸出不可成交的极端权重。层次先验用「资产间方差 vs 估计方差」这个数据驱动的比例,把每个均值往共同先验拉一拉——50 资产合成数据上平均收缩 0.35,最大权重 4.63→1.12,均值 MSE 降 12%,且样本越多收缩越弱(0.94→0.38)。它不是让 Sharpe 翻倍的魔法,而是在「协方差良态时几乎零成本地把组合从不可成交变成可成交、在协方差病态时把濒临崩盘的原始 MV 摁回水面」的那只手。真实市场里你拿到的不会是干净的合成 α,但「先估 τ²、再按比例收缩均值、最后才进 Σ⁻¹」这套流程,比对着 ±4.6 的裸 MV 权重下单要靠谱得多——它把组合优化的目标从「拟合噪声」改写成「尊重不确定性」。

贝叶斯收缩因子组合:用层次先验把极端权重拉回均值
https://blog.halo26812.eu.org/blog/bayesian-shrinkage-factor-portfolio
Author halo
Published at 2026年8月29日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨