show_summary.py 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import pandas as pd
  4. import numpy as np
  5. from datetime import datetime
  6. import warnings
  7. import sys
  8. warnings.filterwarnings('ignore')
  9. # Redirect stdout to suppress verbose output
  10. from io import StringIO
  11. old_stdout = sys.stdout
  12. sys.stdout = StringIO()
  13. from cyb50_30min_dual_direction import ConfigManager, IntradayDataFetcher, DualDirectionSignalGenerator, DualDirectionExecutor
  14. from t1_converter import simulate_t1_trades
  15. def load_local_data(csv_file='cyb50_30min_2023_to_20260325.csv'):
  16. df = pd.read_csv(csv_file)
  17. df['DateTime'] = pd.to_datetime(df['DateTime'])
  18. df.set_index('DateTime', inplace=True)
  19. df.sort_index(inplace=True)
  20. if 'Open' not in df.columns and 'o' in df.columns:
  21. df.rename(columns={'o':'Open','h':'High','l':'Low','c':'Close','v':'Volume','a':'Amount'}, inplace=True)
  22. for col in ['Open', 'High', 'Low', 'Close', 'Volume']:
  23. if col in df.columns:
  24. df[col] = pd.to_numeric(df[col], errors='coerce')
  25. df['Returns'] = df['Close'].pct_change()
  26. df['High_Low_Pct'] = (df['High'] - df['Low']) / df['Close'].shift(1)
  27. df['Close_Open_Pct'] = (df['Close'] - df['Open']) / df['Open']
  28. df.ffill(inplace=True)
  29. df.dropna(inplace=True)
  30. return df
  31. initial_capital = 1000000
  32. raw_data = load_local_data('cyb50_30min_2023_to_20260325.csv')
  33. config_manager = ConfigManager('config.json')
  34. fetcher = IntradayDataFetcher(config_manager)
  35. data_with_indicators = fetcher.calculate_intraday_indicators(raw_data)
  36. signal_generator = DualDirectionSignalGenerator()
  37. signals_df = signal_generator.generate_dual_direction_signals(data_with_indicators)
  38. executor = DualDirectionExecutor(initial_capital=initial_capital)
  39. results_df, trades_df = executor.execute_dual_direction_trades(signals_df)
  40. long_trades = trades_df[trades_df['交易方向'] == '做多'].copy()
  41. t1_trades = simulate_t1_trades(data_with_indicators, long_trades, initial_capital)
  42. t1_adjusted = t1_trades[t1_trades['T+1调整'] == '是(T0→T1)']
  43. final_capital = t1_trades['平仓时资金'].iloc[-1] if len(t1_trades) > 0 else initial_capital
  44. total_return = (final_capital - initial_capital) / initial_capital * 100
  45. total_trades = len(t1_trades)
  46. winning_trades = t1_trades[t1_trades['盈亏金额'] > 0]
  47. losing_trades = t1_trades[t1_trades['盈亏金额'] < 0]
  48. win_rate = len(winning_trades) / total_trades * 100 if total_trades > 0 else 0
  49. total_profit = winning_trades['盈亏金额'].sum() if len(winning_trades) > 0 else 0
  50. total_loss = abs(losing_trades['盈亏金额'].sum()) if len(losing_trades) > 0 else 0
  51. profit_factor = total_profit / total_loss if total_loss > 0 else 0
  52. normal_trades = t1_trades[t1_trades['T+1调整'] != '是(T0→T1)']
  53. normal_pnl = normal_trades['盈亏金额'].sum() if len(normal_trades) > 0 else 0
  54. t1_pnl = t1_adjusted['盈亏金额'].sum() if len(t1_adjusted) > 0 else 0
  55. # Restore stdout
  56. sys.stdout = old_stdout
  57. print('='*60)
  58. print('创业板50 T+1 回测结果汇总')
  59. print('='*60)
  60. print(f'数据加载: {len(raw_data)}条K线')
  61. print(f'数据区间: {raw_data.index[0]} ~ {raw_data.index[-1]}')
  62. print(f'多空策略: 共{len(trades_df)}笔交易, 做多{len(long_trades)}笔')
  63. print(f'T+1转换: {len(t1_trades)}笔交易')
  64. print(f'T+1调整: {len(t1_adjusted)}笔')
  65. print()
  66. print('='*60)
  67. print('总体绩效')
  68. print('='*60)
  69. print(f'初始资金: {initial_capital:,.0f}元')
  70. print(f'最终资金: {final_capital:,.0f}元')
  71. print(f'总收益率: {total_return:+.2f}%')
  72. print(f'总交易次数: {total_trades}笔')
  73. print(f'盈利次数: {len(winning_trades)}笔')
  74. print(f'亏损次数: {len(losing_trades)}笔')
  75. print(f'胜率: {win_rate:.1f}%')
  76. print(f'盈亏比: {profit_factor:.2f}')
  77. print()
  78. print('='*60)
  79. print('T+1调整统计')
  80. print('='*60)
  81. print(f'正常交易: {len(normal_trades)}笔, 盈亏{normal_pnl:+,.0f}元')
  82. print(f'T+1调整(T0→T1): {len(t1_adjusted)}笔, 盈亏{t1_pnl:+,.0f}元')
  83. print()
  84. print('='*60)
  85. print('最近5笔交易')
  86. print('='*60)
  87. print(t1_trades.tail(5)[['开仓时间', '平仓时间', '盈亏金额', 'T+1调整']].to_string(index=False))