大家好,我是赛博解生酱。
在这个充满不确定性的A股市场里交易,能够常常体会到湿实验室(Wet Lab)里盯着培养皿的忐忑感。生物体之所以能在这个熵增的宇宙中延续,靠的不是预测明天会发生什么,而是进化出了一套极强的稳态调节机制(Homeostasis)。
在量化投资的浩瀚海洋中,也有这样一种策略,它不赌国运,不猜点位,而是试图构建一个像生物体一样具有“鲁棒性”的资产组合——它就是风险平价模型(Risk Parity)。
上一篇文章解析了BL模型的整体框架与设计思想,但是BL策略依然需要投资者的主观观点。作为一名上班族,鲜有时间对上市公司进行深入研究,因此一个能够应付不同宏观经济环境的投资策略能够满足我这类“手残党”兼“时间贫困者”的核心诉求——无需频繁盯盘调整,也能在牛熊交替、风格切换的市场中保持相对稳定的收益,而风险平价模型恰好提供了这样一条新路径。
在聊Risk Parity之前,我们先给传统的“股债60/40”组合把把脉。
很多人的投资账户就像一个“偏科”的学生。表面上你买了40%的债券做防守,60%的股票做进攻。但在数学视角下,资金权重 风险权重。
由于股票的波动率通常是债券的3-5倍,在这个看似平衡的组合里,90%以上的风险其实都来源于股票。这就好比你设计了一个生物系统,心脏承担了90%的负荷,一旦心脏(股市)停跳,整个机体(账户)就崩了。
而风险平价模型的核心哲学,就是从资金均衡转向风险均衡。我们要让每一个资产在组合的“风险贡献”中平起平坐。
风险平价模型正是在这种传统模式的痛点下应运而生。该策略真正被推向全球舞台,离不开桥水基金(Bridgewater Associates)及其创始人雷·达里奥(Ray Dalio)的实践和推广。桥水将风险平价思想应用于其旗舰产品——“全天候(All Weather)”策略,旨在构建一个在任何经济周期下都能保持稳健表现的投资组合。
风险平价模型的核心哲学,就是从资金均衡转向风险均衡,要让每一个资产在组合的“风险贡献”中平起平坐。它不追求在牛市中跑得最快,而是追求在不同市场环境下都能保持系统级的鲁棒性。这和生物体的“内环境稳态”何其相似:当外部环境变化时,通过内部的自动调节(即动态调整资产权重),确保核心风险指标稳定。
作为一名耕耘多年科研一线的算法研究员,风险平价的数学表达让我感到一种对称的美感。这本质上是一个凸优化问题。
假设我们有 个资产,权重向量为 ,协方差矩阵为 。组合的整体波动率(风险) 可以表示为:
这里引入一个在经济学甚至日常生活中都常常听到的概念——边际贡献。第 个资产的边际风险贡献(Marginal Risk Contribution, MRC),其实就是风险对权重的偏导数:
那么,该资产对总风险的**总贡献(Risk Contribution, RC)**就是权重乘以边际风险:
我们的终极目标,是让所有资产的风险贡献相等(或者符合预设比例)。这可以转化为一个最小化问题:
赛博酱的思考:这里的求解过程非常简单,其实思想和训练神经网络非常像。我们在寻找一个高维空间中的最优点,使得系统的“风险能量”分布达到最低熵的状态。
在实际的量化实战中,仅仅让风险相等是不够的。为了过去更高收益以及进一步降低风险,风险平价有不同类型的变体:
自动超配低波动资产(如国债)。虽然稳,但硬伤是收益率可能偏低。适合像养老金这种极度厌恶风险的资金。
这是桥水基金(Bridgewater)的拿手好戏。通过给低风险资产(债券)加杠杆,使其波动率对齐股票,从而在保持**夏普比率(Sharpe Ratio)**优势的同时,拉高整体收益。
注意:杠杆是双刃剑,必须要配合严格的风控模型。
这是我目前最感兴趣的方向。传统的Risk Parity最大的痛点在于:历史波动率 未来波动率。
传统的模型用历史数据计算协方差矩阵 ,存在严重的滞后性。在深度学习时代,我们可以利用 LSTM 或 Transformer 网络,结合宏观和行业、舆情等数据(例如NLP技术),预测未来的波动率。
一些简单思考:如果不将所有资产的 设为相等,而是根据模型预测的胜率,动态调整风险预算向量 ,这就变成了: 这实际上是把主动管理的观点(View) 融入到了 被动配置的框架 中。
光说不练假把式。下面我用一段Python代码来模拟一个包含“股灾”场景的市场,看看风险平价是否真能穿越牛熊。
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# 设置绘图参数,中文显示
plt.style.use('ggplot')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def generate_market_data(n_days=1000):
"""生成具有负相关性的股债数据,模拟牛熊周期"""
np.random.seed(42)
dt = 1/252
# 参数设定:[股票, 债券]
# 股票:高收益高波动;债券:低收益低波动
mu = np.array([0.15, 0.04])
vol = np.array([0.25, 0.05])
# 关键:设置强负相关性 (-0.4),确保股债对冲效果
corr_matrix = np.array([
[1.0, -0.4],
[-0.4, 1.0]
])
# 生成相关联的随机过程
cov = np.outer(vol, vol) * corr_matrix
L = np.linalg.cholesky(cov)
returns = np.zeros((n_days, 2))
market_status = [] # 记录市场状态用于验证
for t in range(n_days):
# 模拟随机冲击
shock = np.random.normal(0, 1, 2)
correlated_shock = L @ shock
# 人为制造"熊市"冲击 (在第300-450天模拟股灾)
if 300 < t < 450:
# 股票暴跌,债券因避险上涨
current_mu = np.array([-0.30, 0.08])
market_status.append('熊市')
else:
current_mu = mu
market_status.append('牛市/震荡')
returns[t] = current_mu * dt + correlated_shock * np.sqrt(dt)
dates = pd.date_range('2020-01-01', periods=n_days, freq='B')
df = pd.DataFrame(returns, index=dates, columns=['股票', '债券'])
return df
def run_risk_parity_strategy(returns, lookback=60):
"""极简风险平价策略:倒数波动率加权"""
# 1. 计算滚动波动率
rolling_vol = returns.rolling(window=lookback).std()
# 2. 计算风险平价权重 (权重 = 1 / 波动率)
inv_vol = 1.0 / rolling_vol
# 3. 归一化权重
rp_weights = inv_vol.div(inv_vol.sum(axis=1), axis=0)
# 4. 滞后一期应用权重
rp_weights = rp_weights.shift(1).dropna()
# 5. 计算策略收益
# 对应日期的收益 * 对应日期的权重
strategy_ret = (returns.loc[rp_weights.index] * rp_weights).sum(axis=1)
return strategy_ret, rp_weights
def calculate_metrics(series, name):
"""计算核心评价指标"""
total_ret = (1 + series).prod() - 1
ann_ret = (1 + series).prod() ** (252/len(series)) - 1
ann_vol = series.std() * np.sqrt(252)
sharpe = (ann_ret - 0.02) / ann_vol # 假设无风险利率2%
# 最大回撤
cum = (1 + series).cumprod()
dd = (cum / cum.cummax()) - 1
max_dd = dd.min()
return {
'策略': name,
'年化收益': f"{ann_ret:.1%}",
'年化波动': f"{ann_vol:.1%}",
'夏普比率': f"{sharpe:.2f}",
'最大回撤': f"{max_dd:.1%}"
}
# --- 主程序 ---
# 1. 获取数据
df_returns = generate_market_data()
# 2. 运行不同策略
# 风险平价
rp_ret, rp_weights = run_risk_parity_strategy(df_returns)
# 对比基准
stock_ret = df_returns['股票'].loc[rp_ret.index]
bond_ret = df_returns['债券'].loc[rp_ret.index]
combo_ret = stock_ret * 0.6 + bond_ret * 0.4 # 传统的60/40组合
# 3. 计算净值曲线
cum_rp = (1 + rp_ret).cumprod()
cum_stock = (1 + stock_ret).cumprod()
cum_bond = (1 + bond_ret).cumprod()
cum_6040 = (1 + combo_ret).cumprod()
# 4. 打印指标
metrics = [
calculate_metrics(stock_ret, "纯股票"),
calculate_metrics(bond_ret, "纯债券"),
calculate_metrics(combo_ret, "股债60/40"),
calculate_metrics(rp_ret, "★ 风险平价 (RP)"),
]
print(pd.DataFrame(metrics))
# 5. 绘图
plt.figure(figsize=(14, 8))
# 子图1:累计收益
ax1 = plt.subplot(2, 1, 1)
ax1.plot(cum_stock, label='纯股票 (高波高回撤)', color='gray', alpha=0.5, linestyle='--')
ax1.plot(cum_bond, label='纯债券 (低波低收益)', color='blue', alpha=0.6, linestyle=':')
ax1.plot(cum_rp, label='风险平价 (稳健增长)', color='#d62728', linewidth=2.5)
ax1.plot(cum_6040, label='60/40组合', color='green', alpha=0.6)
# 标记熊市区域
ax1.axvspan(df_returns.index[300], df_returns.index[450], color='gray', alpha=0.2, label='熊市区间')
ax1.set_title('策略累计收益对比:风险平价穿越牛熊', fontsize=14, fontweight='bold')
ax1.legend(loc='upper left')
# 子图2:动态权重变化
ax2 = plt.subplot(2, 1, 2)
ax2.stackplot(rp_weights.index, rp_weights['股票'], rp_weights['债券'],
labels=['股票权重', '债券权重'], colors=['#ff7f0e', '#1f77b4'], alpha=0.8)
ax2.set_title('风险平价策略的动态仓位调整', fontsize=12)
ax2.set_ylabel('资产权重')
ax2.legend(loc='center left')
plt.tight_layout()
plt.show()可以看到,风险平价策略波动率极低,收益在熊市期间(灰色区域)的表现也非常稳健,这与传统股票策略以及60/40组合策略形成了鲜明对比。
世界上没有完美的预测,只有完美的应对。
无论是生物体的进化,还是大模型的训练,亦或是量化投资组合的构建,本质上都是在不确定性中寻找最优解。风险平价模型并不追求在牛市中跑得最快,它追求的是在暴风雨中活得最久。
如果你也是正在探索AI+金融,或者对复杂系统建模感兴趣的朋友,欢迎在评论区留言。也许下一次,我们可以聊聊AI时代如何优化并设计更好的投资策略,让经典的资产配置模型进化成真正的“赛博投资专家”。
我是赛博解生酱,我们下期见!
接下来赛博酱准备采用真实的数据对风险平价模型进行回测,并比较不同改进版本在A股市场中的表现,欢迎大家在评论区分享自己的经验和发现。如果你对Black-Litterman模型感兴趣,欢迎阅读我的另一篇公众号文章资产配置Black Litterman模型从入门到实践。