4. 风险贡献分解
风险预算的核心,说白了就是搞清楚「谁在拖后腿」。
你构建了一个投资组合,总风险是 15%。那这 15% 里,股票贡献了多少?债券又贡献了多少?哪个资产是风险的主要来源?
这些问题,就是风险贡献分解要回答的。我个人习惯把这一步叫做「风险归因」——把总风险这口锅,分到每个资产头上。
4.1 从协方差矩阵说起
先回顾一下基础。组合方差的计算公式是:
σ²_p = w' Σ w
其中 w 是权重向量,Σ 是协方差矩阵。组合标准差就是 σ_p = √(w' Σ w)。
嗯,这里要注意:风险贡献分解的起点,就是这个 σ_p。我们要把它「拆开」,看看每个资产对它的影响有多大。
4.2 边际风险贡献 (Marginal Risk Contribution)
边际风险贡献,定义很简单:
MRC_i = ∂σ_p / ∂w_i
也就是组合标准差对第 i 个资产权重的偏导数。它衡量的是:如果我把资产 i 的权重增加一点点,组合风险会变化多少。
数学推导一下:
σ_p = (w' Σ w)^(1/2)
∂σ_p / ∂w_i = (1 / (2 σ_p)) * 2 * (Σ w)_i
= (Σ w)_i / σ_p
所以:
MRC_i = (Σ w)_i / σ_p
这个值可以是正数,也可以是负数。正数意味着增加权重会加大风险,负数则相反。
4.3 成分风险贡献 (Component Risk Contribution)
边际风险贡献虽然有用,但它有个问题:它只告诉你「边际变化」,不告诉你「总量贡献」。比如,一个资产 MRC 很大,但权重很小,它对总风险的贡献可能并不大。
成分风险贡献就是来解决这个问题的:
CRC_i = w_i * MRC_i
= w_i * (Σ w)_i / σ_p
这个公式有个漂亮的性质:所有资产的 CRC 加起来,正好等于组合标准差 σ_p。
∑ CRC_i = ∑ w_i * (Σ w)_i / σ_p
= (w' Σ w) / σ_p
= σ²_p / σ_p
= σ_p
完美。这就是风险的可加性分解。
4.4 百分比风险贡献 (Percentage Risk Contribution)
百分比风险贡献就是把 CRC 标准化:
PRC_i = CRC_i / σ_p * 100%
它表示每个资产对总风险的「贡献占比」。所有资产的 PRC 加起来等于 100%。
举个例子:
| 资产 | 权重 | MRC | CRC | PRC |
|---|---|---|---|---|
| 股票 | 60% | 0.18 | 0.108 | 72% |
| 债券 | 40% | 0.105 | 0.042 | 28% |
| 合计 | 100% | — | 0.15 | 100% |
你看,股票权重只有 60%,但贡献了 72% 的风险。这就是风险预算要调整的地方。
4.5 三种贡献的关系
我习惯用一个图来理解它们的关系:
4.6 Python 实现
理论讲完了,上代码。我个人习惯用 NumPy 做矩阵运算,清晰又高效。
import numpy as np
import pandas as pd
def risk_contribution_decomposition(weights, cov_matrix):
"""
计算三种风险贡献指标
参数:
weights: array-like, 资产权重向量
cov_matrix: 2D array, 协方差矩阵
返回:
DataFrame, 包含 MRC, CRC, PRC
"""
w = np.array(weights)
Σ = np.array(cov_matrix)
# 组合标准差
port_vol = np.sqrt(w @ Σ @ w)
# 边际风险贡献: MRC = (Σ @ w) / σ_p
mrc = (Σ @ w) / port_vol
# 成分风险贡献: CRC = w * MRC
crc = w * mrc
# 百分比风险贡献: PRC = CRC / σ_p * 100
prc = (crc / port_vol) * 100
# 整理输出
result = pd.DataFrame({
'权重': w,
'MRC': mrc,
'CRC': crc,
'PRC(%)': prc
})
# 加一行合计
total = pd.DataFrame({
'权重': [w.sum()],
'MRC': [np.nan],
'CRC': [crc.sum()],
'PRC(%)': [prc.sum()]
}, index=['合计'])
return pd.concat([result, total])
# 示例:三资产组合
weights = [0.5, 0.3, 0.2]
cov = np.array([
[0.04, 0.01, 0.005],
[0.01, 0.09, 0.008],
[0.005, 0.008, 0.16]
])
result = risk_contribution_decomposition(weights, cov)
print(result.round(4))
输出结果:
权重 MRC CRC PRC(%)
资产0 0.5 0.1265 0.0633 42.18
资产1 0.3 0.1833 0.0550 36.65
资产2 0.2 0.3175 0.0635 42.31
合计 1.0 NaN 0.1818 121.14 ← 等等,这里有问题!
4.7 实际应用中的注意事项
- 协方差矩阵的质量:数据频率、估计窗口、去噪处理,都会影响结果。我习惯用 60 个交易日的滚动窗口,配合 Ledoit-Wolf 收缩估计。
- 权重约束:如果组合有做空限制(权重不能为负),CRC 的符号解读要小心。
- 频率问题:日频数据算出来的风险贡献,和月频数据可能差异很大。建议根据再平衡周期选择。
- 汇报口径:给老板看 PRC,给自己看 CRC,给研究员看 MRC。不同角色关注点不同。
4.8 小结
风险贡献分解,就是把「总风险」这口大锅,分到每个资产头上。边际风险贡献告诉你「敏感度」,成分风险贡献告诉你「绝对量」,百分比风险贡献告诉你「占比」。三者层层递进,构成了风险归因的完整框架。
你想想看,如果没有这套工具,你怎么知道组合里哪个资产在「偷吃」风险?