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
| import numpy as np import pandas as pd import matplotlib.pyplot as plt import matplotlib.dates as mdates from matplotlib.ticker import FuncFormatter
# 运行模拟 simulated_paths = geometric_brownian_motion(S_0, mu, sigma, N_SIM, T, N)
# 创建与测试集对应的时间索引 date_index = pd.date_range(start=train.index[-1], periods=N+1, freq='D')[:N+1]
# ====================== # 可视化部分 # ======================
# 1. 模拟路径与真实价格对比 plt.figure(figsize=(14, 7)) plt.title(f"股票价格蒙特卡洛模拟 (N={N_SIM}次)\nμ={mu:.4f}, σ={sigma:.4f}", fontsize=14)
# 绘制所有模拟路径(半透明处理) for i in range(N_SIM): plt.plot(date_index, simulated_paths[i], lw=1, alpha=0.15, color='steelblue')
# 计算并绘制关键统计量 mean_path = np.mean(simulated_paths, axis=0) upper_95 = np.percentile(simulated_paths, 95, axis=0) lower_5 = np.percentile(simulated_paths, 5, axis=0)
plt.plot(date_index, mean_path, 'b-', lw=2, label='模拟均值路径') plt.plot(date_index, upper_95, 'r--', lw=1.5, label='95%分位数') plt.plot(date_index, lower_5, 'g--', lw=1.5, label='5%分位数')
# 添加实际价格曲线(测试期) test_period = df.loc[test.index, '收盘'] plt.plot(test_period.index, test_period.values, 'k-', lw=2.5, label='实际价格')
# 美化坐标轴 plt.gca().xaxis.set_major_locator(mdates.MonthLocator()) plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) plt.gcf().autofmt_xdate() # 自动旋转日期标签
# 添加图例和网格 plt.legend(loc='upper left') plt.grid(True, alpha=0.3) plt.xlabel('日期') plt.ylabel('价格') plt.tight_layout() plt.savefig('GBM_模拟路径对比.png', dpi=300) plt.show()
# 2. 模拟路径与真实价格差异分析(最后一天) final_prices = simulated_paths[:, -1] actual_final_price = test_period.iloc[-1]
plt.figure(figsize=(10, 6)) plt.hist(final_prices, bins=50, alpha=0.7, color='skyblue', edgecolor='navy') plt.axvline(x=actual_final_price, color='red', linestyle='--', lw=2, label=f'实际价格: {actual_final_price:.2f}') plt.axvline(x=np.mean(final_prices), color='green', linestyle='-', lw=2, label=f'模拟均值: {np.mean(final_prices):.2f}')
# 添加统计指标 plt.text(0.75, 0.9, f'模拟标准差: {np.std(final_prices):.2f}', transform=plt.gca().transAxes, fontsize=12) plt.text(0.75, 0.85, f'偏度: {pd.Series(final_prices).skew():.2f}', transform=plt.gca().transAxes, fontsize=12)
plt.title('模拟期末价格分布 vs 实际价格', fontsize=14) plt.xlabel('期末价格') plt.ylabel('频率') plt.legend() plt.grid(alpha=0.2) plt.savefig('GBM_期末价格分布.png', dpi=300) plt.show()
# 3. 动态预测区间(随时间变化的置信区间) plt.figure(figsize=(14, 7)) plt.fill_between(date_index, np.percentile(simulated_paths, 5, axis=0), np.percentile(simulated_paths, 95, axis=0), color='lightblue', alpha=0.5, label='90%置信区间')
plt.plot(date_index, mean_path, 'b-', lw=2, label='模拟均值') plt.plot(test_period.index, test_period.values, 'k-', lw=2.5, label='实际价格')
# 标记关键事件点 max_dev_idx = np.argmax(np.abs(test_period.values - mean_path[1:])) event_date = test_period.index[max_dev_idx] plt.axvline(x=event_date, color='purple', linestyle=':', alpha=0.8) plt.text(event_date, plt.ylim()[0]*0.95, f'最大偏离点\n{event_date.strftime("%Y-%m-%d")}', ha='center', fontsize=9)
plt.title('GBM模拟的90%置信区间与实际价格对比', fontsize=14) plt.xlabel('日期') plt.ylabel('价格') plt.legend(loc='upper left') plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=2)) plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) plt.gcf().autofmt_xdate() plt.grid(alpha=0.3) plt.tight_layout() plt.savefig('GBM_动态置信区间.png', dpi=300) plt.show()
# 4. 计算预测误差指标 simulated_mean = mean_path[1:] actual_prices = test_period.values
mae = np.mean(np.abs(simulated_mean - actual_prices)) rmse = np.sqrt(np.mean((simulated_mean - actual_prices)**2))
print("\n模型性能评估:") print(f"平均绝对误差(MAE): {mae:.4f}") print(f"均方根误差(RMSE): {rmse:.4f}") print(f"年化波动率预测: {sigma:.4f} (实际: {test.std()*np.sqrt(252):.4f})")
# 5. 关键日期对比表 compare_dates = [test_period.index[0], test_period.index[len(test)//2], test_period.index[-1]] compare_data = []
valid_dates = [d for d in compare_dates if d in date_index] # valid_dates
for date in valid_dates: idx = np.where(date_index == date)[0][0] actual = df.loc[date, '收盘'] sim_mean = mean_path[idx] sim_median = np.median(simulated_paths[:, idx]) compare_data.append([ date.strftime('%Y-%m-%d'), actual, sim_mean, sim_median, actual - sim_mean ])
# 创建对比表格 compare_df = pd.DataFrame(compare_data, columns=['日期', '实际价格', '模拟均值', '模拟中位数', '偏差']) print("\n关键日期价格对比:") print(compare_df.to_string(index=False))
|