regime_working.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. """
  2. Working Regime Strategy - 基于已成功验证的cross检测逻辑
  3. """
  4. import backtrader as bt
  5. import pandas as pd
  6. import numpy as np
  7. class WorkingRegimeStrategy(bt.Strategy):
  8. params = (
  9. ('fast', 20),
  10. ('slow', 60),
  11. ('printlog', False),
  12. )
  13. def __init__(self):
  14. self.dataclose = self.datas[0].close
  15. self.order = None
  16. self.sma_fast = bt.indicators.SMA(period=self.p.fast)
  17. self.sma_slow = bt.indicators.SMA(period=self.p.slow)
  18. self.trade_count = 0
  19. def next(self):
  20. if self.order:
  21. return
  22. if len(self) < 2:
  23. return
  24. fast_now = self.sma_fast[0]
  25. fast_prev = self.sma_fast[-1]
  26. slow_now = self.sma_slow[0]
  27. slow_prev = self.sma_slow[-1]
  28. if np.isnan(fast_now) or np.isnan(fast_prev):
  29. return
  30. # 金叉检测
  31. if fast_prev <= slow_prev and fast_now > slow_now:
  32. if not self.position:
  33. size = int(self.broker.getcash() / self.dataclose[0] / 100) * 100
  34. if size > 0:
  35. self.order = self.buy(size=size)
  36. self.trade_count += 1
  37. if self.p.printlog:
  38. self.log(f'BUY #{self.trade_count} @ {self.dataclose[0]:.2f}')
  39. # 死叉检测
  40. elif fast_prev >= slow_prev and fast_now < slow_now:
  41. if self.position:
  42. self.order = self.close()
  43. if self.p.printlog:
  44. self.log(f'SELL @ {self.dataclose[0]:.2f}')
  45. def notify_order(self, order):
  46. if order.status in [order.Completed]:
  47. if order.isbuy():
  48. self.log(f'BUY EXECUTED @ {order.executed.price:.2f}')
  49. else:
  50. self.log(f'SELL EXECUTED @ {order.executed.price:.2f}')
  51. self.order = None
  52. def log(self, txt, dt=None):
  53. if self.p.printlog:
  54. dt = dt or self.datas[0].datetime.date(0)
  55. print(f'{dt.isoformat()} {txt}')
  56. def stop(self):
  57. roi = (self.broker.getvalue() / self.broker.startingcash - 1) * 100
  58. print(f'\n=== 最终收益: {roi:.2f}% ===')
  59. print(f'总交易: {self.trade_count}')
  60. def run_working_regime(csv_file="chinext50.csv"):
  61. cerebro = bt.Cerebro()
  62. df = pd.read_csv(csv_file, parse_dates=['datetime'], index_col='datetime')
  63. data = bt.feeds.PandasData(dataname=df)
  64. cerebro.adddata(data)
  65. cerebro.addstrategy(WorkingRegimeStrategy, printlog=False)
  66. cerebro.broker.setcash(100000.0)
  67. cerebro.broker.setcommission(commission=0.001)
  68. cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe', riskfreerate=0.02)
  69. cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
  70. cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')
  71. cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='trades')
  72. print('=== 创业板50 Regime策略回测 ===')
  73. print(f'初始资金: {cerebro.broker.getvalue():.2f}')
  74. results = cerebro.run()
  75. strat = results[0]
  76. print(f'最终资金: {cerebro.broker.getvalue():.2f}')
  77. returns = strat.analyzers.returns.get_analysis()
  78. print(f"年化收益: {returns.get('rnorm100', 0):.2f}%")
  79. sharpe = strat.analyzers.sharpe.get_analysis()
  80. sharpe_val = sharpe.get('sharperatio', 0)
  81. print(f"夏普比率: {sharpe_val:.3f}" if sharpe_val else "夏普比率: N/A")
  82. drawdown = strat.analyzers.drawdown.get_analysis()
  83. print(f"最大回撤: {drawdown.get('max', {}).get('drawdown', 0):.2f}%")
  84. trades = strat.analyzers.trades.get_analysis()
  85. if trades and trades.get('total'):
  86. total = trades['total'].get('total', 0)
  87. won = trades['won'].get('total', 0) if trades.get('won') else 0
  88. print(f"总交易: {total}, 盈利: {won}")
  89. if total > 0:
  90. print(f"胜率: {won/total:.1%}")
  91. return cerebro, strat
  92. if __name__ == "__main__":
  93. run_working_regime()