regime_chinext50.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #!/usr/bin/env python3
  2. """
  3. 创业板50指数Regime策略 - 最终工作版
  4. 基于双均线(20/60)的金叉/死叉信号
  5. """
  6. import backtrader as bt
  7. import pandas as pd
  8. import numpy as np
  9. class Chinext50RegimeStrategy(bt.Strategy):
  10. """
  11. 创业板50双均线Regime策略
  12. 参数:
  13. fast: 短期均线周期 (默认20)
  14. slow: 长期均线周期 (默认60)
  15. """
  16. params = (
  17. ('fast', 20),
  18. ('slow', 60),
  19. )
  20. def __init__(self):
  21. self.sma_fast = bt.indicators.SMA(period=self.p.fast)
  22. self.sma_slow = bt.indicators.SMA(period=self.p.slow)
  23. self.trade_count = 0
  24. def next(self):
  25. """策略主逻辑 - 每个交易日调用"""
  26. if len(self) < 2:
  27. return
  28. # 获取当前和前一周期的均线值
  29. fast_now = self.sma_fast[0]
  30. fast_prev = self.sma_fast[-1]
  31. slow_now = self.sma_slow[0]
  32. slow_prev = self.sma_slow[-1]
  33. # 检查有效值
  34. if np.isnan(fast_now):
  35. return
  36. # 金叉检测: 前一周fast<=slow, 这一周fast>slow
  37. golden_cross = fast_prev <= slow_prev and fast_now > slow_now
  38. # 死叉检测: 前一周fast>=slow, 这一周fast<slow
  39. death_cross = fast_prev >= slow_prev and fast_now < slow_now
  40. # 买入逻辑: 金叉 + 空仓
  41. if golden_cross and not self.position:
  42. close_price = self.datas[0].close[0]
  43. size = int(self.broker.getcash() / close_price)
  44. if size > 0:
  45. self.buy(size=size)
  46. self.trade_count += 1
  47. # 卖出逻辑: 死叉 + 有持仓
  48. elif death_cross and self.position:
  49. self.close()
  50. def run_backtest(csv_file="chinext50.csv", cash=100000.0, commission=0.001):
  51. """
  52. 运行回测
  53. 参数:
  54. csv_file: 数据文件路径
  55. cash: 初始资金
  56. commission: 手续费率
  57. """
  58. cerebro = bt.Cerebro()
  59. # 加载数据
  60. df = pd.read_csv(csv_file, parse_dates=['datetime'], index_col='datetime')
  61. data = bt.feeds.PandasData(dataname=df)
  62. cerebro.adddata(data)
  63. # 添加策略
  64. cerebro.addstrategy(Chinext50RegimeStrategy)
  65. # 设置资金
  66. cerebro.broker.setcash(cash)
  67. cerebro.broker.setcommission(commission=commission)
  68. # 添加分析器
  69. cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe', riskfreerate=0.02)
  70. cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
  71. cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')
  72. cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='trades')
  73. print('=' * 50)
  74. print('创业板50 Regime策略回测')
  75. print('=' * 50)
  76. print(f'初始资金: {cerebro.broker.getvalue():.2f}')
  77. # 运行回测
  78. results = cerebro.run()
  79. strat = results[0]
  80. # 输出结果
  81. print(f'最终资金: {cerebro.broker.getvalue():.2f}')
  82. print(f'交易次数: {strat.trade_count}')
  83. returns = strat.analyzers.returns.get_analysis()
  84. print(f"年化收益: {returns.get('rnorm100', 0):.2f}%")
  85. sharpe = strat.analyzers.sharpe.get_analysis()
  86. sharpe_val = sharpe.get('sharperatio', 0)
  87. print(f"夏普比率: {sharpe_val:.3f}" if sharpe_val else "夏普比率: N/A")
  88. drawdown = strat.analyzers.drawdown.get_analysis()
  89. print(f"最大回撤: {drawdown.get('max', {}).get('drawdown', 0):.2f}%")
  90. trades = strat.analyzers.trades.get_analysis()
  91. if trades and trades.get('total'):
  92. total = trades['total'].get('total', 0)
  93. won = trades['won'].get('total', 0) if trades.get('won') else 0
  94. print(f'总交易: {total}, 盈利: {won}')
  95. if total > 0:
  96. print(f'胜率: {won/total:.1%}')
  97. print('=' * 50)
  98. return cerebro, strat
  99. if __name__ == "__main__":
  100. run_backtest()