风险度量基础:波动率、VaR、CVaR、最大回撤、跟踪误差

做量化对冲,说白了就是跟风险打交道。你赚的每一分钱,本质上都是对风险的补偿。我见过太多人,策略回测曲线漂亮得不行,一上实盘就崩了。为什么?因为他对风险的理解太肤浅了。

今天咱们就把风险度量这件事彻底聊透。我个人习惯把风险度量分成两类:一类是波动性度量,告诉你资产有多「颠」;另一类是尾部风险度量,告诉你最坏情况下会亏多少。这两类缺一不可。

核心观点: 没有统一的风险度量标准,任何组合管理都是空中楼阁。
风险度量体系 波动性度量 波动率 最大回撤 跟踪误差 尾部风险度量 VaR CVaR 条件VaR 风险预算模型的核心输入

1. 波动率:最基础的风险刻度

波动率就是收益率的标准差。你想想看,如果一个资产每天涨跌幅度很大,那它的波动率自然就高。我习惯用年化波动率来比较不同资产——把日波动率乘以根号252,就得到年化值。

但这里有个坑。我记得刚入行时,直接用历史波动率做风险预算,结果市场一换挡,模型全废了。为什么?因为历史波动率是向后看的,而市场是向前走的。

我的经验: 做风险预算时,我建议用「衰减加权波动率」——给近期的数据更高的权重。比如用lambda=0.94的EWMA模型,这是RiskMetrics的标准做法。
import numpy as np

def ewma_volatility(returns, lambda_=0.94):
    """指数加权移动平均波动率"""
    weights = np.array([(1-lambda_) * lambda_**i for i in range(len(returns))])
    weights = weights[::-1]  # 最近的数据权重最高
    weights /= weights.sum()
    
    mean = np.average(returns, weights=weights)
    variance = np.average((returns - mean)**2, weights=weights)
    return np.sqrt(variance * 252)  # 年化

# 示例
daily_returns = np.random.randn(500) * 0.01
vol = ewma_volatility(daily_returns)
print(f"EWMA年化波动率: {vol:.2%}")

2. VaR:在险价值,一个让人又爱又恨的指标

VaR回答的问题是:「在95%的置信水平下,我一天最多亏多少钱?」说白了,就是找收益率分布的第5百分位数。

但VaR有个致命缺陷——它只告诉你「最多亏到这儿」,却不告诉你「亏到这儿之后会怎样」。我在2015年股灾时就吃过这个亏。当时组合的95% VaR显示日亏损不超过3%,结果有一天直接亏了8%。为什么?因为VaR根本不关心尾部那5%的分布形状。

注意: VaR不满足次可加性(sub-additivity),这意味着用VaR做风险加总会低估整体风险。这在组合层面是致命的。

计算VaR有三种常用方法:

  • 参数法: 假设收益率服从正态分布,直接用均值和标准差算。快,但不准——金融数据哪有正态的?
  • 历史模拟法: 直接用过去N天的收益率排序,取第5百分位。简单粗暴,但假设历史会重演。
  • 蒙特卡洛模拟: 假设一个随机过程,模拟出成千上万条路径。最灵活,也最慢。
def historical_var(returns, confidence=0.95):
    """历史模拟法计算VaR"""
    sorted_returns = np.sort(returns)
    index = int((1 - confidence) * len(sorted_returns))
    return sorted_returns[index]

def parametric_var(returns, confidence=0.95, horizon=1):
    """参数法计算VaR(正态假设)"""
    from scipy.stats import norm
    mu = returns.mean() * horizon
    sigma = returns.std() * np.sqrt(horizon)
    z = norm.ppf(1 - confidence)
    return mu + z * sigma

# 对比两种方法
np.random.seed(42)
data = np.random.randn(1000) * 0.02
print(f"历史VaR(95%): {historical_var(data):.2%}")
print(f"参数VaR(95%): {parametric_var(data):.2%}")

3. CVaR:比VaR更诚实的尾部风险度量

CVaR,也叫期望损失(Expected Shortfall)。它计算的是「当亏损超过VaR时,平均会亏多少」。说白了,就是看尾部那5%的「平均深度」。

我个人更偏爱CVaR。为什么?因为它满足次可加性,而且对尾部风险更敏感。在风险预算模型中,用CVaR做约束条件,组合会更稳健。

关键区别: VaR是「门槛」,CVaR是「门槛后面的深渊有多深」。做对冲基金,我建议你盯紧CVaR。
def historical_cvar(returns, confidence=0.95):
    """历史模拟法计算CVaR"""
    sorted_returns = np.sort(returns)
    index = int((1 - confidence) * len(sorted_returns))
    tail_returns = sorted_returns[:index]
    return tail_returns.mean()

# 对比VaR和CVaR
var_95 = historical_var(data, 0.95)
cvar_95 = historical_cvar(data, 0.95)
print(f"VaR(95%): {var_95:.2%}")
print(f"CVaR(95%): {cvar_95:.2%}")  # CVaR通常比VaR更负

4. 最大回撤:投资者心理的底线

最大回撤(Max Drawdown)衡量的是从历史高点跌到最低点的幅度。这玩意儿跟投资者的心理承受能力直接挂钩。我记得有个客户,策略年化收益30%,但最大回撤15%,他晚上就睡不着觉了。

做风险预算时,我通常会把最大回撤作为一个硬约束。比如:「组合的最大回撤不能超过10%」。然后通过调整资产权重,让回撤控制在这个范围内。

def max_drawdown(equity_curve):
    """计算最大回撤"""
    peak = np.maximum.accumulate(equity_curve)
    drawdown = (equity_curve - peak) / peak
    return drawdown.min()

# 模拟一条净值曲线
np.random.seed(42)
returns = np.random.randn(500) * 0.01 + 0.0005
equity = 100 * np.exp(np.cumsum(returns))
mdd = max_drawdown(equity)
print(f"最大回撤: {mdd:.2%}")

5. 跟踪误差:对冲基金的「紧箍咒」

跟踪误差(Tracking Error)是组合收益率与基准收益率之差的标准差。说白了,就是你的组合跟基准「走偏」了多少。

做对冲基金,跟踪误差是个双刃剑。太小了,说明你只是个指数基金;太大了,说明你偏离基准太远,可能是在赌博。我一般把跟踪误差控制在2%-5%之间,具体看策略类型。

实战技巧: 用跟踪误差做风险预算时,我习惯把它分解到每个资产上。比如:「股票部分的跟踪误差贡献不能超过60%」。这样能清晰地看到风险来源。
def tracking_error(portfolio_returns, benchmark_returns):
    """计算跟踪误差"""
    diff = portfolio_returns - benchmark_returns
    return np.std(diff, ddof=1) * np.sqrt(252)

# 示例
port_ret = np.random.randn(252) * 0.012
bench_ret = np.random.randn(252) * 0.01
te = tracking_error(port_ret, bench_ret)
print(f"年化跟踪误差: {te:.2%}")

把这些指标串起来:风险预算的输入

好了,现在我们有五个风险度量指标。在风险预算模型中,它们各自扮演什么角色?

指标 在风险预算中的角色 我的使用频率
波动率 基础风险分配单位 ⭐⭐⭐⭐⭐
VaR 日常风险限额 ⭐⭐⭐
CVaR 尾部风险约束 ⭐⭐⭐⭐
最大回撤 硬性止损线 ⭐⭐⭐⭐⭐
跟踪误差 偏离基准的容忍度 ⭐⭐⭐⭐

我个人习惯的做法是:先用波动率做初步的风险预算分配,然后用CVaR和最大回撤做尾部风险校验,最后用跟踪误差约束整体偏离度。这样一套组合拳下来,组合的风险特征就比较清晰了。

避坑指南: 我曾经犯过一个错误——只用波动率做风险预算,结果市场暴跌时,波动率飙升,模型反而要求加仓(因为波动率高了,风险预算被稀释了)。后来我加入了CVaR约束,才解决了这个问题。记住:波动率是「常态」下的风险,CVaR是「极端」下的风险,两者缺一不可。

嗯,风险度量这块就聊到这儿。这些指标是后续所有风险预算模型的基础。你想想看,如果连风险都量不准,那还谈什么管理?

专注资料整理