|
@@ -1,57 +1,58 @@
|
|
|
from okx_codex_trader.backtest import run_backtest
|
|
from okx_codex_trader.backtest import run_backtest
|
|
|
from okx_codex_trader.models import Candle
|
|
from okx_codex_trader.models import Candle
|
|
|
|
|
+from okx_codex_trader.strategy import simple_moving_average
|
|
|
|
|
|
|
|
|
|
|
|
|
def build_crossing_series() -> list[Candle]:
|
|
def build_crossing_series() -> list[Candle]:
|
|
|
closes = [
|
|
closes = [
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 140.0,
|
|
|
50.0,
|
|
50.0,
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
- 40.0,
|
|
|
|
|
50.0,
|
|
50.0,
|
|
|
50.0,
|
|
50.0,
|
|
|
50.0,
|
|
50.0,
|
|
|
50.0,
|
|
50.0,
|
|
|
50.0,
|
|
50.0,
|
|
|
50.0,
|
|
50.0,
|
|
|
|
|
+ 50.0,
|
|
|
|
|
+ 50.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
|
|
+ 60.0,
|
|
|
]
|
|
]
|
|
|
opens = list(closes)
|
|
opens = list(closes)
|
|
|
- opens[20] = 100.0
|
|
|
|
|
|
|
+ opens[21] = 100.0
|
|
|
opens[30] = 90.0
|
|
opens[30] = 90.0
|
|
|
opens[40] = 80.0
|
|
opens[40] = 80.0
|
|
|
|
|
|
|
@@ -73,6 +74,15 @@ def build_crossing_series() -> list[Candle]:
|
|
|
return candles
|
|
return candles
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+def test_simple_moving_average_requires_full_window():
|
|
|
|
|
+ candles = [
|
|
|
|
|
+ Candle(symbol="BTC-USDT-SWAP", ts=index, open=close, high=close, low=close, close=close, volume=1_000.0)
|
|
|
|
|
+ for index, close in enumerate([10.0, 20.0, 30.0, 40.0])
|
|
|
|
|
+ ]
|
|
|
|
|
+
|
|
|
|
|
+ assert simple_moving_average(candles, 3) == [None, None, 20.0, 30.0]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
def test_backtest_runs_fixed_sma_crossover_series():
|
|
def test_backtest_runs_fixed_sma_crossover_series():
|
|
|
candles = build_crossing_series()
|
|
candles = build_crossing_series()
|
|
|
|
|
|
|
@@ -80,7 +90,7 @@ def test_backtest_runs_fixed_sma_crossover_series():
|
|
|
|
|
|
|
|
assert result.initial_equity == 10_000
|
|
assert result.initial_equity == 10_000
|
|
|
assert result.trade_count == 2
|
|
assert result.trade_count == 2
|
|
|
- assert result.trades[0].entry_price == candles[20].open
|
|
|
|
|
|
|
+ assert result.trades[0].entry_price == candles[21].open
|
|
|
assert result.trades[0].exit_price == candles[30].open
|
|
assert result.trades[0].exit_price == candles[30].open
|
|
|
assert result.trades[0].margin_used == 10_000
|
|
assert result.trades[0].margin_used == 10_000
|
|
|
assert result.trades[1].margin_used == result.trades[0].ending_equity
|
|
assert result.trades[1].margin_used == result.trades[0].ending_equity
|