1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
| import pandas as pd import numpy as np import statsmodels.api as sm import matplotlib.pyplot as plt import matplotlib.dates as mdates from matplotlib.ticker import PercentFormatter
# 1. 数据准备 # 假设asset_df包含四只股票的月度收益率,列为['AAPL', 'AMZN', 'GOOG', 'MSFT'] # 假设factors包含三因子数据,列为['MKT-RF', 'SMB', 'HML', 'RF']
# 计算等权重投资组合的月度收益率 portfolio_return = asset_df.mean(axis=1) # 25%等权重组合 portfolio_return.name = 'Portfolio'
# 合并因子数据 full_data = pd.concat([portfolio_return, factors], axis=1).dropna()
# 计算投资组合超额收益 full_data['Portfolio_Excess'] = full_data['Portfolio'] - full_data['RF']
# 2. 滚动三因子模型 WINDOW_SIZE = 36 # 3年滚动窗口 dates = [] alphas = [] betas_mkt = [] betas_smb = [] betas_hml = [] r_squared = []
print("开始滚动三因子模型估计...") for i in range(WINDOW_SIZE, len(full_data)): # 获取当前窗口数据 window_data = full_data.iloc[i-WINDOW_SIZE:i] # 准备回归数据 X = window_data[['Mkt-RF', 'SMB', 'HML']] X = sm.add_constant(X) # 添加截距项 y = window_data['Portfolio_Excess'] # 拟合三因子模型 model = sm.OLS(y, X).fit() # 存储结果 dates.append(full_data.index[i]) alphas.append(model.params['const']) betas_mkt.append(model.params['Mkt-RF']) betas_smb.append(model.params['SMB']) betas_hml.append(model.params['HML']) r_squared.append(model.rsquared)
# 创建结果DataFrame results = pd.DataFrame({ 'Date': dates, 'Alpha': alphas, 'Beta_Mkt': betas_mkt, 'Beta_SMB': betas_smb, 'Beta_HML': betas_hml, 'R_squared': r_squared }).set_index('Date')
# 3. 可视化结果 plt.figure(figsize=(15, 12))
# 3.1 Alpha系数变化 plt.subplot(3, 1, 1) plt.plot(results.index, results['Alpha'], 'b-', lw=1.5) plt.fill_between(results.index, results['Alpha'], 0, where=(results['Alpha'] > 0), facecolor='green', alpha=0.2) plt.fill_between(results.index, results['Alpha'], 0, where=(results['Alpha'] < 0), facecolor='red', alpha=0.2) plt.axhline(0, color='black', linestyle='--', lw=0.8) plt.title('投资组合Alpha系数变化 (滚动36个月)', fontsize=14) plt.ylabel('Alpha (%)', fontsize=12) plt.gca().yaxis.set_major_formatter(PercentFormatter(1.0)) # 转换为百分比格式 plt.grid(alpha=0.3)
# 3.2 Beta系数变化 plt.subplot(3, 1, 2) plt.plot(results.index, results['Beta_Mkt'], 'b-', label='市场风险(Beta_Mkt)', lw=1.5) plt.plot(results.index, results['Beta_SMB'], 'g-', label='规模因子(Beta_SMB)', lw=1.5) plt.plot(results.index, results['Beta_HML'], 'r-', label='价值因子(Beta_HML)', lw=1.5) plt.axhline(1, color='black', linestyle='--', lw=0.8) plt.title('因子暴露变化', fontsize=14) plt.ylabel('Beta系数', fontsize=12) plt.legend(loc='best') plt.grid(alpha=0.3)
# 3.3 R²变化 plt.subplot(3, 1, 3) plt.plot(results.index, results['R_squared'], 'purple', lw=1.5) plt.title('模型解释力变化 (R²)', fontsize=14) plt.ylabel('R²', fontsize=12) plt.ylim(0, 1) plt.grid(alpha=0.3)
# 设置x轴日期格式 for ax in plt.gcf().axes: ax.xaxis.set_major_locator(mdates.YearLocator()) ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y')) plt.setp(ax.xaxis.get_majorticklabels(), rotation=45)
plt.tight_layout() plt.savefig('rolling_three_factor_model.png', dpi=300) plt.show()
# 4. 最终模型结果(使用全部数据) X_full = full_data[['Mkt-RF', 'SMB', 'HML']] X_full = sm.add_constant(X_full) y_full = full_data['Portfolio_Excess']
final_model = sm.OLS(y_full, X_full).fit() print("\n最终三因子模型结果(使用全部数据):") print(final_model.summary())
# 5. 因子暴露分布分析 plt.figure(figsize=(12, 8))
# 5.1 Beta分布直方图 plt.subplot(2, 2, 1) plt.hist(results['Beta_Mkt'], bins=20, color='blue', alpha=0.7) plt.axvline(results['Beta_Mkt'].mean(), color='k', linestyle='dashed', linewidth=1) plt.title('市场风险暴露分布') plt.xlabel('Beta_Mkt') plt.grid(alpha=0.2)
plt.subplot(2, 2, 2) plt.hist(results['Beta_SMB'], bins=20, color='green', alpha=0.7) plt.axvline(results['Beta_SMB'].mean(), color='k', linestyle='dashed', linewidth=1) plt.title('规模因子暴露分布') plt.xlabel('Beta_SMB') plt.grid(alpha=0.2)
plt.subplot(2, 2, 3) plt.hist(results['Beta_HML'], bins=20, color='red', alpha=0.7) plt.axvline(results['Beta_HML'].mean(), color='k', linestyle='dashed', linewidth=1) plt.title('价值因子暴露分布') plt.xlabel('Beta_HML') plt.grid(alpha=0.2)
plt.subplot(2, 2, 4) plt.hist(results['Alpha'], bins=20, color='purple', alpha=0.7) plt.axvline(results['Alpha'].mean(), color='k', linestyle='dashed', linewidth=1) plt.title('Alpha分布') plt.xlabel('Alpha') plt.grid(alpha=0.2)
plt.tight_layout() plt.show()
# 6. 结果解读 print("\n投资组合特征分析:") print(f"平均市场风险暴露: {results['Beta_Mkt'].mean():.2f}") print(f"平均规模因子暴露: {results['Beta_SMB'].mean():.2f}") print(f"平均价值因子暴露: {results['Beta_HML'].mean():.2f}") print(f"平均Alpha: {results['Alpha'].mean():.2%}") print(f"平均模型解释力(R²): {results['R_squared'].mean():.2%}")
if results['Beta_Mkt'].mean() > 1: print("→ 投资组合系统性风险高于市场平均水平") else: print("→ 投资组合系统性风险低于市场平均水平")
if results['Alpha'].mean() > 0: print("→ 投资组合持续产生正超额收益") else: print("→ 投资组合未能产生正超额收益")
|