summaryrefslogtreecommitdiff
path: root/tests/integration/test_strategy_signal_flow.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_strategy_signal_flow.py
parentb4624c77de2ea615a65c04a39d657a38ff2a7c95 (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.py55
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