summaryrefslogtreecommitdiff
path: root/services/strategy-engine/tests
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-02 10:26:52 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-02 10:26:52 +0900
commit53cadcf7e34f05f77082e84f0696b56bcbcbae36 (patch)
treee02650e10c4d5727bc1e32e27788c17327fa46f7 /services/strategy-engine/tests
parentf5521da2876a2c19afc24f370b3258f2be95f81a (diff)
refactor: remove all crypto/Binance code, update to US stock symbols
Diffstat (limited to 'services/strategy-engine/tests')
-rw-r--r--services/strategy-engine/tests/test_asian_session_rsi.py190
-rw-r--r--services/strategy-engine/tests/test_base_filters.py2
-rw-r--r--services/strategy-engine/tests/test_bollinger_strategy.py2
-rw-r--r--services/strategy-engine/tests/test_combined_strategy.py2
-rw-r--r--services/strategy-engine/tests/test_ema_crossover_strategy.py2
-rw-r--r--services/strategy-engine/tests/test_engine.py10
-rw-r--r--services/strategy-engine/tests/test_grid_strategy.py2
-rw-r--r--services/strategy-engine/tests/test_macd_strategy.py2
-rw-r--r--services/strategy-engine/tests/test_multi_symbol.py24
-rw-r--r--services/strategy-engine/tests/test_rsi_strategy.py2
-rw-r--r--services/strategy-engine/tests/test_sentiment_wiring.py32
-rw-r--r--services/strategy-engine/tests/test_volume_profile_strategy.py2
-rw-r--r--services/strategy-engine/tests/test_vwap_strategy.py2
13 files changed, 26 insertions, 248 deletions
diff --git a/services/strategy-engine/tests/test_asian_session_rsi.py b/services/strategy-engine/tests/test_asian_session_rsi.py
deleted file mode 100644
index db031f0..0000000
--- a/services/strategy-engine/tests/test_asian_session_rsi.py
+++ /dev/null
@@ -1,190 +0,0 @@
-"""Tests for Asian Session RSI strategy."""
-
-import sys
-from pathlib import Path
-
-sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
-
-from datetime import datetime, timezone
-from decimal import Decimal
-
-from shared.models import Candle, OrderSide
-from strategies.asian_session_rsi import AsianSessionRsiStrategy
-
-
-def _candle(price, hour=0, minute=30, volume=100.0, day=1):
- return Candle(
- symbol="SOLUSDT",
- timeframe="5m",
- open_time=datetime(2025, 1, day, hour, minute, tzinfo=timezone.utc),
- open=Decimal(str(price)),
- high=Decimal(str(price + 1)),
- low=Decimal(str(price - 1)),
- close=Decimal(str(price)),
- volume=Decimal(str(volume)),
- )
-
-
-def _make_strategy(**overrides):
- s = AsianSessionRsiStrategy()
- params = {
- "rsi_period": 5,
- "rsi_oversold": 30,
- "rsi_overbought": 70,
- "quantity": "0.5",
- "take_profit_pct": 1.5,
- "stop_loss_pct": 0.7,
- "session_start_utc": 0,
- "session_end_utc": 2,
- "max_trades_per_day": 3,
- "max_consecutive_losses": 2,
- }
- params.update(overrides)
- s.configure(params)
- return s
-
-
-def test_no_signal_outside_session():
- s = _make_strategy()
- # Hour 5 UTC = outside session (0-2 UTC)
- for i in range(10):
- sig = s.on_candle(_candle(100 - i * 3, hour=5))
- assert sig is None
-
-
-def test_buy_signal_during_session_on_oversold():
- s = AsianSessionRsiStrategy()
- s._rsi_period = 5
- s._rsi_oversold = 30
- s._quantity = Decimal("0.5")
- s._take_profit_pct = 1.5
- s._stop_loss_pct = 0.7
- s._session_start_utc = 0
- s._session_end_utc = 2
- s._max_trades_per_day = 3
- s._max_consecutive_losses = 10 # High limit so test isn't blocked
-
- # Feed declining prices — collect all signals
- signals = []
- for i in range(10):
- sig = s.on_candle(_candle(100 - i * 3, hour=0, minute=i * 5))
- if sig is not None:
- signals.append(sig)
-
- # Should have generated at least one BUY signal
- buy_signals = [s for s in signals if s.side == OrderSide.BUY]
- assert len(buy_signals) > 0
- assert buy_signals[0].strategy == "asian_session_rsi"
-
-
-def test_take_profit_exit():
- s = _make_strategy(rsi_period=5, rsi_oversold=40)
- # Force entry
- for i in range(8):
- s.on_candle(_candle(100 - i * 2, hour=0, minute=i * 5))
-
- # Should be in position now — push price up for TP
- sig = s.on_candle(_candle(100, hour=0, minute=50)) # entry ~around 84-86
- if s._in_position:
- tp_price = s._entry_price * (1 + s._take_profit_pct / 100)
- sig = s.on_candle(_candle(tp_price + 1, hour=1, minute=0))
- if sig is not None:
- assert sig.side == OrderSide.SELL
- assert "Take profit" in sig.reason
-
-
-def test_stop_loss_exit():
- s = _make_strategy(rsi_period=5, rsi_oversold=40)
- for i in range(8):
- s.on_candle(_candle(100 - i * 2, hour=0, minute=i * 5))
-
- if s._in_position:
- sl_price = s._entry_price * (1 - s._stop_loss_pct / 100)
- sig = s.on_candle(_candle(sl_price - 1, hour=1, minute=0))
- if sig is not None:
- assert sig.side == OrderSide.SELL
- assert "Stop loss" in sig.reason
-
-
-def test_time_exit_when_session_ends():
- s = _make_strategy(rsi_period=5, rsi_oversold=40)
- for i in range(8):
- s.on_candle(_candle(100 - i * 2, hour=0, minute=i * 5))
-
- if s._in_position:
- # Session ends at hour 2
- sig = s.on_candle(_candle(s._entry_price, hour=3, minute=0))
- if sig is not None:
- assert sig.side == OrderSide.SELL
- assert "Time exit" in sig.reason
-
-
-def test_max_trades_per_day():
- s = _make_strategy(rsi_period=3, rsi_oversold=40, max_trades_per_day=1)
- # Force one trade
- for i in range(6):
- s.on_candle(_candle(100 - i * 5, hour=0, minute=i * 5))
- # Exit
- if s._in_position:
- s.on_candle(_candle(200, hour=0, minute=35)) # TP exit
- # Try to enter again — should be blocked
- for i in range(6):
- s.on_candle(_candle(100 - i * 5, hour=1, minute=i * 5))
- # After 1 trade, no more allowed
- assert not s._in_position or s._trades_today >= 1
-
-
-def test_consecutive_losses_stop():
- s = _make_strategy(rsi_period=3, rsi_oversold=40, max_consecutive_losses=2)
- # Simulate 2 losses
- s._consecutive_losses = 2
- # Even with valid conditions, should not enter
- for i in range(6):
- sig = s.on_candle(_candle(100 - i * 5, hour=0, minute=i * 5))
- assert sig is None
-
-
-def test_reset_clears_all():
- s = _make_strategy()
- s.on_candle(_candle(100, hour=0))
- s._in_position = True
- s._trades_today = 2
- s._consecutive_losses = 1
- s.reset()
- assert not s._in_position
- assert s._trades_today == 0
- assert len(s._closes) == 0
-
-
-def test_warmup_period():
- s = _make_strategy(rsi_period=14)
- assert s.warmup_period == 15
-
-
-def test_ema_filter_blocks_below_ema():
- """Entry blocked when price is below EMA."""
- s = AsianSessionRsiStrategy()
- s._rsi_period = 5
- s._rsi_oversold = 40
- s._quantity = Decimal("0.5")
- s._take_profit_pct = 1.5
- s._stop_loss_pct = 0.7
- s._session_start_utc = 0
- s._session_end_utc = 2
- s._max_trades_per_day = 3
- s._max_consecutive_losses = 10
- s._ema_period = 5
- s._require_bullish_candle = False # Test EMA only
-
- # Feed rising prices to set EMA high, then sharp drop
- for i in range(10):
- s.on_candle(_candle(200 + i * 5, hour=0, minute=i * 5))
- # Now feed low price -- below EMA, RSI should be low
- signals = []
- for i in range(5):
- sig = s.on_candle(_candle(100 - i * 5, hour=0, minute=(15 + i) * 5 % 60))
- if sig is not None:
- signals.append(sig)
- # Should have no BUY signals because price is way below EMA
- buy_sigs = [s for s in signals if s.side == OrderSide.BUY]
- assert len(buy_sigs) == 0
diff --git a/services/strategy-engine/tests/test_base_filters.py b/services/strategy-engine/tests/test_base_filters.py
index 3e55973..ae9ca05 100644
--- a/services/strategy-engine/tests/test_base_filters.py
+++ b/services/strategy-engine/tests/test_base_filters.py
@@ -43,7 +43,7 @@ def _candle(price=100.0, volume=10.0, high=None, low=None):
h = high if high is not None else price + 5
lo = low if low is not None else price - 5
return Candle(
- symbol="BTCUSDT",
+ symbol="AAPL",
timeframe="1h",
open_time=datetime(2025, 1, 1, tzinfo=timezone.utc),
open=Decimal(str(price)),
diff --git a/services/strategy-engine/tests/test_bollinger_strategy.py b/services/strategy-engine/tests/test_bollinger_strategy.py
index 7761f2d..8261377 100644
--- a/services/strategy-engine/tests/test_bollinger_strategy.py
+++ b/services/strategy-engine/tests/test_bollinger_strategy.py
@@ -10,7 +10,7 @@ from strategies.bollinger_strategy import BollingerStrategy
def make_candle(close: float) -> Candle:
return Candle(
- symbol="BTC/USDT",
+ symbol="AAPL",
timeframe="1m",
open_time=datetime(2024, 1, 1, tzinfo=timezone.utc),
open=Decimal(str(close)),
diff --git a/services/strategy-engine/tests/test_combined_strategy.py b/services/strategy-engine/tests/test_combined_strategy.py
index 20a572e..8a4dc74 100644
--- a/services/strategy-engine/tests/test_combined_strategy.py
+++ b/services/strategy-engine/tests/test_combined_strategy.py
@@ -72,7 +72,7 @@ class NeutralStrategy(BaseStrategy):
def _candle(price=100.0):
return Candle(
- symbol="BTCUSDT",
+ symbol="AAPL",
timeframe="1m",
open_time=datetime(2025, 1, 1, tzinfo=timezone.utc),
open=Decimal(str(price)),
diff --git a/services/strategy-engine/tests/test_ema_crossover_strategy.py b/services/strategy-engine/tests/test_ema_crossover_strategy.py
index 67a20bf..7028eb0 100644
--- a/services/strategy-engine/tests/test_ema_crossover_strategy.py
+++ b/services/strategy-engine/tests/test_ema_crossover_strategy.py
@@ -10,7 +10,7 @@ from strategies.ema_crossover_strategy import EmaCrossoverStrategy
def make_candle(close: float) -> Candle:
return Candle(
- symbol="BTC/USDT",
+ symbol="AAPL",
timeframe="1m",
open_time=datetime(2024, 1, 1, tzinfo=timezone.utc),
open=Decimal(str(close)),
diff --git a/services/strategy-engine/tests/test_engine.py b/services/strategy-engine/tests/test_engine.py
index ac9a596..2623027 100644
--- a/services/strategy-engine/tests/test_engine.py
+++ b/services/strategy-engine/tests/test_engine.py
@@ -13,7 +13,7 @@ from strategy_engine.engine import StrategyEngine
def make_candle_event() -> dict:
candle = Candle(
- symbol="BTC/USDT",
+ symbol="AAPL",
timeframe="1m",
open_time=datetime(2024, 1, 1, tzinfo=timezone.utc),
open=Decimal("50000"),
@@ -28,7 +28,7 @@ def make_candle_event() -> dict:
def make_signal() -> Signal:
return Signal(
strategy="test",
- symbol="BTC/USDT",
+ symbol="AAPL",
side=OrderSide.BUY,
price=Decimal("50050"),
quantity=Decimal("0.01"),
@@ -46,12 +46,12 @@ async def test_engine_dispatches_candle_to_strategies():
strategy.on_candle = MagicMock(return_value=None)
engine = StrategyEngine(broker=broker, strategies=[strategy])
- await engine.process_once("candles.BTC_USDT", "0")
+ await engine.process_once("candles.AAPL", "0")
strategy.on_candle.assert_called_once()
candle_arg = strategy.on_candle.call_args[0][0]
assert isinstance(candle_arg, Candle)
- assert candle_arg.symbol == "BTC/USDT"
+ assert candle_arg.symbol == "AAPL"
@pytest.mark.asyncio
@@ -64,7 +64,7 @@ async def test_engine_publishes_signal_when_strategy_returns_one():
strategy.on_candle = MagicMock(return_value=make_signal())
engine = StrategyEngine(broker=broker, strategies=[strategy])
- await engine.process_once("candles.BTC_USDT", "0")
+ await engine.process_once("candles.AAPL", "0")
broker.publish.assert_called_once()
call_args = broker.publish.call_args
diff --git a/services/strategy-engine/tests/test_grid_strategy.py b/services/strategy-engine/tests/test_grid_strategy.py
index 9823f98..878b900 100644
--- a/services/strategy-engine/tests/test_grid_strategy.py
+++ b/services/strategy-engine/tests/test_grid_strategy.py
@@ -10,7 +10,7 @@ from strategies.grid_strategy import GridStrategy
def make_candle(close: float) -> Candle:
return Candle(
- symbol="BTC/USDT",
+ symbol="AAPL",
timeframe="1m",
open_time=datetime(2024, 1, 1, tzinfo=timezone.utc),
open=Decimal(str(close)),
diff --git a/services/strategy-engine/tests/test_macd_strategy.py b/services/strategy-engine/tests/test_macd_strategy.py
index 17dd2cf..556fd4c 100644
--- a/services/strategy-engine/tests/test_macd_strategy.py
+++ b/services/strategy-engine/tests/test_macd_strategy.py
@@ -10,7 +10,7 @@ from strategies.macd_strategy import MacdStrategy
def _candle(price: float) -> Candle:
return Candle(
- symbol="BTC/USDT",
+ symbol="AAPL",
timeframe="1m",
open_time=datetime(2024, 1, 1, tzinfo=timezone.utc),
open=Decimal(str(price)),
diff --git a/services/strategy-engine/tests/test_multi_symbol.py b/services/strategy-engine/tests/test_multi_symbol.py
index cb8088c..671a9d3 100644
--- a/services/strategy-engine/tests/test_multi_symbol.py
+++ b/services/strategy-engine/tests/test_multi_symbol.py
@@ -22,7 +22,7 @@ async def test_engine_processes_multiple_streams():
broker = AsyncMock()
candle_btc = Candle(
- symbol="BTCUSDT",
+ symbol="AAPL",
timeframe="1m",
open_time=datetime(2025, 1, 1, tzinfo=timezone.utc),
open=Decimal("50000"),
@@ -32,7 +32,7 @@ async def test_engine_processes_multiple_streams():
volume=Decimal("10"),
)
candle_eth = Candle(
- symbol="ETHUSDT",
+ symbol="MSFT",
timeframe="1m",
open_time=datetime(2025, 1, 1, tzinfo=timezone.utc),
open=Decimal("3000"),
@@ -45,16 +45,16 @@ async def test_engine_processes_multiple_streams():
btc_events = [CandleEvent(data=candle_btc).to_dict()]
eth_events = [CandleEvent(data=candle_eth).to_dict()]
- # First call returns BTC event, second ETH, then empty
- call_count = {"btc": 0, "eth": 0}
+ # First call returns AAPL event, second MSFT, then empty
+ call_count = {"aapl": 0, "msft": 0}
async def mock_read(stream, **kwargs):
- if "BTC" in stream:
- call_count["btc"] += 1
- return btc_events if call_count["btc"] == 1 else []
- elif "ETH" in stream:
- call_count["eth"] += 1
- return eth_events if call_count["eth"] == 1 else []
+ if "AAPL" in stream:
+ call_count["aapl"] += 1
+ return btc_events if call_count["aapl"] == 1 else []
+ elif "MSFT" in stream:
+ call_count["msft"] += 1
+ return eth_events if call_count["msft"] == 1 else []
return []
broker.read = AsyncMock(side_effect=mock_read)
@@ -65,8 +65,8 @@ async def test_engine_processes_multiple_streams():
engine = StrategyEngine(broker=broker, strategies=[strategy])
# Process both streams
- await engine.process_once("candles.BTCUSDT", "$")
- await engine.process_once("candles.ETHUSDT", "$")
+ await engine.process_once("candles.AAPL", "$")
+ await engine.process_once("candles.MSFT", "$")
# Strategy should have been called with both candles
assert strategy.on_candle.call_count == 2
diff --git a/services/strategy-engine/tests/test_rsi_strategy.py b/services/strategy-engine/tests/test_rsi_strategy.py
index b2aecc9..6d31fd5 100644
--- a/services/strategy-engine/tests/test_rsi_strategy.py
+++ b/services/strategy-engine/tests/test_rsi_strategy.py
@@ -10,7 +10,7 @@ from strategies.rsi_strategy import RsiStrategy
def make_candle(close: float, idx: int = 0) -> Candle:
return Candle(
- symbol="BTC/USDT",
+ symbol="AAPL",
timeframe="1m",
open_time=datetime(2024, 1, 1, tzinfo=timezone.utc),
open=Decimal(str(close)),
diff --git a/services/strategy-engine/tests/test_sentiment_wiring.py b/services/strategy-engine/tests/test_sentiment_wiring.py
deleted file mode 100644
index e0052cb..0000000
--- a/services/strategy-engine/tests/test_sentiment_wiring.py
+++ /dev/null
@@ -1,32 +0,0 @@
-"""Test sentiment is wired into strategy engine."""
-
-import sys
-from pathlib import Path
-
-sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
-sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
-
-from shared.sentiment import SentimentData
-from strategies.asian_session_rsi import AsianSessionRsiStrategy
-
-
-def test_strategy_accepts_sentiment():
- s = AsianSessionRsiStrategy()
- data = SentimentData(fear_greed_value=20, fear_greed_label="Extreme Fear")
- s.update_sentiment(data)
- assert s._sentiment is not None
- assert s._sentiment.fear_greed_value == 20
-
-
-def test_strategy_blocks_on_extreme_greed():
- s = AsianSessionRsiStrategy()
- data = SentimentData(fear_greed_value=85)
- s.update_sentiment(data)
- assert not s._check_sentiment()
-
-
-def test_strategy_allows_on_fear():
- s = AsianSessionRsiStrategy()
- data = SentimentData(fear_greed_value=20)
- s.update_sentiment(data)
- assert s._check_sentiment()
diff --git a/services/strategy-engine/tests/test_volume_profile_strategy.py b/services/strategy-engine/tests/test_volume_profile_strategy.py
index f40261c..65ee2e8 100644
--- a/services/strategy-engine/tests/test_volume_profile_strategy.py
+++ b/services/strategy-engine/tests/test_volume_profile_strategy.py
@@ -10,7 +10,7 @@ from strategies.volume_profile_strategy import VolumeProfileStrategy
def make_candle(close: float, volume: float = 1.0) -> Candle:
return Candle(
- symbol="BTC/USDT",
+ symbol="AAPL",
timeframe="1m",
open_time=datetime(2024, 1, 1, tzinfo=timezone.utc),
open=Decimal(str(close)),
diff --git a/services/strategy-engine/tests/test_vwap_strategy.py b/services/strategy-engine/tests/test_vwap_strategy.py
index 0312972..2c34b01 100644
--- a/services/strategy-engine/tests/test_vwap_strategy.py
+++ b/services/strategy-engine/tests/test_vwap_strategy.py
@@ -22,7 +22,7 @@ def make_candle(
if open_time is None:
open_time = datetime(2024, 1, 1, tzinfo=timezone.utc)
return Candle(
- symbol="BTC/USDT",
+ symbol="AAPL",
timeframe="1m",
open_time=open_time,
open=Decimal(str(close)),