"""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")) from datetime import UTC, datetime, timedelta from decimal import Decimal from backtester.engine import BacktestEngine from shared.models import Candle def _generate_candles(prices: list[float], symbol="AAPL") -> list[Candle]: return [ Candle( symbol=symbol, timeframe="1h", open_time=datetime(2025, 1, 1, tzinfo=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 == "AAPL" 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")