第 6 章 · 02 CVaR 条件风险价值


文档摘要

第 6 章 · 02 CVaR 条件风险价值 本节摘要:半方差只看「低于均值」,但对真正的「黑天鹅」式尾部损失仍不够敏锐。CVaR(Conditional Value at Risk,条件风险价值,又名 Expected Shortfall)直接刻画「在最糟糕的那 (1-β) 天里平均亏多少」,是尾部风险的黄金度量。本节讲清 类:它基于 Rockafellar & Uryasev (2001) 的凸化技巧,把看似不可优化的尾部期望转成线性规划,内部引入辅助变量 α(VaR)和 u(超出),用 cvxpy 一次求解。读完本节,你能用 CVaR 替换方差做优化,并理解 beta 参数与「置信度」语义。 内容来源:原项目源码 、文档 ,汉化并套用体系化模板。

第 6 章 · 02 CVaR 条件风险价值

本节摘要:半方差只看「低于均值」,但对真正的「黑天鹅」式尾部损失仍不够敏锐。CVaR(Conditional Value at Risk,条件风险价值,又名 Expected Shortfall)直接刻画「在最糟糕的那 (1-β) 天里平均亏多少」,是尾部风险的黄金度量。本节讲清 EfficientCVaR 类:它基于 Rockafellar & Uryasev (2001) 的凸化技巧,把看似不可优化的尾部期望转成线性规划,内部引入辅助变量 α(VaR)和 u(超出),用 cvxpy 一次求解。读完本节,你能用 CVaR 替换方差做优化,并理解 beta 参数与「置信度」语义。

内容来源:原项目源码 pypfopt/efficient_frontier/efficient_cvar.py、文档 docs/GeneralEfficientFrontier.rst,汉化并套用体系化模板。

学习目标

阅读完本节,你应当能够:

  1. EfficientCVaR 替换方差做尾部风险优化。
  2. 说清 VaR 与 CVaR 的定义与区别。
  3. 理解 beta 置信度 与「最坏 (1-β) 天」的语义。
  4. 解释 Rockafellar-Uryasev 凸化为什么把尾部期望变成 线性规划
  5. 区分 min_cvar / efficient_risk / efficient_return 三个目标。

一、VaR 与 CVaR:尾部风险的两把尺子

VaR(Value at Risk,风险价值):在置信度 β 下,损失不会超过的阈值。例如「95% VaR = 3%」表示有 95% 的把握单日亏损不超过 3%。

CVaR(条件风险价值):在所有损失超过 VaR 的日子里,平均亏多少。例如「95% CVaR = 5%」表示「最惨的 5% 日子里平均亏 5%」。

指标 物理含义 数学性质
VaR 第 (1-β) 分位数 非凸,优化困难
CVaR 尾部损失的期望 凸函数,可优化

💡 为什么用 CVaR 而非 VaR:VaR 只看「门槛那一点」,对门槛之外的极端程度完全无视;更致命的是 VaR 非凸,无法用凸优化求解。CVaR 兼顾了「门槛后的全部损失」与「数学可解」,所以工业上 CVaR 才是主流。

二、Rockafellar-Uryasev 凸化:从积分到线性规划

CVaR 的原始定义是个积分,看着漂亮但难优化:

CVaR(w, β) = (1/(1-β)) ∫_{L≥α} L(w,r) p(r) dr

Rockafellar & Uryasev (2001) 的核心洞见是:最小化 CVaR 等价于最小化下面这个凸函数 F_β:

F_β(w, α) = α + (1/(1-β)) · E[ max(-wᵀr - α, 0) ]

其中 α 是 VaR(也作为优化变量),max(x, 0) 用辅助变量 u 表示。如果有 T 个历史样本,积分变求和,整个问题退化为线性规划:

min α + 1/((1-β)T) Σ u_i s.t. u_i ≥ 0 u_i ≥ -wᵀr_i - α

源码 min_cvar 完全照搬这个公式:

self._alpha = cp.Variable() # VaR self._u = cp.Variable(len(self.returns)) # 每天的超出量 def min_cvar(self, market_neutral=False): self._objective = self._alpha + 1.0 / ( len(self.returns) * (1 - self._beta) ) * cp.sum(self._u) self.add_constraint(lambda _: self._u >= 0.0) self.add_constraint( lambda w: self.returns.values @ w + self._alpha + self._u >= 0.0 ) self._make_weight_sum_constraint(market_neutral) return self._solve_cvxpy_opt_problem()

三、EfficientCVaR 的构造与 beta

from pypfopt import expected_returns, EfficientCVaR mu = expected_returns.mean_historical_return(df) returns = expected_returns.returns_from_prices(df) ec = EfficientCVaR( expected_returns=mu, returns=returns, beta=0.95, # 置信度,默认 95% weight_bounds=(0, 1), solver=None, verbose=False, solver_options=None, )

beta 是置信度(不是分位数),典型值 80%、90%、95%。源码里专门做了校验和提醒:

@staticmethod def _validate_beta(beta): if not (0 <= beta < 1): raise ValueError("beta must be between 0 and 1") if beta <= 0.2: warnings.warn( "Warning: beta is the confidence-level, not the quantile. " "Typical values are 80%, 90%, 95%.", UserWarning) return beta

⚠️ beta 是置信度不是分位数:写 beta=0.95 是「95% 置信度」,对应看「最惨的 5% 日子」。如果误写成 beta=0.05,你就在算「最惨的 95% 日子」,毫无意义。库主动在 beta≤0.2 时发警告。

四、三个目标方法

方法 含义 数学形式
min_cvar(market_neutral=False) 最小化 CVaR min α + (1/((1-β)T))·Σu
efficient_risk(target_cvar) 给定 CVaR 上限下最大化收益 max μᵀw, s.t. CVaR ≤ target
efficient_return(target_return) 给定收益下最小化 CVaR min CVaR, s.t. μᵀw ≥ target

注意:父类的 max_sharpemin_volatilitymax_quadratic_utility 都不可用,因为 Sharpe / 方差在 CVaR 框架下没意义。

def min_volatility(self): raise NotImplementedError("Please use min_cvar instead.") def max_sharpe(self, risk_free_rate=0.0): raise NotImplementedError("Method not available in EfficientCVaR.") def max_quadratic_utility(self, risk_aversion=1, market_neutral=False): raise NotImplementedError("Method not available in EfficientCVaR.")

portfolio_performance 返回**(期望收益, CVaR)** 二元组(没有 Sharpe,因为分母不再是方差):

mu, cvar_val = ec.portfolio_performance(verbose=True) # Expected annual return: 25.0% # Conditional Value at Risk: 1.85%

五、完整示例:最小 CVaR

from pypfopt import expected_returns, EfficientCVaR mu = expected_returns.mean_historical_return(df) returns = expected_returns.returns_from_prices(df) ec = EfficientCVaR(mu, returns, beta=0.95) ec.min_cvar() # 最小化 95% CVaR weights = ec.clean_weights() print(weights) ec.portfolio_performance(verbose=True)

如果想「给定收益目标最小化尾部风险」,换成:

ec.efficient_return(target_return=0.15) # 给定 15% 年化,最小化 CVaR

💡 历史数据要够长:CVaR 衡量的是尾部,样本太少就观测不到尾部。官方建议至少包含一次「尾部事件」(比如一次完整熊市)。3 年日线是底线,5-10 年更稳妥。

六、CVaR 与半方差的对比

对比维度 半方差 Semivariance CVaR
关注点 低于均值的偏差 损失分布的尾部
是否含 VaR 是(α 即 VaR)
参数 benchmark beta 置信度
数学形式 二次规划 线性规划
对极端事件 较敏感 最敏感
适合场景 不喜欢下行但不极端 极端厌恶、监管约束

本节要点回顾

  1. CVaR(条件风险价值) = 损失超过 VaR 的尾部期望,衡量「最惨 (1-β) 天的平均损失」;VaR 非凸不可优化,CVaR 凸可优化。
  2. Rockafellar-Uryasev 凸化 把 CVaR 优化转成线性规划:引入 α(=VaR)和辅助变量 u,目标 α + 1/((1-β)T)·Σu
  3. EfficientCVaR 构造时喂历史收益 + beta(置信度,典型 0.95);beta≤0.2 会触发警告。
  4. 方法:min_cvarefficient_risk(target_cvar)efficient_return(target_return);父类的 max_sharpe/min_volatility/max_quadratic_utility 都不可用。
  5. 输出:portfolio_performance 返回 (期望收益, CVaR),不再有 Sharpe。
  6. 样本要够:尾部风险必须观测到尾部事件,3 年日线是底线,否则 CVaR 估计本身就不可信。

下一节,我们看 CDaR 条件回撤——把目光从「单日损失」拉长到「累计回撤」,直接对齐「最大回撤」这一投资者最直观的痛感。


发布者: 作者: 灏天文库 转发
评论区 (0)
U