为什么VaR不够用?#
VaR(Value at Risk)告诉我们”在95%置信度下,最大损失不超过X”。但它有两个致命缺陷:
- 不衡量尾部风险:VaR只给出临界点,不告诉你超过VaR后的损失有多大
- 非次可加性:违反风险度量的数学公理,导致分散化反而显示风险增加
CVaR(Conditional Value at Risk,条件风险价值)解决了这些问题。

CVaR的数学定义#
CVaR是损失超过VaR的那些极端值的条件期望:
其中:
- 是投资组合损失
- 是置信水平(通常取95%或99%)
- 是对应置信度的在险价值
Python实现CVaR计算#
方法1:历史模拟法#
import numpy as np
import pandas as pd
def calculate_cvar(returns, confidence=0.95):
"""
计算CVaR(条件风险价值)
Parameters:
-----------
returns : array-like
资产收益率序列(正值表示盈利,负值表示亏损)
confidence : float
置信水平,默认0.95
Returns:
--------
cvar : float
CVaR值(正数表示损失)
var : float
VaR值
"""
# 转换为损失(负号表示损失)
losses = -np.array(returns)
# 计算VaR
var = np.percentile(losses, confidence * 100)
# 计算CVaR:超过VaR的损失的条件期望
cvar = losses[losses > var].mean()
return cvar, var
# 示例
np.random.seed(42)
returns = np.random.normal(0.0005, 0.02, 1000) # 日收益率
cvar, var = calculate_cvar(returns, confidence=0.95)
print(f"VaR(95%): {var:.4f}")
print(f"CVaR(95%): {cvar:.4f}")python方法2:蒙特卡洛模拟(更精确)#
from scipy.stats import norm
def monte_carlo_cvar(mu, sigma, confidence=0.95, n_simulations=100000):
"""
用蒙特卡洛模拟计算CVaR(假设正态分布)
"""
# 生成模拟收益
simulated_returns = np.random.normal(mu, sigma, n_simulations)
losses = -simulated_returns
# 计算VaR
var = np.percentile(losses, confidence * 100)
# 计算CVaR
cvar = losses[losses > var].mean()
# 解析解(正态分布假设下)
# CVaR = μ + σ * φ(Φ^{-1}(α)) / (1-α)
from scipy.stats import norm
z_alpha = norm.ppf(confidence)
cvar_analytical = -mu + sigma * norm.pdf(z_alpha) / (1 - confidence)
return cvar, var, cvar_analytical
# 示例:日收益率均值0.05%,波动率2%
cvar_mc, var_mc, cvar_analytic = monte_carlo_cvar(0.0005, 0.02)
print(f"Monte Carlo CVaR: {cvar_mc:.4f}")
print(f"Analytical CVaR: {cvar_analytic:.4f}")pythonCVaR在投资组合优化中的应用#
传统均值-方差优化的问题#
Markowitz的均值-方差优化只关注波动率(方差),忽略了尾部风险。在金融危机期间,这种优化会导致:
- 过度集中在某些”低波动”资产
- 对尾部事件毫无准备
CVaR投资组合优化#
将目标函数从最小化方差改为最小化CVaR:
from scipy.optimize import minimize
def cvar_portfolio_optimization(returns_df, confidence=0.95, target_return=None):
"""
CVaR投资组合优化
Parameters:
-----------
returns_df : DataFrame
各资产的收益率矩阵
confidence : float
CVaR置信水平
target_return : float
目标收益率(可选)
Returns:
--------
weights : array
最优权重
"""
n_assets = returns_df.shape[1]
def portfolio_cvar(weights):
"""计算投资组合的CVaR"""
portfolio_returns = returns_df.dot(weights)
cvar, _ = calculate_cvar(portfolio_returns, confidence)
return cvar
# 约束条件:权重和为1
constraints = [{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}]
if target_return is not None:
# 添加目标收益约束
def return_constraint(w):
return returns_df.dot(w).mean() - target_return
constraints.append({'type': 'eq', 'fun': return_constraint})
# 边界:不允许做空(可选)
bounds = tuple((0, 1) for _ in range(n_assets))
# 初始权重:等权
initial_weights = np.array([1/n_assets] * n_assets)
# 优化
result = minimize(
portfolio_cvar,
initial_weights,
method='SLSQP',
bounds=bounds,
constraints=constraints
)
return result.x
# 示例
returns_df = pd.DataFrame({
'Stock_A': np.random.normal(0.001, 0.02, 1000),
'Stock_B': np.random.normal(0.0008, 0.015, 1000),
'Stock_C': np.random.normal(0.0012, 0.025, 1000)
})
optimal_weights = cvar_portfolio_optimization(returns_df, confidence=0.95)
print("Optimal Weights:", optimal_weights)pythonCVaR vs VaR:实战对比#
| 特性 | VaR | CVaR |
|---|---|---|
| 尾部风险 | 不衡量 | 衡量 |
| 次可加性 | 不满足 | 满足 |
| 优化性质 | 非凸,难优化 | 凸,易优化 |
| 计算复杂度 | 低 | 中等 |
| 监管接受度 | 高(Basel III) | 中等 |
回测框架中的CVaR应用#
在回测中,可以用滚动窗口计算CVaR,监控策略的尾部风险:
def rolling_cvar(returns, window=252, confidence=0.95):
"""计算滚动CVaR"""
cvar_series = []
dates = []
for i in range(window, len(returns)):
roll_returns = returns[i-window:i]
cvar, var = calculate_cvar(roll_returns, confidence)
cvar_series.append(cvar)
dates.append(returns.index[i])
return pd.Series(cvar_series, index=dates)
# 示例:计算策略的滚动CVaR
strategy_returns = pd.Series(...) # 你的策略收益率
rolling_cvar_series = rolling_cvar(strategy_returns, window=252)python总结#
CVaR是比VaR更优秀的风险度量工具,尤其适合:
- 尾部风险管理:捕捉极端损失
- 投资组合优化:凸优化问题,数值稳定
- 压力测试:结合情景分析,评估极端市场条件下的风险
实战建议:在风险管理框架中,同时报告VaR和CVaR。VaR用于监管合规,CVaR用于内部风险决策。
延伸阅读#
- Rockafellar & Uryasev (2000):CVaR优化的奠基论文
- Basel Committee (2019):对交易账户市场风险的最新规定(FRTB)
- Acerbi & Tasche (2002):CVaR的数学性质证明