test_backtest.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. from okx_codex_trader.backtest import run_backtest
  2. from okx_codex_trader.models import Candle
  3. from okx_codex_trader.strategy import simple_moving_average
  4. def build_crossing_series() -> list[Candle]:
  5. closes = [
  6. 60.0,
  7. 60.0,
  8. 60.0,
  9. 60.0,
  10. 60.0,
  11. 60.0,
  12. 60.0,
  13. 60.0,
  14. 60.0,
  15. 60.0,
  16. 60.0,
  17. 60.0,
  18. 60.0,
  19. 60.0,
  20. 60.0,
  21. 60.0,
  22. 60.0,
  23. 60.0,
  24. 60.0,
  25. 60.0,
  26. 140.0,
  27. 50.0,
  28. 50.0,
  29. 50.0,
  30. 50.0,
  31. 50.0,
  32. 50.0,
  33. 50.0,
  34. 50.0,
  35. 50.0,
  36. 60.0,
  37. 60.0,
  38. 60.0,
  39. 60.0,
  40. 60.0,
  41. 60.0,
  42. 60.0,
  43. 60.0,
  44. 60.0,
  45. 60.0,
  46. 60.0,
  47. 60.0,
  48. 60.0,
  49. 60.0,
  50. 60.0,
  51. ]
  52. opens = list(closes)
  53. opens[21] = 100.0
  54. opens[30] = 90.0
  55. opens[40] = 80.0
  56. candles = []
  57. for index, (open_price, close_price) in enumerate(zip(opens, closes)):
  58. high = max(open_price, close_price)
  59. low = min(open_price, close_price)
  60. candles.append(
  61. Candle(
  62. symbol="BTC-USDT-SWAP",
  63. ts=index,
  64. open=open_price,
  65. high=high,
  66. low=low,
  67. close=close_price,
  68. volume=1_000.0,
  69. )
  70. )
  71. return candles
  72. def test_simple_moving_average_requires_full_window():
  73. candles = [
  74. Candle(symbol="BTC-USDT-SWAP", ts=index, open=close, high=close, low=close, close=close, volume=1_000.0)
  75. for index, close in enumerate([10.0, 20.0, 30.0, 40.0])
  76. ]
  77. assert simple_moving_average(candles, 3) == [None, None, 20.0, 30.0]
  78. def test_backtest_runs_fixed_sma_crossover_series():
  79. candles = build_crossing_series()
  80. result = run_backtest(candles=candles, leverage=2)
  81. assert result.initial_equity == 10_000
  82. assert result.trade_count == 2
  83. assert result.trades[0].entry_price == candles[21].open
  84. assert result.trades[0].exit_price == candles[30].open
  85. assert result.trades[0].margin_used == 10_000
  86. assert result.trades[1].margin_used == result.trades[0].ending_equity
  87. assert result.ending_equity == result.trades[-1].ending_equity
  88. assert "total_return" in result.to_dict()
  89. assert "max_drawdown" in result.to_dict()
  90. assert result.win_rate == 0.5