2、极端风险度量:VaR的局限性与缺陷、CVaR(条件风险价值)的计算、压力测试场景设计、最大回撤与Calmar比率
2.1 VaR的局限性与缺陷:为什么它靠不住?
说到风险度量,很多人第一反应就是VaR(Value at Risk)。我刚开始做量化那会儿,也把VaR当宝贝。直到2015年股灾,我亲眼看着一个用VaR做风控的基金,一天之内亏掉了过去半年的利润。
VaR到底在算什么?说白了就是:在95%或99%的置信水平下,你的最大可能亏损是多少。比如日VaR(95%)=100万,意思是有95%的概率,你一天最多亏100万。
但问题来了——剩下的5%呢?VaR完全不告诉你。这就像天气预报说“明天有95%的概率不下雨”,结果那5%的概率来了场洪水。你想想看,这能叫风险度量吗?
VaR的三大硬伤:
- 尾部风险失明:只关心分位数,不关心分位数以外的损失有多大。两个组合的VaR可能一样,但一个极端亏损是200万,另一个是2000万。
- 不满足次可加性:理论上,分散化应该降低风险。但VaR不保证这一点。我见过一个案例,把两个资产分开算VaR是100万,合在一起算反而变成120万——这明显不合理。
- 对分布假设敏感:用正态分布算VaR,和用t分布算,结果能差好几倍。现实中金融数据哪有那么乖?
我的经验:VaR可以作为参考,但千万别把它当风控的唯一标准。我曾经在回测中加了一个条件:如果VaR超过某个阈值就减仓,结果遇到极端行情时,VaR还没触发,仓位已经亏没了。
2.2 CVaR(条件风险价值):把尾部风险算清楚
CVaR,也叫Expected Shortfall(ES),它解决了VaR的核心问题。CVaR问的是:当亏损超过VaR阈值时,平均会亏多少?
举个例子:假设你有100个交易日的收益数据,VaR(95%)排在第5差的亏损。CVaR(95%)就是取最差的5个亏损,算它们的平均值。这样,尾部风险就被量化了。
# 计算CVaR的简单实现
import numpy as np
def calculate_cvar(returns, confidence_level=0.95):
"""
计算CVaR(条件风险价值)
returns: 收益率序列
confidence_level: 置信水平,默认95%
"""
# 排序收益率
sorted_returns = np.sort(returns)
# 找到VaR的分位点
var_index = int(len(sorted_returns) * (1 - confidence_level))
var = -sorted_returns[var_index]
# CVaR是尾部损失的均值
tail_losses = -sorted_returns[:var_index]
cvar = np.mean(tail_losses)
return var, cvar
# 模拟数据
np.random.seed(42)
returns = np.random.normal(0.001, 0.02, 1000)
var_95, cvar_95 = calculate_cvar(returns, 0.95)
print(f"VaR(95%): {var_95:.4f}")
print(f"CVaR(95%): {cvar_95:.4f}")
你看,CVaR天然满足次可加性。分散化投资,CVaR一定会降低。这在数学上保证了“不要把鸡蛋放在一个篮子里”这个朴素道理。
注意:CVaR也不是万能的。它对数据质量要求更高,如果样本量不够,尾部估计会很不稳定。我建议至少用500个以上的数据点来计算CVaR。
2.3 压力测试场景设计:模拟最坏的情况
CVaR和VaR都是基于历史数据的统计方法。但黑天鹅事件之所以叫黑天鹅,就是因为历史数据里没有。这时候,压力测试就派上用场了。
压力测试的核心思路是:假设一些极端但可能发生的情景,看看你的组合会怎样。我个人习惯把压力测试分为三类:
| 类型 | 描述 | 例子 |
|---|---|---|
| 历史重现 | 复制过去发生过的极端事件 | 2008年金融危机、2020年疫情 |
| 假设情景 | 基于逻辑推演的极端情况 | 利率突然上升500bp、原油暴跌50% |
| 因子冲击 | 对关键风险因子施加极端变动 | 波动率飙升、相关性突变 |
我曾经在2018年设计过一个压力测试:假设中美贸易摩擦全面升级,A股单日暴跌8%。当时很多人觉得这不可能。结果2019年5月6日,上证指数真的跌了5.58%。虽然没到8%,但那个压力测试帮我们提前减了仓。
设计压力测试的几个要点:
- 相关性会失效:正常行情下不相关的资产,危机时可能一起跌。2008年就是典型,几乎所有资产都在跌,除了现金。
- 流动性会枯竭:压力测试里一定要考虑“卖不出去”的情况。我见过一个组合,理论上能扛住20%的下跌,但实际因为流动性问题,只跌了5%就爆仓了。
- 反馈效应:你的减仓行为本身会加剧市场下跌。这个在压力测试里很难量化,但必须意识到。
2.4 最大回撤与Calmar比率:衡量你的“抗揍能力”
最大回撤(Maximum Drawdown, MDD)是我最看重的风险指标之一。它衡量的是:从历史最高点跌到最低点,你最多亏了多少。
举个例子:你的账户净值从100万涨到200万,然后跌到120万,再涨到150万。最大回撤就是(200-120)/200=40%。注意,不是从100万算起,而是从最高点算起。
# 计算最大回撤
def max_drawdown(equity_curve):
"""
计算最大回撤
equity_curve: 净值序列
"""
# 计算历史最高点
running_max = np.maximum.accumulate(equity_curve)
# 计算回撤
drawdown = (equity_curve - running_max) / running_max
# 最大回撤
mdd = np.min(drawdown)
return mdd
# 模拟净值曲线
np.random.seed(42)
returns = np.random.normal(0.001, 0.02, 500)
equity = 100 * np.cumprod(1 + returns)
mdd = max_drawdown(equity)
print(f"最大回撤: {mdd*100:.2f}%")
Calmar比率就是把最大回撤和收益结合起来:
Calmar比率 = 年化收益率 / 最大回撤(绝对值)
这个比率越高越好。比如年化收益20%,最大回撤10%,Calmar就是2。我个人觉得,Calmar比率大于2的量化策略,才算得上“稳健”。
避坑指南:我曾经犯过一个错误——只看最大回撤的数值,没看回撤持续的时间。一个策略最大回撤20%,但3个月就回来了,和另一个同样回撤20%但3年才回来的,风险完全不一样。所以我现在还会看“回撤恢复期”这个指标。
2.5 知识体系总览
下面这张图把本章的核心逻辑串起来了。你可以看到,从VaR到CVaR,再到压力测试和最大回撤,其实是一条从“统计风险”到“极端风险”的递进路径。
嗯,这张图把四个核心概念串起来了。你可以看到,VaR是基础,但不够用;CVaR补上了尾部风险;压力测试应对未知的黑天鹅;最大回撤和Calmar则是从实战角度衡量你的“抗揍能力”。
我个人建议,在实际的风控体系中,这四个指标要一起用。别指望单一指标能解决所有问题。就像开车,你不能只看速度表,还得看油表、水温表,对吧?