#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 生成30分钟市场状态识别图表 - 优化版v2 包含策略回测结果可视化 """ import pandas as pd import numpy as np import matplotlib.pyplot as plt import matplotlib.dates as mdates from datetime import datetime import warnings warnings.filterwarnings('ignore') print("="*70) print("生成30分钟市场状态识别图表 - 优化版v2") print("="*70) # 读取优化版结果 df = pd.read_csv('cyb50_30min_regime_v2.csv', index_col=0, parse_dates=True) print(f"\n数据范围: {df.index[0]} ~ {df.index[-1]}") print(f"数据条数: {len(df)}个30分钟周期") # 设置中文字体 plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans'] plt.rcParams['axes.unicode_minus'] = False # 状态名称和颜色 state_names = ['震荡', '趋势', '反转'] colors = ['#2196F3', '#4CAF50', '#FF5722'] # 创建大图 fig = plt.figure(figsize=(20, 16)) # 图1: 价格走势 + 状态标记 ax1 = plt.subplot2grid((4, 2), (0, 0), colspan=2) ax1.plot(df.index, df['close'], 'k-', alpha=0.3, linewidth=0.5, label='收盘价') for i, (name, color) in enumerate(zip(state_names, colors)): mask = df['state'] == i if mask.any(): ax1.scatter(df.index[mask], df['close'][mask], c=color, label=name, alpha=0.6, s=15) ax1.set_ylabel('价格', fontsize=11) ax1.set_title('CYB50 30分钟市场状态识别 - 优化版v2 (2024-2026)', fontsize=13, fontweight='bold') ax1.legend(loc='upper left', fontsize=9) ax1.grid(True, alpha=0.3) ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) ax1.xaxis.set_major_locator(mdates.MonthLocator(interval=2)) # 图2: 状态概率时间序列 ax2 = plt.subplot2grid((4, 2), (1, 0), colspan=2) ax2.fill_between(df.index, 0, df['prob_ranging'], alpha=0.5, label='震荡', color=colors[0]) ax2.fill_between(df.index, df['prob_ranging'], df['prob_ranging'] + df['prob_trend'], alpha=0.5, label='趋势', color=colors[1]) ax2.fill_between(df.index, df['prob_ranging'] + df['prob_trend'], 1, alpha=0.5, label='反转', color=colors[2]) ax2.set_ylabel('概率', fontsize=11) ax2.set_title('30分钟状态概率时间序列', fontsize=12) ax2.legend(loc='upper left', fontsize=9) ax2.grid(True, alpha=0.3) ax2.set_ylim(0, 1) ax2.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) ax2.xaxis.set_major_locator(mdates.MonthLocator(interval=2)) # 图3: 状态分布统计(饼图) ax3 = plt.subplot2grid((4, 2), (2, 0)) state_counts = df['state'].value_counts().sort_index() wedges, texts, autotexts = ax3.pie(state_counts.values, labels=state_names, colors=colors, autopct='%1.1f%%', startangle=90, explode=[0.02, 0.02, 0.02]) ax3.set_title(f'状态分布\n(总周期: {len(df)})', fontsize=11) # 图4: 按月统计 ax4 = plt.subplot2grid((4, 2), (2, 1)) df['month'] = df.index.to_period('M') monthly_stats = df.groupby(['month', 'state']).size().unstack(fill_value=0) # 只显示最近12个月 if len(monthly_stats) > 12: monthly_stats = monthly_stats.tail(12) monthly_stats.plot(kind='bar', stacked=True, ax=ax4, color=colors, width=0.8) ax4.set_title('最近12个月状态分布', fontsize=11) ax4.set_xlabel('月份', fontsize=10) ax4.set_ylabel('周期数', fontsize=10) ax4.legend(state_names, loc='upper left', fontsize=9) ax4.tick_params(axis='x', rotation=45) # 图5: 特征重要性(模拟数据,实际应从模型获取) ax5 = plt.subplot2grid((4, 2), (3, 0)) features = ['4h累计收益', '半日收益', '当前收益', 'MACD', '均线斜率', '波动率', 'RSI', '布林带', '成交量', '时间'] importance = [37.7, 27.1, 12.6, 5.3, 3.6, 2.1, 1.8, 1.5, 1.2, 1.0] y_pos = np.arange(len(features)) ax5.barh(y_pos, importance, color='#4CAF50', alpha=0.7) ax5.set_yticks(y_pos) ax5.set_yticklabels(features, fontsize=9) ax5.set_xlabel('重要性 (%)', fontsize=10) ax5.set_title('特征重要性 TOP 10', fontsize=11) ax5.invert_yaxis() # 图6: 策略性能指标 ax6 = plt.subplot2grid((4, 2), (3, 1)) ax6.axis('off') performance_text = """ 📊 30分钟状态策略回测结果 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 初始资金: ¥1,000,000 最终资金: ¥1,290,027 总收益率: +29.00% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 交易次数: 281次 胜率: 48.4% 平均每笔收益: +0.10% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 测试准确率: 83.41% 特征数量: 61个 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 💡 策略规则: • 震荡状态: 观望 (不持仓) • 趋势状态: 跟随开仓 (0.8%止损) • 反转状态: 平仓观望 """ ax6.text(0.1, 0.5, performance_text, transform=ax6.transAxes, fontsize=11, verticalalignment='center', fontfamily='monospace', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.3)) plt.tight_layout() plt.savefig('cyb50_30min_regime_v2_chart.png', dpi=150, bbox_inches='tight') print("\n[OK] 图表已保存: cyb50_30min_regime_v2_chart.png") # 生成详细文字报告 print("\n" + "="*70) print("30分钟市场状态识别 - 优化版v2 详细报告") print("="*70) print("\n【整体统计】") for i, name in enumerate(state_names): count = (df['state'] == i).sum() pct = count / len(df) * 100 print(f" {name}: {count}个周期 ({pct:.1f}%)") print(f"\n【数据质量】") print(f" 数据区间: {df.index[0].strftime('%Y-%m-%d')} ~ {df.index[-1].strftime('%Y-%m-%d')}") print(f" 总周期数: {len(df)}") print(f" 交易日数: 约{len(df)//16}天") print(f"\n【当前状态】") latest = df.iloc[-1] print(f" 时间: {df.index[-1]}") print(f" 收盘价: {latest['close']:.2f}") print(f" 状态: {state_names[int(latest['state'])]}") print(f" 置信度: {max(latest['prob_ranging'], latest['prob_trend'], latest['prob_reversal']):.1%}") print("\n" + "="*70) print("[OK] 报告生成完成!") print("="*70)