第 6 章 · 02 CVaR 条件风险价值 本节摘要:半方差只看「低于均值」,但对真正的「黑天鹅」式尾部损失仍不够敏锐。CVaR(Conditional Value at Risk,条件风险价值,又名 Expected Shortfall)直接刻画「在最糟糕的那 (1-β) 天里平均亏多少」,是尾部风险的黄金度量。本节讲清 类:它基于 Rockafellar & Uryasev (2001) 的凸化技巧,把看似不可优化的尾部期望转成线性规划,内部引入辅助变量 α(VaR)和 u(超出),用 cvxpy 一次求解。读完本节,你能用 CVaR 替换方差做优化,并理解 beta 参数与「置信度」语义。 内容来源:原项目源码 、文档 ,汉化并套用体系化模板。
本节摘要:半方差只看「低于均值」,但对真正的「黑天鹅」式尾部损失仍不够敏锐。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,汉化并套用体系化模板。
阅读完本节,你应当能够:
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 才是主流。
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()
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_sharpe、min_volatility、max_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%
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 年更稳妥。
| 对比维度 | 半方差 Semivariance | CVaR |
|---|---|---|
| 关注点 | 低于均值的偏差 | 损失分布的尾部 |
| 是否含 VaR | 否 | 是(α 即 VaR) |
| 参数 | benchmark | beta 置信度 |
| 数学形式 | 二次规划 | 线性规划 |
| 对极端事件 | 较敏感 | 最敏感 |
| 适合场景 | 不喜欢下行但不极端 | 极端厌恶、监管约束 |
α + 1/((1-β)T)·Σu。min_cvar、efficient_risk(target_cvar)、efficient_return(target_return);父类的 max_sharpe/min_volatility/max_quadratic_utility 都不可用。(期望收益, CVaR),不再有 Sharpe。下一节,我们看 CDaR 条件回撤——把目光从「单日损失」拉长到「累计回撤」,直接对齐「最大回撤」这一投资者最直观的痛感。