风险预算模型:超越风险平价的资产配置新范式#
引言#
在现代投资组合理论中,资产配置一直是核心问题。从Markowitz的均值方差优化到风险平价策略,资产配置方法不断演进。风险预算(Risk Budgeting)模型作为一种更灵活的资产配置框架,允许投资者根据对风险的看法和偏好,主动分配各资产的风险贡献。
本文将深入探讨风险预算模型的理论基础、实现方法和实战应用,帮助你构建更灵活、更有效的资产配置策略。
一、从风险平价到风险预算#
1.1 风险平价回顾#
风险平价(Risk Parity)的核心思想是让组合中每个资产对总风险的贡献相等。例如,在一个包含股票和债券的组合中,股票的风险贡献可能占90%,债券只占10%。风险平价策略通过调整权重,使两者的风险贡献相等(各50%)。
风险平价的优点:
- 分散化:避免单一资产主导组合风险
- 稳健性:在不同市场环境下表现相对稳定
- 简单性:不需要预期收益率输入
风险平价的局限性:
- 过于被动:所有资产的风险贡献必须相等,缺乏灵活性
- 忽略收益预期:完全不考虑资产的预期收益率
- 对波动率假设敏感:依赖波动率估计的准确性
1.2 风险预算的概念#
风险预算是对风险平价的推广。在风险预算框架下,投资者可以:
- 主动分配风险:根据对资产的看法,分配不同的风险预算
- 融合收益预期:可以结合预期收益率进行优化
- 灵活调整:根据市场环境和投资目标动态调整
风险预算 vs 风险平价:
| 特性 | 风险平价 | 风险预算 |
|---|---|---|
| 风险贡献 | 必须相等 | 可以自定义 |
| 收益预期 | 不考虑 | 可以考虑 |
| 灵活性 | 低 | 高 |
| 适用场景 | 稳健型组合 | 各类投资目标 |
二、风险预算模型的理论基础#
2.1 风险贡献分解#
风险预算的核心是**风险贡献(Risk Contribution, RC)**的分解。对于一个投资组合,总风险(通常用波动率或VaR表示)可以分解为各资产的风险贡献。
波动率风险评估:
假设组合权重向量为 ,资产收益率协方差矩阵为 ,则组合波动率为:
根据Euler定理,总风险可以分解为各资产的风险贡献:
其中,资产 的风险贡献为:
风险贡献的百分比:
2.2 风险预算优化问题#
在风险预算模型中,我们设定每个资产的目标风险贡献比例 (满足 ),然后寻找权重 ,使得实际风险贡献比例等于目标比例:
这是一个非线性方程组,通常需要通过数值方法求解。
数学形式:
定义目标函数:
我们需要最小化 ,同时满足权重约束(如 , )。
2.3 与均值方差优化的关系#
风险预算可以视为均值方差优化的一种特殊形式:
- 当所有资产的风险预算相等时,风险预算等价于风险平价
- 当加入预期收益率,并求解均值-风险优化时,风险预算可以融合收益观点
- 风险预算避免了均值方差优化对预期收益率的过度敏感
三、风险预算模型的Python实现#
3.1 计算风险贡献#
import numpy as np
import pandas as pd
from scipy.optimize import minimize
import matplotlib.pyplot as plt
import seaborn as sns
def calculate_portfolio_risk(weights, cov_matrix):
"""
计算组合波动率
Args:
weights: 权重向量 (n,)
cov_matrix: 协方差矩阵 (n, n)
Returns:
portfolio_variance: 组合方差
portfolio_volatility: 组合波动率
"""
portfolio_variance = np.dot(weights.T, np.dot(cov_matrix, weights))
portfolio_volatility = np.sqrt(portfolio_variance)
return portfolio_variance, portfolio_volatility
def calculate_risk_contribution(weights, cov_matrix):
"""
计算各资产的风险贡献
Args:
weights: 权重向量 (n,)
cov_matrix: 协方差矩阵 (n, n)
Returns:
rc: 风险贡献向量 (n,)
rc_pct: 风险贡献百分比 (n,)
"""
# 计算组合波动率
_, portfolio_vol = calculate_portfolio_risk(weights, cov_matrix)
# 计算边际风险贡献
marginal_rc = np.dot(cov_matrix, weights) / portfolio_vol
# 计算风险贡献
rc = weights * marginal_rc
# 计算风险贡献百分比
rc_pct = rc / np.sum(rc)
return rc, rc_pct
# 示例使用
if __name__ == "__main__":
# 假设有3个资产
n_assets = 3
# 模拟协方差矩阵
np.random.seed(42)
returns = np.random.randn(1000, n_assets) * 0.01
cov_matrix = np.cov(returns.T)
# 等权重组合
weights = np.ones(n_assets) / n_assets
# 计算风险贡献
rc, rc_pct = calculate_risk_contribution(weights, cov_matrix)
print("等权重组合的风险贡献:")
for i in range(n_assets):
print(f" 资产{i+1}: {rc[i]:.6f} ({rc_pct[i]:.2%})")python3.2 风险预算优化求解#
def risk_budget_objective(weights, cov_matrix, risk_budget):
"""
风险预算优化的目标函数
Args:
weights: 权重向量 (n,)
cov_matrix: 协方差矩阵 (n, n)
risk_budget: 目标风险预算向量 (n,) ,满足 sum(risk_budget) = 1
Returns:
objective: 目标函数值
"""
# 计算实际风险贡献
rc, rc_pct = calculate_risk_contribution(weights, cov_matrix)
# 计算与目标风险预算的偏差
deviation = rc_pct - risk_budget
# 使用平方和作为目标函数
objective = np.sum(deviation ** 2)
return objective
def risk_budget_optimization(cov_matrix, risk_budget, constraints=None, bounds=None):
"""
风险预算优化求解
Args:
cov_matrix: 协方差矩阵 (n, n)
risk_budget: 目标风险预算向量 (n,)
constraints: 约束条件(如权重和为1)
bounds: 变量边界(如权重非负)
Returns:
optimal_weights: 最优权重向量
"""
n_assets = cov_matrix.shape[0]
# 默认约束:权重和为1
if constraints is None:
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1.0})
# 默认边界:权重在0到1之间
if bounds is None:
bounds = tuple((0, 1) for _ in range(n_assets))
# 初始猜测:等权重
initial_weights = np.ones(n_assets) / n_assets
# 优化求解
result = minimize(
fun=risk_budget_objective,
x0=initial_weights,
args=(cov_matrix, risk_budget),
method='SLSQP',
bounds=bounds,
constraints=constraints,
options={'ftol': 1e-9, 'disp': False}
)
if not result.success:
print("优化未收敛!")
print(result.message)
return result.x
# 示例使用
if __name__ == "__main__":
# 设定风险预算
risk_budget = np.array([0.5, 0.3, 0.2]) # 资产1: 50%, 资产2: 30%, 资产3: 20%
# 优化求解
optimal_weights = risk_budget_optimization(cov_matrix, risk_budget)
print("\n风险预算优化的结果:")
print(f"最优权重:{optimal_weights}")
print(f"权重和:{np.sum(optimal_weights):.6f}")
# 验证风险贡献
rc, rc_pct = calculate_risk_contribution(optimal_weights, cov_matrix)
print("\n实际风险贡献:")
for i in range(n_assets):
print(f" 资产{i+1}: {rc_pct[i]:.2%} (目标: {risk_budget[i]:.2%})")python3.3 加入收益预期的扩展#
风险预算模型可以扩展为均值-风险预算优化,融合收益预期:
def mean_risk_budget_objective(weights, cov_matrix, expected_returns, risk_budget,
risk_aversion=1.0, rc_penalty=100.0):
"""
均值-风险预算优化的目标函数
Args:
weights: 权重向量
cov_matrix: 协方差矩阵
expected_returns: 预期收益率向量
risk_budget: 目标风险预算
risk_aversion: 风险厌恶系数
rc_penalty: 风险贡献偏差的惩罚系数
Returns:
objective: 目标函数值(最大化效用 = 收益 - 风险厌恶 * 风险 - 惩罚项)
"""
# 计算组合收益率
portfolio_return = np.dot(weights, expected_returns)
# 计算组合风险
_, portfolio_vol = calculate_portfolio_risk(weights, cov_matrix)
# 计算风险贡献偏差
rc, rc_pct = calculate_risk_contribution(weights, cov_matrix)
rc_deviation = np.sum((rc_pct - risk_budget) ** 2)
# 效用函数 = 收益 - 风险厌恶 * 风险 - 惩罚项
utility = portfolio_return - risk_aversion * portfolio_vol - rc_penalty * rc_deviation
# 返回负效用(因为scipy.optimize.minimize是最小化)
return -utility
def mean_risk_budget_optimization(cov_matrix, expected_returns, risk_budget,
risk_aversion=1.0, constraints=None, bounds=None):
"""
均值-风险预算优化求解
"""
n_assets = cov_matrix.shape[0]
if constraints is None:
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1.0})
if bounds is None:
bounds = tuple((0, 1) for _ in range(n_assets))
initial_weights = np.ones(n_assets) / n_assets
result = minimize(
fun=mean_risk_budget_objective,
x0=initial_weights,
args=(cov_matrix, expected_returns, risk_budget, risk_aversion, 100.0),
method='SLSQP',
bounds=bounds,
constraints=constraints,
options={'ftol': 1e-9, 'disp': False}
)
if not result.success:
print("优化未收敛!")
print(result.message)
return result.xpython四、实战案例:多资产组合的风险预算配置#
4.1 数据准备#
我们使用真实的资产数据来构建风险预算组合。选择以下资产:
- 股票:沪深300指数(000300.SH)
- 债券:中债10年期国债指数
- 商品:南华商品指数
- 现金:货币基金(或短期国债)
import tushare as ts
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# 设置tushare token
ts.set_token('your_tushare_token')
pro = ts.pro_api()
def load_asset_data(start_date='20180101', end_date='20231231'):
"""
加载多资产数据
Returns:
returns_df: 收益率DataFrame
prices_df: 价格DataFrame
"""
# 资产代码
assets = {
'stock': '000300.SH', # 沪深300
'bond': '000012.SH', # 上证国债指数
'commodity': 'NH0100.NH', # 南华商品指数
'cash': '000300.SH' # 暂时用股票替代,实际应使用权债或货币基金
}
returns_dict = {}
prices_dict = {}
for asset_name, asset_code in assets.items():
# 获取日线数据
if asset_code.endswith('.SH') or asset_code.endswith('.SZ'):
df = pro.index_daily(ts_code=asset_code, start_date=start_date, end_date=end_date)
else:
# 对于商品指数,可能需要其他数据源
print(f"警告:{asset_name} 数据源未配置")
continue
# 按日期升序排列
df = df.sort_values('trade_date')
# 计算收益率
df['return'] = df['close'].pct_change()
# 存储
returns_dict[asset_name] = df.set_index('trade_date')['return']
prices_dict[asset_name] = df.set_index('trade_date')['close']
# 合并数据
returns_df = pd.DataFrame(returns_dict).dropna()
prices_df = pd.DataFrame(prices_dict).dropna()
return returns_df, prices_df
# 加载数据
returns_df, prices_df = load_asset_data()
print("资产收益率数据:")
print(returns_df.head())
print(f"\n数据期间:{returns_df.index[0]} 至 {returns_df.index[-1]}")
print(f"数据条数:{len(returns_df)}")python4.2 计算协方差矩阵#
def calculate_cov_matrix(returns_df, method='sample', shrinkage_intensity=0.5):
"""
计算收益率协方差矩阵
Args:
returns_df: 收益率DataFrame
method: 计算方法 ('sample', 'shrinkage', 'ewma')
shrinkage_intensity: 收缩强度(仅shrinkage方法)
Returns:
cov_matrix: 协方差矩阵
"""
if method == 'sample':
# 简单样本协方差
cov_matrix = returns_df.cov() * 252 # 年化
elif method == 'shrinkage':
# 收缩估计(Ledoit-Wolf)
sample_cov = returns_df.cov() * 252
# 目标矩阵:对角矩阵,对角线元素为样本协方差的均值
target = np.diag(np.diag(sample_cov))
# 收缩
cov_matrix = (1 - shrinkage_intensity) * sample_cov + shrinkage_intensity * target
cov_matrix = pd.DataFrame(
cov_matrix,
index=returns_df.columns,
columns=returns_df.columns
)
elif method == 'ewma':
# 指数加权移动平均
ewma_cov = returns_df.ewm(span=60).cov() * 252
cov_matrix = ewma_cov.groupby(level=1).tail(1).droplevel(1)
else:
raise ValueError(f"不支持的方法:{method}")
return cov_matrix
# 计算协方差矩阵
cov_matrix = calculate_cov_matrix(returns_df, method='shrinkage', shrinkage_intensity=0.3)
print("\n年化协方差矩阵:")
print(cov_matrix)python4.3 不同风险预算方案的比较#
def compare_risk_budget_schemes(returns_df, cov_matrix):
"""
比较不同的风险预算方案
"""
asset_names = returns_df.columns.tolist()
n_assets = len(asset_names)
# 定义不同的风险预算方案
schemes = {
'风险平价': np.ones(n_assets) / n_assets, # 等风险贡献
'偏股票': np.array([0.6, 0.2, 0.15, 0.05]), # 股票占60%风险
'偏债券': np.array([0.2, 0.6, 0.15, 0.05]), # 债券占60%风险
'保守型': np.array([0.3, 0.3, 0.2, 0.2]), # 较均匀分配
'激进型': np.array([0.7, 0.1, 0.15, 0.05]), # 股票占70%风险
}
results = []
for scheme_name, risk_budget in schemes.items():
# 优化求解
weights = risk_budget_optimization(cov_matrix.values, risk_budget)
# 计算组合指标
portfolio_return = np.dot(weights, returns_df.mean()) * 252 # 年化收益率
_, portfolio_vol = calculate_portfolio_risk(weights, cov_matrix.values)
sharpe_ratio = portfolio_return / portfolio_vol if portfolio_vol > 0 else 0
# 计算实际风险贡献
rc, rc_pct = calculate_risk_contribution(weights, cov_matrix.values)
# 存储结果
result = {
'方案': scheme_name,
'权重': weights,
'年化收益率': portfolio_return,
'年化波动率': portfolio_vol,
'夏普比率': sharpe_ratio,
'风险贡献': rc_pct
}
results.append(result)
# 打印结果
print(f"\n{scheme_name}方案:")
for i, asset in enumerate(asset_names):
print(f" {asset}: 权重={weights[i]:.2%}, 风险贡献={rc_pct[i]:.2%}")
print(f" 组合年化收益率:{portfolio_return:.2%}")
print(f" 组合年化波动率:{portfolio_vol:.2%}")
print(f" 夏普比率:{sharpe_ratio:.4f}")
return results
# 比较不同方案
results = compare_risk_budget_schemes(returns_df, cov_matrix)python4.4 可视化分析#
def visualize_risk_budget_results(results, save_path='risk_budget_comparison.png'):
"""
可视化不同风险预算方案的结果
"""
n_schemes = len(results)
asset_names = ['stock', 'bond', 'commodity', 'cash'] # 根据实际资产调整
# 创建子图
fig, axes = plt.subplots(2, 2, figsize=(16, 12))
# 1. 权重对比
ax1 = axes[0, 0]
weights_matrix = np.array([r['权重'] for r in results]).T
x = np.arange(len(results))
width = 0.2
for i, asset in enumerate(asset_names):
ax1.bar(x + i*width, weights_matrix[i, :], width, label=asset)
ax1.set_xlabel('风险预算方案')
ax1.set_ylabel('权重')
ax1.set_title('各方案权重对比')
ax1.set_xticks(x + width * (len(asset_names)-1) / 2)
ax1.set_xticklabels([r['方案'] for r in results], rotation=45)
ax1.legend()
ax1.grid(True, alpha=0.3)
# 2. 风险贡献对比
ax2 = axes[0, 1]
rc_matrix = np.array([r['风险贡献'] for r in results]).T
for i, asset in enumerate(asset_names):
ax2.bar(x + i*width, rc_matrix[i, :], width, label=asset)
ax2.set_xlabel('风险预算方案')
ax2.set_ylabel('风险贡献')
ax2.set_title('各方案风险贡献对比')
ax2.set_xticks(x + width * (len(asset_names)-1) / 2)
ax2.set_xticklabels([r['方案'] for r in results], rotation=45)
ax2.legend()
ax2.grid(True, alpha=0.3)
# 3. 收益率-风险散点图
ax3 = axes[1, 0]
returns = [r['年化收益率'] for r in results]
volatilities = [r['年化波动率'] for r in results]
sharpe_ratios = [r['夏普比率'] for r in results]
scatter = ax3.scatter(volatilities, returns, c=sharpe_ratios, s=100, cmap='viridis')
for i, result in enumerate(results):
ax3.annotate(result['方案'], (volatilities[i], returns[i]), fontsize=9)
ax3.set_xlabel('年化波动率')
ax3.set_ylabel('年化收益率')
ax3.set_title('风险-收益特征')
ax3.grid(True, alpha=0.3)
plt.colorbar(scatter, ax=ax3, label='夏普比率')
# 4. 夏普比率对比
ax4 = axes[1, 1]
scheme_names = [r['方案'] for r in results]
sharpe_values = [r['夏普比率'] for r in results]
bars = ax4.bar(scheme_names, sharpe_values, color='skyblue', edgecolor='black')
ax4.set_xlabel('风险预算方案')
ax4.set_ylabel('夏普比率')
ax4.set_title('各方案夏普比率对比')
ax4.set_xticklabels(scheme_names, rotation=45)
ax4.grid(True, alpha=0.3)
# 在柱子上标注数值
for bar, value in zip(bars, sharpe_values):
height = bar.get_height()
ax4.text(bar.get_x() + bar.get_width()/2., height,
f'{value:.4f}', ha='center', va='bottom')
plt.tight_layout()
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.close()
print(f"可视化结果已保存至:{save_path}")
# 生成可视化
visualize_risk_budget_results(results)python五、动态风险预算策略#
5.1 时变风险预算#
市场环境变化时,风险预算也应动态调整。以下是几种常见的动态调整方法:
- 基于波动率的调整:当某资产波动率上升时,降低其风险预算
- 基于相关性的调整:当资产间相关性上升时,降低其共同风险预算
- 基于宏观状态的调整:根据经济周期(增长、通胀、衰退等)调整风险预算
- 基于风险预警的调整:当市场风险预警指标触发时,降低风险资产预算
实现示例:基于波动率的动态风险预算
def dynamic_risk_budget_volatility(returns_df, lookback_period=60, decay_factor=0.9):
"""
基于波动率的动态风险预算
Args:
returns_df: 收益率DataFrame
lookback_period: 滚动窗口长度
decay_factor: 衰减因子(用于EWMA波动率)
Returns:
dynamic_budgets: 动态风险预算DataFrame
"""
n_assets = returns_df.shape[1]
asset_names = returns_df.columns.tolist()
# 计算滚动波动率
rolling_vol = returns_df.rolling(window=lookback_period).std() * np.sqrt(252)
# 使用EWMA平滑波动率
ewma_vol = returns_df.ewm(alpha=1-decay_factor).std() * np.sqrt(252)
# 风险预算与波动率成反比(波动率越高,分配的风险预算越低)
# 使用softmax函数将风险预算归一化
inverse_vol = 1 / ewma_vol
dynamic_budgets = inverse_vol.div(inverse_vol.sum(axis=1), axis=0)
return dynamic_budgets.dropna()
def backtest_dynamic_risk_budget(returns_df, cov_matrix, dynamic_budgets, initial_capital=1000000):
"""
回测动态风险预算策略
Args:
returns_df: 收益率DataFrame
cov_matrix: 协方差矩阵(可以使用滚动协方差)
dynamic_budgets: 动态风险预算DataFrame
initial_capital: 初始资金
Returns:
portfolio_values: 组合价值序列
weights_history: 权重历史
"""
dates = dynamic_budgets.index
n_dates = len(dates)
portfolio_values = [initial_capital]
weights_history = []
for i in range(1, n_dates):
current_date = dates[i]
prev_date = dates[i-1]
# 获取当前风险预算
current_budget = dynamic_budgets.loc[current_date].values
# 重新优化权重(使用滚动协方差矩阵)
# 注意:这里简化为使用固定协方差矩阵,实际应使用滚动窗口估计
optimal_weights = risk_budget_optimization(cov_matrix.values, current_budget)
weights_history.append(optimal_weights)
# 计算当日收益率
daily_returns = returns_df.loc[current_date].values
portfolio_return = np.dot(optimal_weights, daily_returns)
# 更新组合价值
new_value = portfolio_values[-1] * (1 + portfolio_return)
portfolio_values.append(new_value)
return portfolio_values, weights_history
# 示例使用
dynamic_budgets = dynamic_risk_budget_volatility(returns_df, lookback_period=60)
# 回测
portfolio_values, weights_history = backtest_dynamic_risk_budget(
returns_df, cov_matrix, dynamic_budgets
)
print(f"\n动态风险预算策略回测结果:")
print(f"初始资金:{1000000:.2f}")
print(f"最终资金:{portfolio_values[-1]:.2f}")
print(f"总收益率:{(portfolio_values[-1]/portfolio_values[0]-1):.2%}")python5.2 风险预算与Black-Litterman结合#
Black-Litterman模型允许投资者将主观观点融入资产配置。将风险预算与Black-Litterman结合,可以同时体现风险偏好和收益观点。
def black_litterman_optimization(returns_df, cov_matrix, risk_budget,
views=None, view_confidence=None,
tau=0.05, risk_aversion=2.5):
"""
Black-Litterman + 风险预算优化
Args:
returns_df: 收益率DataFrame
cov_matrix: 协方差矩阵
risk_budget: 风险预算向量
views: 投资者观点矩阵 (k, n),k个观点,n个资产
view_confidence: 观点置信度向量 (k,)
tau: 尺度参数
risk_aversion: 风险厌恶系数
Returns:
optimal_weights: 最优权重
"""
n_assets = cov_matrix.shape[0]
# 1. 计算市场均衡组合(使用风险平价作为基准)
market_weights = risk_budget_optimization(cov_matrix.values, np.ones(n_assets)/n_assets)
# 2. 计算均衡预期收益率
equilibrium_returns = risk_aversion * np.dot(cov_matrix.values, market_weights)
# 3. 如果有观点,调整预期收益率
if views is not None and view_confidence is not None:
# 观点不确定性矩阵
omega = np.diag(1 / view_confidence)
# Black-Litterman公式
M_inv = np.linalg.inv(tau * cov_matrix.values)
views_array = np.array(views)
# 调整后预期收益率
post_cov = np.linalg.inv(M_inv + views_array.T @ np.linalg.inv(omega) @ views_array)
post_returns = post_cov @ (M_inv @ equilibrium_returns +
views_array.T @ np.linalg.inv(omega) @ views_array @ equilibrium_returns)
else:
post_returns = equilibrium_returns
post_cov = cov_matrix.values
# 4. 结合风险预算进行优化
optimal_weights = mean_risk_budget_optimization(
post_cov, post_returns, risk_budget, risk_aversion
)
return optimal_weights
# 示例使用(假设有一个观点:股票收益率将超额2%)
views = [[1, 0, 0, 0]] # 第一个资产(股票)有超额收益
view_confidence = [0.5] # 观点置信度50%
optimal_weights_bl = black_litterman_optimization(
returns_df, cov_matrix,
risk_budget=np.array([0.4, 0.3, 0.2, 0.1]),
views=views,
view_confidence=view_confidence
)
print("\nBlack-Litterman + 风险预算优化结果:")
for i, asset in enumerate(returns_df.columns):
print(f" {asset}: 权重={optimal_weights_bl[i]:.2%}")python六、风险预算模型的实际应用考虑#
6.1 估计误差的影响#
风险预算模型依赖协方差矩阵的估计,而估计误差会显著影响结果。
应对策略:
- 使用稳健的协方差估计方法:如Ledoit-Wolf收缩估计
- 增加约束:限制权重范围,避免过度集中
- 敏感性分析:测试不同协方差估计方法下的权重稳定性
def sensitivity_analysis_cov(returns_df, risk_budget, n_bootstrap=100):
"""
协方差估计的敏感性分析(Bootstrap方法)
"""
n_assets = returns_df.shape[1]
weights_samples = []
for i in range(n_bootstrap):
# Bootstrap重采样
sampled_returns = returns_df.sample(n=len(returns_df), replace=True)
sampled_cov = sampled_returns.cov() * 252
# 优化
weights = risk_budget_optimization(sampled_cov.values, risk_budget)
weights_samples.append(weights)
weights_samples = np.array(weights_samples)
# 统计
weights_mean = weights_samples.mean(axis=0)
weights_std = weights_samples.std(axis=0)
print("\n协方差估计敏感性分析(Bootstrap):")
for i, asset in enumerate(returns_df.columns):
print(f" {asset}: 平均权重={weights_mean[i]:.2%}, 标准差={weights_std[i]:.2%}")
return weights_samplespython6.2 交易成本与再平衡#
风险预算组合需要定期再平衡,以保持风险贡献符合目标。
再平衡策略:
- 日历再平衡:固定时间间隔(如每月、每季度)
- 阈值再平衡:当权重偏离超过阈值时触发
- 混合策略:结合时间和阈值
def rebalance_strategy(portfolio_values, weights_history, returns_df,
rebalance_freq='M', threshold=0.05):
"""
再平衡策略模拟
Args:
portfolio_values: 组合价值序列
weights_history: 权重历史
returns_df: 收益率数据
rebalance_freq: 再平衡频率('M': 每月, 'Q': 每季度)
threshold: 权重偏离阈值
Returns:
rebalanced_values: 再平衡后的组合价值
rebalance_times: 再平衡次数
"""
# 这里简化实现,实际应考虑交易成本和滑点
rebalanced_values = portfolio_values.copy()
rebalance_times = 0
# 日历再平衡
if rebalance_freq == 'M':
# 每月第一个交易日再平衡
for i in range(1, len(portfolio_values)):
if i % 20 == 0: # 假设每月20个交易日
rebalance_times += 1
# 重置权重(这里简化为不调整)
# 阈值再平衡
for i in range(1, len(weights_history)):
if i < len(weights_history) - 1:
weight_deviation = np.abs(weights_history[i] - weights_history[i-1])
if np.any(weight_deviation > threshold):
rebalance_times += 1
print(f"\n再平衡次数:{rebalance_times}")
return rebalanced_values, rebalance_timespython6.3 风险预算与因子投资#
风险预算可以应用于因子层面,构建因子风险预算组合。
实现步骤:
- 识别组合的主要风险因子(如市场、规模、价值、动量等)
- 计算资产对因子的暴露
- 设定因子的风险预算
- 优化资产权重,使因子的风险贡献符合预算
def factor_risk_budget_optimization(asset_returns, factor_returns, factor_exposures, factor_risk_budget):
"""
因子风险预算优化
Args:
asset_returns: 资产收益率 (T, n)
factor_returns: 因子收益率 (T, k)
factor_exposures: 资产对因子的暴露 (n, k)
factor_risk_budget: 因子的风险预算 (k,)
Returns:
optimal_weights: 最优资产权重
"""
# 计算因子协方差矩阵
factor_cov = np.cov(factor_returns.T)
# 计算资产协方差矩阵(通过因子模型)
asset_cov = factor_exposures @ factor_cov @ factor_exposures.T
# 优化:使因子的风险贡献符合预算
# 这里需要定义因子风险贡献的计算方式
# 简化:直接优化资产权重,使组合在因子上的暴露符合预算
n_assets = asset_returns.shape[1]
def objective(weights):
# 计算组合因子暴露
portfolio_factor_exposure = weights @ factor_exposures
# 计算因子风险贡献(简化:使用因子波动率加权暴露)
factor_risk_contrib = portfolio_factor_exposure * np.diag(factor_cov)
factor_risk_contrib = factor_risk_contrib / np.sum(factor_risk_contrib)
# 与目标预算的偏差
deviation = factor_risk_contrib - factor_risk_budget
return np.sum(deviation ** 2)
# 约束:权重和为1,非负
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1.0})
bounds = tuple((0, 1) for _ in range(n_assets))
initial_weights = np.ones(n_assets) / n_assets
result = minimize(objective, initial_weights, method='SLSQP',
bounds=bounds, constraints=constraints)
return result.xpython七、总结#
风险预算模型提供了一种灵活、直观的资产配置框架,它既继承了风险平价的分散化理念,又允许投资者根据主观判断和市场环境动态调整。
核心要点:
- 理论基础:基于风险贡献的分解,通过数值优化求解满足目标风险预算的权重
- 实现方法:使用SciPy等优化库求解非线性方程组
- 扩展到收益:可以融合预期收益率,实现均值-风险预算优化
- 动态调整:根据市场状态动态调整风险预算,提高策略适应性
- 结合实际:考虑估计误差、交易成本、再平衡频率等实际问题
未来方向:
- 高频数据应用:将风险预算应用于日内资产配置
- 机器学习融合:使用机器学习预测最优风险预算
- 多目标优化:同时优化多个目标(收益、风险、ESG等)
- 实时优化:构建实时风险预算系统,支持快速决策
风险预算模型为资产配置提供了一个强大的工具,但其成功应用离不开对市场的深刻理解、对风险的准确度量,以及严格的纪律执行。
免责声明:本文所有策略、代码和案例仅用于学术交流,不构成任何投资建议。投资有风险,决策需谨慎。
参考文献#
- Qian, E. (2005). “Risk Parity Portfolios: Efficient Portfolios Through True Diversification”. Panagora Asset Management.
- Maillard, S., Roncalli, T., & Teïletche, J. (2010). “The Properties of Equally Weighted Risk Contribution Portfolios”. The Journal of Portfolio Management.
- Roncalli, T. (2013). “Introduction to Risk Parity and Budgeting”. Chapman and Hall/CRC.
- Ang, A. (2014). “Asset Management: A Systematic Approach to Factor Investing”. Oxford University Press.
- Kolm, P. N., & Ritter, G. (2016). “Dynamic Risk Budgeting for Portfolios”. Journal of Investment Management.