generate_30min_regime_chart.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. 生成30分钟级别市场状态识别图表
  5. """
  6. import pandas as pd
  7. import matplotlib.pyplot as plt
  8. import matplotlib.dates as mdates
  9. from datetime import datetime
  10. import warnings
  11. warnings.filterwarnings('ignore')
  12. print("="*70)
  13. print("生成30分钟市场状态识别图表")
  14. print("="*70)
  15. # 读取30分钟结果数据
  16. df = pd.read_csv('cyb50_30min_regime_result.csv', index_col='datetime', parse_dates=True)
  17. print(f"\n数据范围: {df.index[0]} ~ {df.index[-1]}")
  18. print(f"数据条数: {len(df)}个30分钟周期")
  19. # 设置中文字体
  20. plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
  21. plt.rcParams['axes.unicode_minus'] = False
  22. # 状态名称和颜色
  23. state_names = ['震荡', '趋势', '反转']
  24. colors = ['#2196F3', '#4CAF50', '#FF5722'] # 蓝、绿、橙
  25. # 创建图表
  26. fig, axes = plt.subplots(3, 1, figsize=(20, 14))
  27. # 图1: 价格走势 + 状态标记
  28. ax1 = axes[0]
  29. ax1.plot(df.index, df['close'], 'k-', alpha=0.3, linewidth=0.5, label='收盘价')
  30. for i, (name, color) in enumerate(zip(state_names, colors)):
  31. mask = df['state'] == i
  32. if mask.any():
  33. ax1.scatter(df.index[mask], df['close'][mask],
  34. c=color, label=name, alpha=0.6, s=20)
  35. ax1.set_ylabel('价格', fontsize=12)
  36. ax1.set_title('CYB50 30分钟市场状态识别 (2024-2026)', fontsize=14, fontweight='bold')
  37. ax1.legend(loc='upper left', fontsize=10)
  38. ax1.grid(True, alpha=0.3)
  39. # 格式化x轴日期
  40. ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
  41. ax1.xaxis.set_major_locator(mdates.MonthLocator(interval=2))
  42. # 图2: 状态概率时间序列
  43. ax2 = axes[1]
  44. ax2.fill_between(df.index, 0, df['prob_ranging'],
  45. alpha=0.5, label='震荡', color=colors[0])
  46. ax2.fill_between(df.index, df['prob_ranging'],
  47. df['prob_ranging'] + df['prob_trend'],
  48. alpha=0.5, label='趋势', color=colors[1])
  49. ax2.fill_between(df.index,
  50. df['prob_ranging'] + df['prob_trend'], 1,
  51. alpha=0.5, label='反转', color=colors[2])
  52. ax2.set_ylabel('概率', fontsize=12)
  53. ax2.set_title('30分钟状态概率时间序列', fontsize=12)
  54. ax2.legend(loc='upper left', fontsize=10)
  55. ax2.grid(True, alpha=0.3)
  56. ax2.set_ylim(0, 1)
  57. ax2.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
  58. ax2.xaxis.set_major_locator(mdates.MonthLocator(interval=2))
  59. # 图3: 状态分布统计
  60. ax3 = axes[2]
  61. state_counts = df['state'].value_counts().sort_index()
  62. bars = ax3.bar(range(3), state_counts.values, color=colors, alpha=0.7)
  63. ax3.set_xticks(range(3))
  64. ax3.set_xticklabels(state_names)
  65. ax3.set_ylabel('周期数', fontsize=12)
  66. ax3.set_title('30分钟状态分布统计', fontsize=12)
  67. # 添加数值标签
  68. for i, (bar, count) in enumerate(zip(bars, state_counts.values)):
  69. pct = count / len(df) * 100
  70. ax3.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 20,
  71. f'{count}\n({pct:.1f}%)',
  72. ha='center', va='bottom', fontsize=11, fontweight='bold')
  73. plt.tight_layout()
  74. plt.savefig('cyb50_30min_regime_chart.png', dpi=150, bbox_inches='tight')
  75. print("\n[OK] 图表已保存: cyb50_30min_regime_chart.png")
  76. # 生成详细报告
  77. print("\n" + "="*70)
  78. print("30分钟级别详细识别结果")
  79. print("="*70)
  80. # 按月份统计
  81. print("\n【月度统计 - 最近6个月】")
  82. print(f"{'月份':<12} {'总周期':<8} {'震荡':<8} {'趋势':<8} {'反转':<8} {'主要状态':<10}")
  83. print("-"*70)
  84. recent_months = df[df.index >= '2024-09-01'].copy()
  85. for year_month in sorted(recent_months.index.to_period('M').unique()):
  86. mask = recent_months.index.to_period('M') == year_month
  87. month_data = recent_months[mask]
  88. total = len(month_data)
  89. ranging = (month_data['state'] == 0).sum()
  90. trend = (month_data['state'] == 1).sum()
  91. reversal = (month_data['state'] == 2).sum()
  92. main_state = state_names[month_data['state'].mode()[0]]
  93. print(f"{str(year_month):<12} {total:<8} {ranging:<8} {trend:<8} {reversal:<8} {main_state:<10}")
  94. # 最近一周详细数据
  95. print("\n【最近一周详细数据】")
  96. print(f"{'日期时间':<20} {'收盘价':<10} {'状态':<8} {'震荡%':<8} {'趋势%':<8} {'反转%':<8}")
  97. print("-"*70)
  98. last_week = df.tail(40) # 约5个交易日
  99. for idx, row in last_week.iterrows():
  100. state = state_names[int(row['state'])]
  101. print(f"{str(idx):<20} {row['close']:<10.2f} {state:<8} "
  102. f"{row['prob_ranging']:<8.1%} {row['prob_trend']:<8.1%} {row['prob_reversal']:<8.1%}")
  103. print("\n" + "="*70)
  104. print("[OK] 报告生成完成!")
  105. print("="*70)