In [1]:
Copied!
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import yfinance as yf
from scipy.optimize import minimize
from sklearn.decomposition import PCA
plt.rcParams['figure.figsize'] = (12, 6)
plt.style.use('seaborn-v0_8-muted')
# 多元资产池:构建一个典型的“全天候”风格组合
tickers = ['SPY', 'TLT', 'GLD', 'QQQ', 'VIXY']
labels = ['标普500', '长期美债', '黄金', '纳指100', '恐慌指数']
prices = yf.download(tickers, start='2015-01-01', end='2024-01-01',
progress=False)['Close'].dropna()
returns = prices.pct_change().dropna()
cov = returns.cov() * 252
n = len(tickers)
print('数据准备就绪。')
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import yfinance as yf
from scipy.optimize import minimize
from sklearn.decomposition import PCA
plt.rcParams['figure.figsize'] = (12, 6)
plt.style.use('seaborn-v0_8-muted')
# 多元资产池:构建一个典型的“全天候”风格组合
tickers = ['SPY', 'TLT', 'GLD', 'QQQ', 'VIXY']
labels = ['标普500', '长期美债', '黄金', '纳指100', '恐慌指数']
prices = yf.download(tickers, start='2015-01-01', end='2024-01-01',
progress=False)['Close'].dropna()
returns = prices.pct_change().dropna()
cov = returns.cov() * 252
n = len(tickers)
print('数据准备就绪。')
数据准备就绪。
In [2]:
Copied!
import matplotlib.pyplot as plt
# 1. 设置系统自带的中文字体(这里使用黑体 SimHei)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 如果你想用微软雅黑,可以改成 ['Microsoft YaHei']
# 2. 解决更换字体后,负号(-)显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False
import matplotlib.pyplot as plt
# 1. 设置系统自带的中文字体(这里使用黑体 SimHei)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 如果你想用微软雅黑,可以改成 ['Microsoft YaHei']
# 2. 解决更换字体后,负号(-)显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False
1. 风险贡献:谁在拖后腿?¶
在等权组合中,每个资产买一样多。但因为股票的波动率是债券的 4-5 倍,所以组合 90% 以上的风险其实来自股票。风险平价的目标是让每类资产提供的“波动”是一样多的。
In [3]:
Copied!
def get_risk_contributions(w, cov):
p_vol = np.sqrt(w @ cov @ w)
mrc = cov @ w / p_vol # 边际风险贡献
trc = w * mrc # 总风险贡献
return trc / trc.sum()
eq_w = np.ones(n) / n
eq_rc = get_risk_contributions(eq_w, cov)
plt.bar(labels, eq_rc, alpha=0.7)
plt.axhline(1/n, color='red', linestyle='--', label='理想持平线')
plt.title("等权组合中,风险贡献极度不平衡!")
plt.legend()
plt.show()
def get_risk_contributions(w, cov):
p_vol = np.sqrt(w @ cov @ w)
mrc = cov @ w / p_vol # 边际风险贡献
trc = w * mrc # 总风险贡献
return trc / trc.sum()
eq_w = np.ones(n) / n
eq_rc = get_risk_contributions(eq_w, cov)
plt.bar(labels, eq_rc, alpha=0.7)
plt.axhline(1/n, color='red', linestyle='--', label='理想持平线')
plt.title("等权组合中,风险贡献极度不平衡!")
plt.legend()
plt.show()
2. 深度普及:主成分风险分析 (PCA Risk)¶
进阶视角: 有时你买了 5 只股票,以为分散了风险。但 PCA 可能会告诉你,这 5 只股票 90% 的波动都来自同一个方向。这就是隐性相关性。
真正的风险平价不仅要求资产间平衡,还要求风险因子间平衡。
In [4]:
Copied!
pca = PCA()
pca.fit(returns)
evr = pca.explained_variance_ratio_
plt.bar(range(1, n+1), evr, alpha=0.6, color='purple')
plt.plot(range(1, n+1), np.cumsum(evr), marker='o', color='red')
plt.title("组合风险的隐性构成:前两个主成分解释了绝大部分波动")
plt.xlabel("主成分编号")
plt.ylabel("解释方差比例")
plt.show()
print(f"结论:虽然我们有 5 类资产,但本质上只有 {np.where(np.cumsum(evr) > 0.9)[0][0] + 1} 个核心力量在驱动组合。")
pca = PCA()
pca.fit(returns)
evr = pca.explained_variance_ratio_
plt.bar(range(1, n+1), evr, alpha=0.6, color='purple')
plt.plot(range(1, n+1), np.cumsum(evr), marker='o', color='red')
plt.title("组合风险的隐性构成:前两个主成分解释了绝大部分波动")
plt.xlabel("主成分编号")
plt.ylabel("解释方差比例")
plt.show()
print(f"结论:虽然我们有 5 类资产,但本质上只有 {np.where(np.cumsum(evr) > 0.9)[0][0] + 1} 个核心力量在驱动组合。")
结论:虽然我们有 5 类资产,但本质上只有 2 个核心力量在驱动组合。
3. 求解风险平价权重¶
我们通过优化,寻找一组权重,使得 (每个资产的风险贡献 - 1/N)^2 的总和最小。
In [5]:
Copied!
def obj_fun(w, cov):
rc = get_risk_contributions(w, cov)
return np.sum((rc - 1/len(w))**2)
res = minimize(obj_fun, eq_w, args=(cov,),
bounds=[(0.01, 1)]*n, constraints={'type':'eq', 'fun': lambda w: w.sum()-1})
rp_w = res.x
print("--- 风险平价配置方案 ---")
for l, w in zip(labels, rp_w):
print(f"{l:<10}: {w:.2%}")
def obj_fun(w, cov):
rc = get_risk_contributions(w, cov)
return np.sum((rc - 1/len(w))**2)
res = minimize(obj_fun, eq_w, args=(cov,),
bounds=[(0.01, 1)]*n, constraints={'type':'eq', 'fun': lambda w: w.sum()-1})
rp_w = res.x
print("--- 风险平价配置方案 ---")
for l, w in zip(labels, rp_w):
print(f"{l:<10}: {w:.2%}")
--- 风险平价配置方案 --- 标普500 : 28.79% 长期美债 : 16.72% 黄金 : 21.64% 纳指100 : 31.85% 恐慌指数 : 1.00%
🎯 练习¶
- 极端测试:如果加入一个波动率极大的资产(如比特币),风险平价策略会给它分配多少权重?
- 因子平衡:尝试计算这 5 个资产在第一主成分(PC1)上的暴露,思考如何降低组合对“市场共同下跌”的敏感度。
- 现实调整:风险平价通常会导致组合收益过低,在现实中往往需要配合杠杆使用。思考:如何在不改变风险比例的前提下提升预期收益?
下一模块 → ../06_ml_trading/(我们将学习如何利用机器学习识别复杂的盈利模式)
In [ ]:
Copied!