summaryrefslogtreecommitdiff
path: root/tests/integration/test_backtest_end_to_end.py
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 17:05:45 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 17:05:45 +0900
commitb8dc7344ff99eb23d5f003795f17cdba3b89c40b (patch)
treeb072312d8c7b3dcd6c0f2e521370deb9a6758630 /tests/integration/test_backtest_end_to_end.py
parentb4624c77de2ea615a65c04a39d657a38ff2a7c95 (diff)
test: add integration tests for strategy, order, portfolio, and backtest flows
Diffstat (limited to 'tests/integration/test_backtest_end_to_end.py')
-rw-r--r--tests/integration/test_backtest_end_to_end.py66
1 files changed, 66 insertions, 0 deletions
diff --git a/tests/integration/test_backtest_end_to_end.py b/tests/integration/test_backtest_end_to_end.py
new file mode 100644
index 0000000..4bdb5f3
--- /dev/null
+++ b/tests/integration/test_backtest_end_to_end.py
@@ -0,0 +1,66 @@
+"""Integration test: full backtest with real strategy on generated candles."""
+import sys
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "services" / "strategy-engine" / "src"))
+sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "services" / "strategy-engine"))
+sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "services" / "backtester" / "src"))
+
+import pytest
+from decimal import Decimal
+from datetime import datetime, timedelta, timezone
+
+from shared.models import Candle
+from backtester.engine import BacktestEngine
+
+
+def _generate_candles(prices: list[float], symbol="BTCUSDT") -> list[Candle]:
+ return [
+ Candle(
+ symbol=symbol, timeframe="1h",
+ open_time=datetime(2025, 1, 1, tzinfo=timezone.utc) + timedelta(hours=i),
+ open=Decimal(str(p)), high=Decimal(str(p + 100)),
+ low=Decimal(str(p - 100)), close=Decimal(str(p)),
+ volume=Decimal("100"),
+ )
+ for i, p in enumerate(prices)
+ ]
+
+
+def test_backtest_rsi_strategy_end_to_end():
+ """Run RSI strategy through backtester and verify result structure."""
+ from strategies.rsi_strategy import RsiStrategy
+
+ strategy = RsiStrategy()
+ strategy.configure({"period": 5, "oversold": 30, "overbought": 70, "quantity": "0.1"})
+
+ # Generate price series: decline then rise
+ prices = [100 - i for i in range(15)] + [85 + i * 2 for i in range(15)]
+ candles = _generate_candles(prices)
+
+ engine = BacktestEngine(strategy, Decimal("10000"))
+ result = engine.run(candles)
+
+ assert result.strategy_name == "rsi"
+ assert result.symbol == "BTCUSDT"
+ assert result.initial_balance == Decimal("10000")
+ assert result.detailed is not None
+ assert result.detailed.total_trades >= 0
+
+
+def test_backtest_with_no_signals():
+ """Strategy that generates no signals should return initial balance."""
+ from strategies.rsi_strategy import RsiStrategy
+
+ strategy = RsiStrategy()
+ strategy.configure({"period": 14, "oversold": 10, "overbought": 90, "quantity": "0.1"})
+
+ # Flat prices -- no RSI extremes
+ prices = [100.0] * 30
+ candles = _generate_candles(prices)
+
+ engine = BacktestEngine(strategy, Decimal("10000"))
+ result = engine.run(candles)
+
+ assert result.total_trades == 0
+ assert result.final_balance == Decimal("10000")