halo 的技术博客

返回

先说结论:波动率平价把风险等同于标准差,而标准差是个近视眼——它看得见日常的颠簸,看不见那条平时藏起来、崩盘时吞掉你半个组合的肥尾。传统风险平价(risk parity)让每个资产对组合波动的贡献相等,逻辑优雅。但它有个致命盲点:对那些「平时收租、偶尔爆仓」的资产(卖期权、carry 交易、短久期高收益信用),标准差系统性低估其真实风险,于是波动率平价反而给它们最高权重。尾部风险平价(Tail Risk Parity)用 CVaR(条件在险价值)替代标准差,把「谁在崩盘时贡献最大」拉平。本文用纯 numpy 完整实现,并用一个精心设计的陷阱资产把差距演给你看。

一、波动率平价的盲点:低波动 ≠ 低风险#

风险平价的思想很干净:不要让任何单一资产主导组合风险。等权组合的问题是,股票波动是债券的三倍,60/40 组合里 90% 的风险其实都来自股票——「资产等权」不等于「风险等权」。波动率平价的解法是按风险反比配权,让每个资产贡献相同的组合波动。

但「风险 = 波动率」这个等式,藏着一个巨大的假设:收益分布是对称的、薄尾的(理想情况是正态)。对股票、债券这类资产,标准差还算能代表风险。可金融市场里有一类资产专门违反这个假设:

  • 卖期权 / 短波动策略:平时稳定收取权利金,波动极低;但市场一崩,亏损是断崖式的
  • carry 交易:高息货币平时慢慢升值收息,风险事件一来汇率瞬间崩塌
  • 短久期高收益信用:违约前一直付息、价格平稳,违约时本金蒸发

这些资产的共同特征是负偏度 + 高峰度:日常波动率(标准差)很低,但左尾极肥。用标准差衡量,它们看起来是「低风险高收益」的圣杯;实际上它们是把风险从「日常波动」挪到了「尾部」,标准差这个近视眼根本看不见。

我们造一组资产,故意埋进这样一个陷阱:

四资产收益分布

关键数字:短波动信用的年化波动率只有 16.8%(和股票相当,但其中大部分来自罕见崩盘,日常波动极低),偏度 -10.2、超峰度 113——这是一条灾难性的肥左尾。而股票的偏度只有 -0.11、超峰度 0.5,接近正态。

二、CVaR:不只问「会亏多少」,而是「崩了之后平均亏多少」#

要看见尾部,得换一把尺子。VaR(Value at Risk,在险价值)是第一直觉:5% VaR 就是「95% 的日子里亏损不超过这个数」。但 VaR 有两个众所周知的毛病:它只告诉你尾部的门槛,不告诉你门槛之外有多惨;而且它不满足次可加性(两个资产合并后 VaR 可能大于各自之和),这让它无法用于风险分解。

CVaR(Conditional VaR,又叫 Expected Shortfall)修好了这两点。5% CVaR 是「最坏 5% 的日子里,平均亏多少」:

CVaRα=E[rrVaRα]\text{CVaR}_\alpha = -\mathbb{E}[\,r \mid r \le \text{VaR}_\alpha\,]

def cvar(x, alpha=0.05):
    var = np.quantile(x, alpha)
    tail = x[x <= var]
    return -tail.mean()
python

用这两把尺子分别量四个资产,排序就变了:

波动率 vs CVaR 排序

资产年化波动率日 CVaR(5%)
股票16.2%2.15%
债券6.0%0.78%
商品19.9%2.55%
短波动信用16.8%2.33%

用日常眼光(如果只看未含崩盘的平静期波动),短波动信用像是低风险资产。但 CVaR 把它的真面目揭出来了:它的尾部风险(2.33%)逼近股票、远超债券。CVaR 之所以能做到,是因为它满足次可加性——这是 Artzner 等人「一致性风险度量」四公理之一,也是它能替代标准差做风险分解的数学前提。VaR 不满足这条,所以下面的风险贡献分解只能建立在 CVaR 上。

三、CVaR 风险贡献:谁在崩盘时真正主导组合#

风险平价的核心是「风险贡献」的概念。对波动率,各资产的边际贡献能用协方差算出来。对 CVaR,我们用 Euler 分配(Euler allocation):由于 CVaR 是权重的一阶齐次函数,它可以被精确拆分成各资产的贡献之和,且第 ii 个资产的 CVaR 贡献是:

RCi=wi(E[rirpVaRα(rp)])\text{RC}_i = w_i \cdot \left(-\,\mathbb{E}[\,r_i \mid r_p \le \text{VaR}_\alpha(r_p)\,]\right)

直觉极其清晰:在组合整体落入最坏 5% 的那些日子里,资产 ii 平均亏了多少,乘以它的权重,就是它对组合尾部风险的贡献。注意条件是「组合在尾部」而非「资产自己在尾部」——这抓住了「谁在组合最需要时掉链子」。

def cvar_risk_contrib(w, R, alpha=0.05):
    pr = R @ w
    var = np.quantile(pr, alpha)
    tail_mask = pr <= var                    # 组合落入尾部的那些日子
    cond_mean = R[tail_mask].mean(axis=0)    # 各资产在这些日子的平均收益
    return w * (-cond_mean)                  # Euler 贡献
python

现在见证陷阱。先按波动率平价(按波动率反比配权)建组合,看看 CVaR 贡献怎么分布:

iv = 1.0 / (np.array([rets[:, i].std() for i in range(N)]) * np.sqrt(252))
w_vp = iv / iv.sum()      # 波动率平价权重
python

结果触目惊心:

资产VP 权重CVaR 贡献占比
股票18.3%25.8%
债券49.1%9.9%
商品14.9%25.1%
短波动信用17.7%39.2%

波动率平价只给了短波动信用 17.7% 的权重,它却贡献了 39.2% 的组合尾部风险。波动率平价自以为把风险摊平了,实际上把组合的命门——那条 -10.2 偏度的肥尾——悄悄堆到了最危险的资产上。这就是短波动策略在 2008、2018Vol、2020 一次次团灭的结构性原因:所有基于波动率的风控,在崩盘前都给它们开了绿灯。

四、尾部风险平价:把崩盘贡献迭代拉平到 25%#

目标明确了:不让任何资产主导组合的尾部风险。即让每个资产的 CVaR 贡献占比都等于 1/N=25%1/N = 25\%。CVaR 组合优化本可以用 Rockafellar-Uryasev 的线性规划精确求解,但为了让原理透明、代码自足,这里用一个迭代的投影梯度法——哪个资产尾部贡献超标就降它的权重,不足就升,反复迭代直到拉平:

def tail_risk_parity(R, alpha=0.05, iters=6000, lr=0.03):
    n = R.shape[1]
    w = np.ones(n) / n
    for _ in range(iters):
        rc = cvar_risk_contrib(w, R, alpha)
        target = rc.mean()               # 目标:贡献均等
        grad = rc - target               # 超标的往下调,不足的往上调
        w = w - lr * grad
        w = np.clip(w, 1e-4, None)       # 只做多
        w = w / w.sum()                  # 归一化
    return w

w_trp = tail_risk_parity(rets)
python

收敛后,CVaR 贡献被精确拉平:

CVaR 风险贡献对比

尾部风险平价把四个资产的 CVaR 贡献全部拉到 ~25%。代价体现在权重上:

配置权重对比

短波动信用的权重从波动率平价的 17.7% 被砍到 11.5%,腾出来的仓位主要加到了尾部温和的债券上。这不是尾部风险平价『保守』,而是它终于看见了波动率平价看不见的东西——短波动信用那 39.2% 的隐藏尾部贡献。

五、回测:拉平尾部贡献,换来更平的净值#

在同一段含崩盘的市场上跑三个组合(等权 / 波动率平价 / 尾部风险平价):

净值曲线对比

策略年化收益年化波动Sharpe最大回撤日 CVaR(5%)
等权0.4%8.9%0.05-22.8%1.37%
波动率平价2.1%6.4%0.34-14.6%0.96%
尾部风险平价3.3%5.9%0.57-12.2%0.83%

尾部风险平价在所有维度上都赢了波动率平价:Sharpe 从 0.34 升到 0.57,最大回撤从 -14.6% 收到 -12.2%,组合 CVaR 从 0.96% 降到 0.83%。收益还更高——因为它在崩盘日少扛了短波动信用的巨亏,净值曲线的坑更浅,复利基数保得更好

要诚实说明:这段样本里,正是因为短波动信用真的爆了几次,才让「提前减配它」显得英明。如果这段样本里它一次都没崩,波动率平价的高权重反而会赚更多——尾部风险平价买的是保险,保险在没出事时永远显得多余。它的价值不在提高平均收益,而在削掉左尾、让你活到下一轮

六、结果解读与实战边界#

这个方法的真正价值。 它把风控的焦点从「日常波动」搬到「崩盘贡献」,专治波动率类风控对肥尾资产的系统性盲区。任何组合里若含有短波动、carry、信用、卖保护这类「负偏度收租」资产,波动率平价几乎必然低配了它们的真实风险——尾部风险平价是对这个盲区的直接修正。

四个必须知道的陷阱:

  1. 尾部估计的样本量诅咒。 CVaR 只用最坏 5% 的数据点。3000 天里,5% 尾部只有 150 个点;如果你想看 1% 尾部,就只剩 30 个点。尾部越极端,可用样本越少,估计越不稳。短波动信用那条 -10.2 偏度的尾巴,可能整个样本里就靠几十次崩盘定义——换个样本期,CVaR 估计可能大幅漂移。实战中必须配合参数化尾部模型(EVT 广义帕累托分布)或更长历史来稳住尾部估计,纯经验 CVaR 在小样本上会骗你。

  2. 样本内最优必然乐观。 上面的回测是样本内的:我用同一段数据既估 CVaR 又跑回测。真实的尾部风险平价必须样本外验证——用滚动窗口估 CVaR、下一期持有,再滚动。样本内 Sharpe 0.57 里,有一部分是「我知道短波动信用会崩所以提前减配」的后视镜红利,样本外会打折。

  3. CVaR 分解依赖历史尾部会重演。 Euler 分解算的是「历史上组合落尾时谁亏得多」。但下一次崩盘的相关性结构可能和历史完全不同——2008 是信用崩、2020 是流动性崩、2022 是股债双杀。用历史尾部相关性配的权,在新型崩盘里可能失效。尾部相关性在危机中往往趋近 1(一起崩),这会让分散化承诺落空。

  4. 迭代解 vs 精确解。 本文的投影梯度法直观但不保证全局最优,且对学习率敏感。生产环境应该用 Rockafellar-Uryasev 的 CVaR 线性规划公式(把 CVaR 最小化转成可求解的 LP),既严格又快。这里用迭代法是为了让「拉平尾部贡献」这个机制看得见摸得着。

一句话总结:波动率平价问「谁平时抖得厉害」,尾部风险平价问「谁崩起来最要命」——后者才是真正会杀死你组合的问题。当你的资产篮子里有『平时收租、偶尔爆仓』的东西时,换尺子这件事,可能比调任何参数都值钱。

尾部风险平价:用 CVaR 替代波动率,把每个资产的『崩盘贡献』拉平
https://blog.halo26812.eu.org/blog/tail-risk-parity-cvar
Author halo
Published at 2026年7月25日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨