backtest_correct_long_only.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #!/usr/bin/env python3
  2. """
  3. 基于 cyb50_30min_dual_direction.py 的只做多回测
  4. 使用与 auto_report_long_only_t1.py 相同的策略逻辑
  5. """
  6. import sys
  7. sys.path.insert(0, '/home/erwin/.openclaw/workspace/cyb50-quant/cat-fly/t1')
  8. import pandas as pd
  9. import numpy as np
  10. from datetime import datetime, timedelta
  11. # 导入策略模块
  12. from cyb50_30min_dual_direction import (
  13. DualDirectionSignalGenerator
  14. )
  15. def calculate_indicators(data):
  16. """计算技术指标"""
  17. df = data.copy()
  18. # 移动平均线
  19. df['MA6'] = df['Close'].rolling(window=6).mean()
  20. df['MA12'] = df['Close'].rolling(window=12).mean()
  21. df['MA24'] = df['Close'].rolling(window=24).mean()
  22. # RSI
  23. delta = df['Close'].diff()
  24. gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
  25. loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
  26. rs = gain / loss
  27. df['RSI'] = 100 - (100 / (1 + rs))
  28. # 布林带
  29. df['BB_middle'] = df['Close'].rolling(window=20).mean()
  30. bb_std = df['Close'].rolling(window=20).std()
  31. df['BB_upper'] = df['BB_middle'] + (bb_std * 2)
  32. df['BB_lower'] = df['BB_middle'] - (bb_std * 2)
  33. # MACD
  34. exp1 = df['Close'].ewm(span=12, adjust=False).mean()
  35. exp2 = df['Close'].ewm(span=26, adjust=False).mean()
  36. df['MACD'] = exp1 - exp2
  37. df['MACD_signal'] = df['MACD'].ewm(span=9, adjust=False).mean()
  38. df['MACD_hist'] = df['MACD'] - df['MACD_signal']
  39. # KDJ
  40. low_9 = df['Low'].rolling(window=9).min()
  41. high_9 = df['High'].rolling(window=9).max()
  42. rsv = (df['Close'] - low_9) / (high_9 - low_9) * 100
  43. df['K'] = rsv.ewm(com=2, adjust=False).mean()
  44. df['D'] = df['K'].ewm(com=2, adjust=False).mean()
  45. df['J'] = 3 * df['K'] - 2 * df['D']
  46. df['Volume_MA'] = df['Volume'].rolling(window=12).mean()
  47. df['Volume_Ratio'] = df['Volume'] / df['Volume_MA']
  48. df['Price_Momentum'] = (df['Close'] - df['Close'].shift(6)) / df['Close'].shift(6)
  49. df['Close_Open_Pct'] = (df['Close'] - df['Open']) / df['Open']
  50. return df
  51. def run_backtest():
  52. """运行回测"""
  53. print("="*70)
  54. print("基于 DualDirection 策略的只做多回测")
  55. print("="*70)
  56. # 加载数据
  57. data_file = 'cyb50_30min_2023_to_20260325.csv'
  58. print(f"\n[1/3] 加载数据: {data_file}")
  59. data = pd.read_csv(data_file)
  60. data['DateTime'] = pd.to_datetime(data['DateTime'])
  61. data.set_index('DateTime', inplace=True)
  62. data.sort_index(inplace=True)
  63. print(f" 数据条数: {len(data)}")
  64. print(f" 范围: {data.index[0]} ~ {data.index[-1]}")
  65. # 计算技术指标
  66. print("\n[2/3] 计算技术指标...")
  67. df = calculate_indicators(data)
  68. print(" 完成")
  69. # 生成信号
  70. print("\n[3/3] 生成多空信号...")
  71. signal_generator = DualDirectionSignalGenerator()
  72. signals_df = signal_generator.generate_dual_direction_signals(df)
  73. print(f"\n信号统计:")
  74. print(f" 做多信号: {signal_generator.long_signal_count}个")
  75. print(f" 做空信号: {signal_generator.short_signal_count}个")
  76. print(f" 总信号: {signal_generator.total_signal_count}个")
  77. # 提取做多信号
  78. long_signals = signals_df[signals_df['Signal'] == 1]
  79. print(f"\n做多信号详情:")
  80. print(long_signals[['Close', 'Long_Score', 'Long_Signals']].head(10))
  81. if __name__ == '__main__':
  82. run_backtest()