diff options
| author | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-04-01 17:05:45 +0900 |
|---|---|---|
| committer | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-04-01 17:05:45 +0900 |
| commit | b8dc7344ff99eb23d5f003795f17cdba3b89c40b (patch) | |
| tree | b072312d8c7b3dcd6c0f2e521370deb9a6758630 /tests/integration/test_backtest_end_to_end.py | |
| parent | b4624c77de2ea615a65c04a39d657a38ff2a7c95 (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.py | 66 |
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") |
