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_strategy_signal_flow.py | |
| parent | b4624c77de2ea615a65c04a39d657a38ff2a7c95 (diff) | |
test: add integration tests for strategy, order, portfolio, and backtest flows
Diffstat (limited to 'tests/integration/test_strategy_signal_flow.py')
| -rw-r--r-- | tests/integration/test_strategy_signal_flow.py | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/tests/integration/test_strategy_signal_flow.py b/tests/integration/test_strategy_signal_flow.py new file mode 100644 index 0000000..ee47f8e --- /dev/null +++ b/tests/integration/test_strategy_signal_flow.py @@ -0,0 +1,55 @@ +"""Integration test: candle -> strategy engine -> signal.""" +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")) + +import pytest +from decimal import Decimal +from datetime import datetime, timezone +from unittest.mock import AsyncMock, MagicMock + +from shared.models import Candle, OrderSide +from shared.events import CandleEvent, Event +from strategy_engine.engine import StrategyEngine + + +@pytest.fixture +def candles(): + """Generate a series of declining candles that should trigger RSI oversold.""" + base = [] + for i in range(20): + price = Decimal(str(100 - i * 2)) # 100, 98, 96... + base.append(Candle( + symbol="BTCUSDT", timeframe="1m", + open_time=datetime(2025, 1, 1, i, 0, tzinfo=timezone.utc), + open=price, high=price + 1, low=price - 1, + close=price, volume=Decimal("10"), + )) + return base + + +@pytest.mark.asyncio +async def test_strategy_engine_produces_signals_from_candles(candles): + """Feed candles into strategy engine and verify signals are published.""" + from strategies.rsi_strategy import RsiStrategy + + broker = AsyncMock() + # Mock broker.read to return candle events one at a time, then empty + events = [CandleEvent(data=c).to_dict() for c in candles] + broker.read = AsyncMock(side_effect=[events, []]) + + strategy = RsiStrategy() + strategy.configure({"period": 14, "oversold": 30, "overbought": 70, "quantity": "0.01"}) + + engine = StrategyEngine(broker=broker, strategies=[strategy]) + + await engine.process_once("candles.BTCUSDT", "$") + + # With 20 declining candles (100->62), RSI should be very low + # Check if broker.publish was called with a signal + if broker.publish.called: + call_args = broker.publish.call_args_list + for call in call_args: + assert call[0][0] == "signals" # published to signals stream |
