引言:传统资产配置的困境与风险平价的崛起
在现代投资管理领域,资产配置被公认为决定投资组合长期表现的最关键因素,其重要性远超个股选择和市场择时。然而,传统的资产配置方法,尤其是基于市值加权或简单等权重的策略,在面对市场极端波动时往往暴露出显著的脆弱性。2008年全球金融危机、2020年新冠疫情期间的市场崩盘,以及近年来地缘政治冲突引发的市场动荡,都清晰地揭示了传统组合的痛点:风险过度集中。
传统组合通常面临两大核心难题:
- 股票风险主导:在典型的60/40股债组合中,尽管股票仅占60%的权重,但由于其远高于债券的波动性,组合90%以上的风险实际上来源于股票敞口。这意味着投资者在承担巨大波动的同时,并未获得相应的风险分散效益。
- 尾部风险失控:当市场危机来临时,股票和债券(尤其是信用债)往往出现相关性飙升,导致”分散化失效”,组合损失远超预期。
正是在这样的背景下,风险平价(Risk Parity)模型应运而生。它并非追求收益最大化,而是致力于风险均衡——让各类资产对组合的风险贡献相等。这种看似简单的理念,实则蕴含着深刻的金融逻辑,为破解传统组合波动难题提供了全新的量化解决方案。本文将深入剖析风险平价模型的理论基础、量化实现路径、实战应用策略,并通过详尽的Python代码示例展示其具体操作,最终探讨如何通过该模型实现真正的稳健收益。
一、传统资产配置的”波动陷阱”:为何我们需要风险平价?
1.1 传统市值加权组合的内在缺陷
市值加权组合(如标普500指数)是被动投资的基石,但其风险结构极不合理。假设一个简单的双资产组合:股票(年化波动率20%)和债券(年化波动率5%),初始权重为60%股票和40%债券。
风险贡献计算:
- 股票风险贡献 = 权重 × 边际风险贡献 ≈ 60% × 20% = 12%
- 债券风险贡献 = 40% × 5% = 2%
结果:组合总风险约14%,但股票贡献了约85%的风险,债券仅贡献15%。投资者看似分散了资金,实则将绝大部分风险押注在单一资产类别上。
1.2 相关性崩溃:分散化的阿喀琉斯之踵
传统组合依赖资产间的低相关性来平滑波动。然而,在系统性风险爆发时,资产相关性会急剧上升。例如:
- 2008年危机:股票与公司债的相关性从平时的0.3飙升至0.8以上
- 2020年3月:黄金、股票、债券同时下跌,传统分散化瞬间失效
这种”同涨同跌”现象使得组合在最需要保护的时候反而失去缓冲。
1.3 风险平价的核心理念:从”资金平衡”到”风险平衡”
风险平价彻底颠覆了传统思维。它不再关注资金如何分配,而是让风险本身实现均衡。在上述双资产例子中,风险平价会调整权重,使得:
- 股票风险贡献 = 债券风险贡献 = 组合总风险的50%
通过计算可得,这需要将股票权重降至约20%,债券权重提升至80%。虽然股票资金占比大幅下降,但其风险贡献与债券持平,实现了真正的风险分散。
二、风险平价模型的量化基础:从理论到数学表达
2.1 风险贡献的精确度量
风险平价的核心是计算每类资产对组合总风险的边际贡献。这需要引入现代投资组合理论(MPT)中的风险度量框架。
2.1.1 组合方差与协方差矩阵
对于一个包含N类资产的组合,其总方差为: $\( \sigma_p^2 = \sum_{i=1}^{N}\sum_{j=1}^{N} w_i w_j \sigma_i \sigma_j \rho_{ij} \)\( 其中 \)w_i\( 是资产i的权重,\)\sigmai\( 是其波动率,\)\rho{ij}$ 是资产i和j的相关系数。
用矩阵形式表示为: $\( \sigma_p^2 = \mathbf{w}^T \Sigma \mathbf{w} \)\( 其中 \)\mathbf{w}\( 是权重向量,\)\Sigma$ 是协方差矩阵。
2.1.2 边际风险贡献(MRC)
资产i对组合总风险的边际贡献定义为组合风险对该资产权重的偏导数: $\( MRC_i = \frac{\partial \sigma_p}{\partial w_i} = \frac{(\Sigma \mathbf{w})_i}{\sigma_p} \)\( 其中 \)(\Sigma \mathbf{w})_i$ 是协方差矩阵与权重向量乘积的第i个元素。
2.1.3 风险贡献(RC)
资产i的总风险贡献是其边际贡献与权重的乘积: $$ RC_i = w_i \times MRC_i = \frac{w_i (\Sigma \math1. 风险平价模型的量化基础:从理论到数学表达
2.1.1 组合方差与协方差矩阵
对于一个包含N类资产的组合,其总方差为: $\( \sigma_p^2 = \sum_{i=1}^{N}\sum_{j=1}^{N} w_i w_j \sigma_i \sigma_j \rho_{ij} \)\( 其中 \)w_i\( 是资产i的权重,\)\sigmai\( 是其波动率,\)\rho{ij}$ 是资产i和j的相关系数。
用矩阵形式表示为: $\( \sigma_p^2 = \mathbf{w}^T \Sigma \mathbf{w} \)\( 其中 \)\mathbf{w}\( 是权重向量,\)\Sigma$ 是协方差矩阵。
2.1.2 边际风险贡献(MRC)
资产i对组合总风险的边际贡献定义为组合风险对该资产权重的偏导数: $\( MRC_i = \frac{\partial \sigma_p}{\partial w_i} = \frac{(\Sigma \mathbf{w})_i}{\sigma_p} \)\( 其中 \)(\Sigma \mathbf{w})_i$ 是协方差矩阵与权重向量乘积的第i个元素。
2.1.3 风险贡献(RC)
资产i的总风险贡献是其边际贡献与权重的乘积: $\( RC_i = w_i \times MRC_i = \frac{w_i (\Sigma \mathbf{w})_i}{\sigma_p} \)$
关键性质:所有资产的风险贡献之和等于组合总风险: $\( \sum_{i=1}^{N} RC_i = \sigma_p \)$
2.2 风险平价的数学优化目标
风险平价的核心约束是让每类资产的风险贡献相等: $\( RC_i = \frac{\sigma_p}{N}, \quad \forall i = 1,2,...,N \)$
这转化为一个优化问题: $\( \min_{\mathbf{w}} \sum_{i=1}^{N} \left( RC_i - \frac{\sigma_p}{N} \right)^2 \)\( \)\( \text{s.t.} \quad \sum_{i=1}^{N} w_i = 1, \quad w_i \geq 0 \)$
2.3 实际应用中的关键挑战与解决方案
2.3.1 协方差矩阵估计误差
问题:历史协方差矩阵估计存在噪声,尤其在资产数量多时,估计误差会被放大。
解决方案:
- 收缩估计法(Shrinkage Estimator):将样本协方差矩阵向目标矩阵(如单位矩阵或单因子矩阵)收缩
- 因子模型降维:用少数宏观经济因子解释资产收益变动
- 滚动窗口与指数加权:使用更近期的数据赋予更高权重
2.3.2 非凸优化问题
问题:风险平价优化是非凸问题,存在多个局部最优解。
解决方案:
- 序列二次规划(SQP)
- 信赖域算法
- 解析近似解:在双资产情况下可推导精确解
三、Python实战:从零实现风险平价模型
下面我们将通过完整的Python代码,演示如何构建一个四资产(股票、债券、商品、REITs)的风险平价组合。
3.1 环境准备与数据获取
import numpy as np
import pandas as pd
import yfinance as yf
from scipy.optimize import minimize
import matplotlib.pyplot as plt
import seaborn as sns
# 设置中文字体(根据系统调整)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 下载历史数据(2015-2024)
tickers = {
'股票': 'SPY', # 标普500 ETF
'债券': 'TLT', # 20年期国债ETF
'商品': 'GLD', # 黄金ETF
'REITs': 'VNQ' # 房地产信托ETF
}
# 获取数据
data = yf.download(list(tickers.values()), start='2015-01-01', end='2024-12-31')['Adj Close']
data.columns = list(tickers.keys())
# 计算对数收益率
returns = np.log(data / data.shift(1)).dropna()
print("数据概览:")
print(returns.head())
print(f"\n数据形状:{returns.shape}")
3.2 风险贡献计算函数
def calculate_risk_contributions(weights, cov_matrix):
"""
计算各资产的风险贡献
:param weights: 权重向量
:param cov_matrix: 协方差矩阵
:return: 风险贡献向量
"""
# 组合波动率
portfolio_vol = np.sqrt(weights.T @ cov_matrix @ weights)
# 边际风险贡献
marginal_risk_contrib = (cov_matrix @ weights) / portfolio_vol
# 总风险贡献
risk_contrib = weights * marginal_risk_contrib
return risk_contrib
def calculate_portfolio_volatility(weights, cov_matrix):
"""计算组合波动率"""
return np.sqrt(weights.T @ cov_matrix @ weights)
def risk_parity_objective(weights, cov_matrix):
"""
风险平价目标函数:最小化风险贡献的差异
"""
rc = calculate_risk_contributions(weights, cov_matrix)
# 目标:让所有资产的风险贡献相等
target_rc = np.sum(rc) / len(rc)
return np.sum((rc - target_rc)**2)
3.3 优化求解风险平价权重
def calculate_risk_parity_weights(cov_matrix, max_iter=1000):
"""
计算风险平价权重
:param cov_matrix: 协方差矩阵
:param max_iter: 最大迭代次数
:return: 优化后的权重
"""
n_assets = cov_matrix.shape[0]
# 初始猜测:等权重
initial_weights = np.ones(n_assets) / n_assets
# 约束条件
constraints = (
{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}, # 权重和为1
)
# 边界条件:不允许做空
bounds = tuple((0, 1) for _ in range(n_assets))
# 优化
result = minimize(
fun=risk_parity_objective,
x0=initial_weights,
args=(cov_matrix,),
method='SLSQP',
bounds=bounds,
constraints=constraints,
options={'maxiter': max_iter, 'ftol': 1e-9}
)
if not result.success:
print(f"优化失败:{result.message}")
return None
return result.x
# 计算协方差矩阵(使用252天滚动窗口)
cov_matrix = returns.rolling(252).cov().dropna()
# 选取最近一期协方差矩阵进行计算
latest_cov = cov_matrix.iloc[-4:] # 最后4个资产的协方差矩阵
print("最新协方差矩阵:")
print(latest_cov)
3.4 风险平价组合回测
def backtest_risk_parity(returns, rebal_freq=21):
"""
回测风险平价组合
:param returns: 收益率数据
:param rebal_freq: 再平衡频率(交易日)
:return: 组合净值曲线
"""
n_periods = len(returns)
n_assets = returns.shape[1]
# 初始化
portfolio_value = 1.0
weights = np.ones(n_assets) / n_assets # 初始等权重
nav_series = [1.0]
for i in range(1, n_periods):
# 每rebal_freq天再平衡
if i % rebal_freq == 0:
# 使用过去252天数据计算协方差矩阵
if i >= 252:
cov_mat = returns.iloc[i-252:i].cov().values
weights = calculate_risk_parity_weights(cov_mat)
if weights is None:
weights = np.ones(n_assets) / n_assets
else:
weights = np.ones(n_assets) / n_assets
# 计算当日收益
daily_return = np.dot(weights, returns.iloc[i].values)
portfolio_value *= (1 + daily_return)
nav_series.append(portfolio_value)
return pd.Series(nav_series, index=returns.index)
# 执行回测
rp_nav = backtest_risk_parity(returns)
# 对比基准:等权重组合
ew_nav = (1 + returns).cumprod()
ew_nav = ew_nav.mean(axis=1) # 等权重组合净值
# 对比基准:60/40股债组合
stock_weight = 0.6
bond_weight = 0.4
benchmark_nav = 1 + returns['股票'] * stock_weight + returns['债券'] * bond_weight
benchmark_nav = benchmark_nav.cumprod()
3.5 绩效评估与可视化
def calculate_performance_metrics(nav_series, benchmark_series):
"""计算绩效指标"""
returns_series = nav_series.pct_change().dropna()
benchmark_returns = benchmark_series.pct_change().dropna()
# 年化收益率
annual_return = (nav_series.iloc[-1] / nav_series.iloc[0]) ** (252/len(returns_series)) - 1
# 年化波动率
annual_vol = returns_series.std() * np.sqrt(252)
# 夏普比率(假设无风险利率2%)
sharpe_ratio = (annual_return - 0.02) / annual_vol
# 最大回撤
cumulative = nav_series
running_max = cumulative.expanding().max()
drawdown = (cumulative - running_max) / running_max
max_drawdown = drawdown.min()
# 胜率(相对于基准)
outperformance = (returns_series - benchmark_returns).gt(0).mean()
return {
'年化收益率': f"{annual_return:.2%}",
'年化波动率': f"{annual_vol:.2%}",
'夏普比率': f"{sharpe_ratio:.2f}",
'最大回撤': f"{max_drawdown:.2%}",
'跑赢基准概率': f"{outperformance:.1%}"
}
# 计算指标
rp_metrics = calculate_performance_metrics(rp_nav, benchmark_nav)
ew_metrics = calculate_performance_metrics(ew_nav, benchmark_nav)
bm_metrics = calculate_performance_metrics(benchmark_nav, benchmark_nav)
print("\n=== 风险平价组合绩效 ===")
for k, v in rp_metrics.items():
print(f"{k}: {v}")
print("\n=== 等权重组合绩效 ===")
for k, v in ew_metrics.items():
print(f"{k}: {v}")
print("\n=== 60/40基准组合绩效 ===")
for k, v in bm_metrics.items():
print(f"{k}: {v}")
# 可视化
plt.figure(figsize=(14, 6))
# 净值对比
plt.subplot(1, 2, 1)
plt.plot(rp_nav.index, rp_nav.values, label='风险平价', linewidth=2)
plt.plot(ew_nav.index, ew_nav.mean(axis=1).values, label='等权重', alpha=0.7)
plt.plot(benchmark_nav.index, benchmark_nav.values, label='60/40基准', alpha=0.7)
plt.title('净值曲线对比')
plt.xlabel('日期')
plt.ylabel('累计净值')
plt.legend()
plt.grid(True, alpha=0.3)
# 风险贡献对比
plt.subplot(1, 2, 2)
# 计算最新一期风险贡献
latest_weights = calculate_risk_parity_weights(latest_cov.values)
rc = calculate_risk_contributions(latest_weights, latest_cov.values)
plt.bar(range(len(rc)), rc)
plt.title('风险平价组合风险贡献')
plt.xlabel('资产类别')
plt.ylabel('风险贡献')
plt.xticks(range(len(rc)), list(tickers.keys()))
plt.grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.show()
3.6 代码运行结果分析
运行上述代码后,你将得到:
- 净值曲线对比:清晰展示风险平价组合在波动控制上的优势
- 绩效指标表格:量化比较三种策略的表现
- 风险贡献柱状图:验证风险平价是否真正实现了风险均衡
预期结果:在2015-2024年的回测中,风险平价组合通常会表现出:
- 更低的波动率(约8-10% vs 12-15%)
- 更小的最大回撤(约10-15% vs 20-25%)
- 更优的夏普比率(通常>0.8)
- 更高的风险贡献均衡度(各资产RC差异%)
四、进阶策略:从基础风险平价到增强型方案
4.1 引入杠杆:风险平价的”放大器”
基础风险平价组合往往因债券权重过高而导致预期收益偏低。通过适度杠杆(如2倍),可以在保持风险均衡的同时提升收益。
杠杆实现代码:
def leveraged_risk_parity_weights(cov_matrix, leverage=2.0):
"""
计算杠杆化风险平价权重
:param leverage: 杠杆倍数
"""
base_weights = calculate_risk_parity_weights(cov_matrix)
if base_weights is None:
return None
# 杠杆化(需考虑融资成本)
leveraged_weights = base_weights * leverage
# 约束:权重不能超过1(单资产上限)
leveraged_weights = np.clip(leveraged_weights, 0, 1)
# 重新归一化(如果超过1)
if leveraged_weights.sum() > 1:
leveraged_weights = leveraged_weights / leveraged_weights.sum()
return leveraged_weights
4.2 动态风险预算:应对市场 regime 变化
市场波动率是动态变化的,固定风险预算可能失效。动态风险平价根据市场波动率调整风险敞口。
动态调整逻辑:
- 当市场波动率上升时,降低整体风险预算
- 当市场波动率下降时,适度增加风险敞口
def dynamic_risk_parity_weights(cov_matrix, current_vol, baseline_vol=0.15):
"""
动态风险平价:根据当前波动率调整风险预算
:param current_vol: 当前市场波动率
:param baseline_vol: 基准波动率(如15%)
"""
base_weights = calculate_risk_parity_weights(cov_matrix)
# 计算调整系数(反比关系)
adjustment_factor = baseline_vol / current_vol
# 调整权重(保持总和为1)
adjusted_weights = base_weights * adjustment_factor
adjusted_weights /= adjusted_weights.sum()
return adjusted_weights
4.3 引入动量因子:增强收益
在风险平价基础上加入动量因子,可以提升组合收益。具体做法是:对风险贡献进行动量加权。
def momentum_weighted_risk_parity(returns, cov_matrix, momentum_window=63):
"""
动量加权风险平价
"""
# 计算动量得分(过去63天收益)
momentum_scores = returns.iloc[-momentum_window:].mean()
# 基础风险平价权重
base_weights = calculate_risk_parity_weights(cov_matrix)
# 动量加权(对高动量资产增加风险预算)
momentum_weights = base_weights * (1 + momentum_scores / momentum_scores.std())
momentum_weights /= momentum_weights.sum()
return momentum_weights
五、风险平价的局限性与风险管理
5.1 模型固有缺陷
- 对协方差矩阵高度敏感:估计误差会直接导致权重失真
- 尾部风险未完全消除:在极端市场下,资产相关性可能趋近1,风险平价也会失效
- 流动性约束:小规模资产可能无法承载大资金的快速调整
5.2 实战风险管理框架
5.2.1 压力测试与情景分析
def stress_test_risk_parity(cov_matrix, stress_scenarios):
"""
压力测试:模拟极端市场下的表现
:param stress_scenarios: 压力情景字典,如{'股债双杀': {'股票': -0.1, '债券': -0.05}}
"""
base_weights = calculate_risk_parity_weights(cov_matrix)
results = {}
for scenario_name, returns_shock in stress_scenarios.items():
# 构造压力下的协方差矩阵(放大波动率)
stressed_cov = cov_matrix.copy()
for asset, shock in returns_shock.items():
idx = list(tickers.keys()).index(asset)
stressed_cov.iloc[idx, idx] *= 3 # 假设波动率放大3倍
# 重新计算权重
stressed_weights = calculate_risk_parity_weights(stressed_cov)
# 计算压力下的风险贡献
rc = calculate_risk_contributions(stressed_weights, stressed_cov.values)
results[scenario_name] = dict(zip(tickers.keys(), rc))
return results
# 定义压力情景
stress_scenarios = {
'股债双杀': {'股票': -0.1, '债券': -0.05},
'通胀飙升': {'股票': -0.08, '债券': -0.1, '商品': 0.05},
'流动性危机': {'股票': -0.15, '债券': -0.02, 'REITs': -0.12}
}
stress_results = stress_test_risk_parity(latest_cov.values, stress_scenarios)
print("\n压力测试结果:")
for scenario, rc in stress_results.items():
print(f"\n{scenario}:")
for asset, value in rc.items():
print(f" {asset}: {value:.4f}")
5.2.2 动态再平衡纪律
核心原则:
- 定期再平衡:每月或每季度强制调整回目标权重
- 阈值再平衡:当某资产风险贡献偏离目标超过±20%时触发调整
- 交易成本控制:在再平衡时考虑冲击成本,避免过度交易
六、实战案例:2020年3月市场崩盘中的风险平价表现
6.1 市场背景回顾
2020年3月,新冠疫情引发全球市场恐慌:
- 标普500指数下跌34%
- 美国国债上涨(避险情绪)
- 黄金先跌后涨
- 公司债暴跌
6.2 组合表现对比
传统60/40组合:
- 股票部分损失:-34% × 60% = -20.4%
- 债券部分收益:+5% × 40% = +2%
- 总损失:-18.4%
风险平价组合(假设权重:股票20%、债券60%、黄金10%、REITs 10%):
- 股票:-34% × 20% = -6.8%
- 债券:+5% × 60% = +3%
- 黄金:+2% × 10% = +0.2%
- REITs:-25% × 10% = -2.5%
- 总损失:-6.1%
关键洞察:风险平价通过大幅降低股票权重,有效控制了尾部损失。虽然债券权重高,但其波动率低,实际风险贡献仍与股票相当。
6.3 事后复盘与优化
2020年3月也暴露了风险平价的弱点:流动性冲击下的再平衡困难。当时许多ETF出现大幅折溢价,实际交易成本极高。
优化方案:
- 引入波动率过滤器:当VIX指数超过40时,暂停再平衡
- 增加现金缓冲:保留5-10%现金应对极端情况
- 使用期货替代ETF:提高流动性,降低冲击成本
七、构建稳健收益的完整框架
7.1 四步实施路径
第一步:数据准备与清洗
- 获取至少5-10年历史数据
- 处理缺失值和异常值
- 检验数据平稳性
第二步:协方差矩阵优化
- 使用收缩估计法
- 引入因子模型降维
- 滚动窗口动态更新
第三步:权重计算与优化
- 实现风险平价核心算法
- 加入杠杆和动态调整
- 设置约束条件(行业、个券上限)
第四步:执行与监控
- 建立再平衡日历
- 实时监控风险贡献偏离度
- 定期压力测试
7.2 与传统组合的对比总结
| 指标 | 60/40组合 | 风险平价组合 | 说明 |
|---|---|---|---|
| 资金分配 | 股票60%,债券40% | 股票20%,债券60%,其他20% | 风险平价债券权重更高 |
| 风险贡献 | 股票85%,债券15% | 各资产约25% | 风险平价实现均衡 |
| 年化波动率 | 12-15% | 8-10% | 风险平价更稳健 |
| 最大回撤 | -20%至-30% | -10%至-15% | 风险平价回撤更小 |
| 夏普比率 | 0.5-0.7 | 0.8-1.0 | 风险平价风险调整后收益更高 |
| 尾部风险 | 高 | 中 | 风险平价仍需杠杆提升收益 |
7.3 个人投资者实施建议
对于个人投资者,可采用以下简化方案:
- 使用现成ETF:SPY(股票)、TLT(债券)、GLD(黄金)、VNQ(REITs)
- 季度再平衡:每季度调整一次,降低交易成本
- 杠杆控制:如需增强收益,杠杆不超过1.5倍
- 长期坚持:风险平价的优势在3-5年周期中才能充分显现
八、结论:风险平价——从理论到实践的稳健之路
风险平价模型通过风险均衡理念,从根本上解决了传统组合”风险集中”的痛点。它并非追求绝对收益,而是致力于优化风险-adjusted回报,这正是长期投资成功的关键。
核心价值总结:
- 破解波动难题:通过风险贡献均衡,大幅降低组合波动率和最大回撤
- 实现稳健收益:在不同市场环境下提供更平滑的净值曲线
- 量化透明:所有决策基于数据和模型,避免主观情绪干扰
未来展望: 随着人工智能和机器学习技术的发展,风险平价模型正朝着智能化方向演进:
- AI驱动的协方差预测:使用LSTM、Transformer等模型提升预测精度
- 自适应风险预算:根据市场状态动态调整风险分配
- 多因子融合:将风险平价与动量、价值等因子结合
对于追求长期稳健增值的投资者而言,风险平价不仅是一种技术工具,更是一种投资哲学——它提醒我们:控制风险,才能驾驭收益。
附录:完整代码与数据获取指南
A.1 完整可运行脚本
# 一键运行完整风险平价系统
import numpy as np
import pandas as pd
import yfinance as yf
from scipy.optimize import minimize
import matplotlib.pyplot as plt
class RiskParityPortfolio:
"""风险平价组合类"""
def __init__(self, tickers, start_date, end_date):
self.tickers = tickers
self.start_date = start_date
self.end_date = end_date
self.data = None
self.returns = None
self.cov_matrix = None
def fetch_data(self):
"""获取数据"""
self.data = yf.download(
list(self.tickers.values()),
start=self.start_date,
end=self.end_date
)['Adj Close']
self.data.columns = list(self.tickers.keys())
self.returns = np.log(self.data / self.data.shift(1)).dropna()
return self
def calculate_weights(self, window=252):
"""计算最新权重"""
if self.returns is None:
raise ValueError("请先获取数据")
# 使用滚动窗口计算协方差
cov_mat = self.returns.iloc[-window:].cov().values
# 风险平价优化
n_assets = len(self.tickers)
initial_weights = np.ones(n_assets) / n_assets
constraints = ({'type': 'eq', 'fun': lambda w: np.sum(w) - 1})
bounds = tuple((0, 1) for _ in range(n_assets))
def objective(w):
vol = np.sqrt(w.T @ cov_mat @ w)
rc = w * (cov_mat @ w) / vol
target = np.sum(rc) / n_assets
return np.sum((rc - target)**2)
result = minimize(objective, initial_weights, method='SLSQP',
bounds=bounds, constraints=constraints)
return dict(zip(self.tickers.keys(), result.x))
def backtest(self, rebal_freq=21):
"""回测"""
returns = self.returns
n_periods = len(returns)
n_assets = len(self.tickers)
nav = 1.0
nav_series = [1.0]
weights = np.ones(n_assets) / n_assets
for i in range(1, n_periods):
if i % rebal_freq == 0 and i >= 252:
cov_mat = returns.iloc[i-252:i].cov().values
# 重新计算权重
initial_weights = np.ones(n_assets) / n_assets
constraints = ({'type': 'eq', 'fun': lambda w: np.sum(w) - 1})
bounds = tuple((0, 1) for _ in range(n_assets))
def objective(w):
vol = np.sqrt(w.T @ cov_mat @ w)
rc = w * (cov_mat @ w) / vol
target = np.sum(rc) / n_assets
return np.sum((rc - target)**2)
result = minimize(objective, initial_weights, method='SLSQP',
bounds=bounds, constraints=constraints)
if result.success:
weights = result.x
daily_return = np.dot(weights, returns.iloc[i].values)
nav *= (1 + daily_return)
nav_series.append(nav)
return pd.Series(nav_series, index=returns.index)
# 使用示例
if __name__ == "__main__":
# 定义资产
tickers = {
'股票': 'SPY',
'债券': 'TLT',
'商品': 'GLD',
'REITs': 'VNQ'
}
# 创建实例
rp = RiskParityPortfolio(tickers, '2015-01-01', '2024-12-31')
# 获取数据
rp.fetch_data()
# 计算当前权重
current_weights = rp.calculate_weights()
print("当前风险平价权重:")
for asset, weight in current_weights.items():
print(f" {asset}: {weight:.2%}")
# 回测
nav = rp.backtest()
print(f"\n回测结果:累计收益率 {(nav.iloc[-1]-1):.2%}")
# 可视化
plt.figure(figsize=(10, 6))
plt.plot(nav.index, nav.values, linewidth=2)
plt.title('风险平价组合净值曲线')
plt.xlabel('日期')
plt.ylabel('累计净值')
plt.grid(True, alpha=0.3)
plt.show()
A.2 数据获取注意事项
- 数据源:推荐使用Yahoo Finance(yfinance库)或Wind、Bloomberg等专业数据库
- 数据频率:日频数据最适合风险平价计算
- 数据长度:至少5年历史数据,理想为10年
- 数据清洗:处理除权、除息、停牌等情况
A.3 常见问题解答
Q1: 风险平价是否适合所有市场环境? A: 风险平价在震荡市和熊市中表现优异,但在单边牛市可能跑输纯股票组合。建议作为核心配置(50-70%),搭配其他策略。
Q2: 个人投资者如何低成本实现? A: 使用ETF组合,季度再平衡,避免频繁交易。杠杆可通过融资融券或杠杆ETF实现,但需谨慎。
Q3: 如何处理资产数量较多的情况? A: 当资产超过10个时,建议使用因子模型降维,或采用分层风险平价(Hierarchical Risk Parity)方法。
最终总结:风险平价模型通过量化手段实现了真正的风险分散,为破解传统组合波动难题提供了科学方案。虽然它不是万能的,但在长期投资中,其稳健性和可解释性使其成为现代资产配置不可或缺的工具。对于追求睡得着觉的投资的投资者而言,风险平价值得深入研究和实践。
