风险度量基础:波动率、协方差矩阵、VaR、CVaR、最大回撤、风险因子模型

各位同学,欢迎来到风险度量的世界。

说实话,做量化投资这么多年,我最大的体会就是:不懂风险,赚再多钱也是白搭。你想想看,一次黑天鹅事件,可能就把你几年的利润全吞了。所以,这一章我们得把风险度量的基本功打扎实。

1. 波动率:最朴素的“心跳”指标

波动率,说白了就是资产价格上下跳动的幅度。我习惯把它比作一个人的“心跳”——跳得太快,你紧张;跳得太慢,你又担心它是不是挂了。

在金融里,我们通常用年化波动率来衡量。计算方式很简单:

import numpy as np

# 假设我们有日收益率数据
daily_returns = np.array([0.01, -0.02, 0.015, -0.005, 0.008])
# 计算日波动率(标准差)
daily_vol = np.std(daily_returns, ddof=1)
# 年化(假设252个交易日)
annual_vol = daily_vol * np.sqrt(252)

print(f"年化波动率: {annual_vol:.4f}")
我的小经验: 我在项目中遇到过,直接用历史波动率去预测未来,结果被市场狠狠打脸。因为波动率有“聚集效应”——大涨大跌后往往跟着更大的波动。所以,我建议你至少用GARCH模型或者EWMA(指数加权移动平均)来动态估计。

2. 协方差矩阵:资产之间的“关系网”

单看一个资产的波动率还不够。你想想,如果两个资产同涨同跌,那组合的风险并没有分散。协方差矩阵就是用来描述资产之间“联动关系”的。

举个例子,假设我们有3只股票:

import numpy as np

# 假设3只股票的日收益率数据(5天)
returns = np.array([
    [0.01, 0.02, -0.01],
    [-0.02, 0.01, 0.03],
    [0.015, -0.01, 0.02],
    [-0.005, 0.005, -0.015],
    [0.008, -0.02, 0.01]
])

# 计算协方差矩阵
cov_matrix = np.cov(returns, rowvar=False)
print("协方差矩阵:")
print(cov_matrix)
关键点: 协方差矩阵的对角线是各资产的方差(波动率的平方),非对角线是资产间的协方差。如果协方差为正,说明它们倾向于同向运动;为负,则反向。

嗯,这里要注意:协方差矩阵必须是半正定的,否则在后续做优化时会出问题。我曾经因为数据缺失导致矩阵不正定,结果优化出来的权重全是负数,亏了不少钱。

3. VaR:你的钱最多会亏多少?

VaR(Value at Risk),风险价值。它回答一个问题:在给定的置信水平下,未来一段时间内,你的投资组合最多可能亏损多少?

比如,95%置信水平下的日VaR为100万,意思是:有95%的把握,明天亏损不超过100万;但还有5%的可能,亏损超过100万。

计算VaR有三种常见方法:

  • 参数法(方差-协方差法): 假设收益率服从正态分布,直接用均值和标准差算。
  • 历史模拟法: 直接用过去的历史收益率排序,取分位数。
  • 蒙特卡洛模拟法: 假设一个随机过程,模拟出大量路径,再取分位数。
import numpy as np

# 历史模拟法计算95% VaR
returns = np.random.normal(0.001, 0.02, 1000)  # 模拟1000个日收益率
confidence_level = 0.95
VaR = np.percentile(returns, (1 - confidence_level) * 100)
print(f"95% VaR: {VaR:.4f}")
避坑指南: 我曾经用参数法算VaR,结果市场出现极端行情,实际亏损远超VaR值。为什么?因为收益率根本不服从正态分布,尾部太厚了。所以,VaR不是万能的,它无法告诉你“如果亏损超过VaR,到底会亏多少”。

4. CVaR:比VaR更“诚实”的指标

CVaR(Conditional VaR),也叫期望损失。它弥补了VaR的缺陷——它计算的是超过VaR那部分损失的期望值

说白了,VaR告诉你“最坏情况的下限”,CVaR告诉你“最坏情况下的平均损失”。

# 计算95% CVaR
threshold = np.percentile(returns, (1 - confidence_level) * 100)
CVaR = returns[returns <= threshold].mean()
print(f"95% CVaR: {CVaR:.4f}")
我个人习惯: 在做风险预算时,我更喜欢用CVaR而不是VaR。因为CVaR对尾部风险更敏感,能更好地捕捉“黑天鹅”事件。你想想看,如果两个组合的VaR相同,但CVaR不同,你会选哪个?当然是CVaR更小的那个。

5. 最大回撤:投资者的“心理底线”

最大回撤(Maximum Drawdown),就是从最高点到最低点的最大跌幅。它衡量的是:如果你在最倒霉的时候入场,最多会亏多少?

这个指标特别重要,因为它直接关系到投资者的心理承受能力。我见过很多策略,年化收益很高,但最大回撤超过50%,结果客户根本拿不住,最后割肉离场。

def max_drawdown(price_series):
    peak = np.maximum.accumulate(price_series)
    drawdown = (price_series - peak) / peak
    return drawdown.min()

# 模拟价格序列
prices = np.cumprod(1 + np.random.normal(0.001, 0.02, 1000))
mdd = max_drawdown(prices)
print(f"最大回撤: {mdd:.2%}")
核心观点: 最大回撤和收益是“跷跷板”。你想追求高收益,就得承受大回撤。风险预算的本质,就是在收益和回撤之间找到平衡点。

6. 风险因子模型:拆解风险的“显微镜”

前面讲的都是整体风险。但实际投资中,我们需要知道风险到底来自哪里。是市场波动?是行业轮动?还是某个特定风格?

风险因子模型就是用来干这个的。最经典的是Fama-French三因子模型:市场因子、规模因子(小盘股 vs 大盘股)、价值因子(高账面市值比 vs 低账面市值比)。

后来还有五因子模型、甚至十因子模型。我个人习惯用Barra模型,它把风险拆解成:

  • 市场因子: 大盘涨跌的影响
  • 行业因子: 你重仓了哪个行业
  • 风格因子: 比如动量、价值、波动率等
  • 特异风险: 个股自己的“脾气”
# 简单示例:用线性回归分解风险
import statsmodels.api as sm

# 假设我们有组合收益率和因子收益率数据
portfolio_returns = np.random.normal(0.001, 0.02, 100)
market_returns = np.random.normal(0.0005, 0.015, 100)
size_factor = np.random.normal(0.0002, 0.01, 100)

X = np.column_stack([market_returns, size_factor])
X = sm.add_constant(X)
model = sm.OLS(portfolio_returns, X).fit()
print(model.summary())
我曾经踩过的坑: 刚开始做因子模型时,我一股脑把所有因子都加进去,结果模型过拟合,样本外表现一塌糊涂。后来我学乖了:因子不是越多越好,关键是要有经济含义,并且因子之间要尽量正交。

知识体系总览

为了让你更直观地理解这些概念之间的关系,我画了一张图:

风险度量知识体系 波动率 协方差矩阵 最大回撤 VaR(风险价值) CVaR(期望损失) 风险因子模型 风险预算实战应用 资产配置 · 风险平价 · 因子暴露控制 · 压力测试 从基础指标到进阶模型,最终服务于风险预算实战

这张图清晰地展示了我们这一章的知识脉络。从最基础的波动率、协方差矩阵,到进阶的VaR、CVaR,再到风险因子模型,最终都指向一个目标——风险预算

总结一下: 波动率告诉你“跳得多快”,协方差告诉你“怎么一起跳”,VaR/CVaR告诉你“最坏能跳多深”,最大回撤告诉你“心理承受极限”,而风险因子模型则帮你找到“是谁在推着你跳”。把这些工具用好,你就能在风险预算中游刃有余。

好了,这一章的内容就到这里。记住,风险度量不是目的,控制风险才是。下一章我们会把这些工具串起来,真正开始做风险预算。


专注资料整理