summaryrefslogtreecommitdiff
path: root/services/strategy-engine/tests/test_macd_strategy.py
diff options
context:
space:
mode:
Diffstat (limited to 'services/strategy-engine/tests/test_macd_strategy.py')
-rw-r--r--services/strategy-engine/tests/test_macd_strategy.py80
1 files changed, 80 insertions, 0 deletions
diff --git a/services/strategy-engine/tests/test_macd_strategy.py b/services/strategy-engine/tests/test_macd_strategy.py
new file mode 100644
index 0000000..e1ae2a3
--- /dev/null
+++ b/services/strategy-engine/tests/test_macd_strategy.py
@@ -0,0 +1,80 @@
+"""Tests for the MACD strategy."""
+from datetime import datetime, timezone
+from decimal import Decimal
+
+import pytest
+
+from shared.models import Candle, OrderSide
+from strategies.macd_strategy import MacdStrategy
+
+
+def _candle(price: float) -> Candle:
+ return Candle(
+ symbol="BTC/USDT",
+ timeframe="1m",
+ open_time=datetime(2024, 1, 1, tzinfo=timezone.utc),
+ open=Decimal(str(price)),
+ high=Decimal(str(price)),
+ low=Decimal(str(price)),
+ close=Decimal(str(price)),
+ volume=Decimal("1.0"),
+ )
+
+
+def _make_strategy(**kwargs) -> MacdStrategy:
+ params = {"fast_period": 3, "slow_period": 6, "signal_period": 3, "quantity": "0.01"}
+ params.update(kwargs)
+ s = MacdStrategy()
+ s.configure(params)
+ return s
+
+
+def test_macd_warmup_period():
+ s = _make_strategy()
+ assert s.warmup_period == 6 + 3 # slow_period + signal_period
+
+
+def test_macd_no_signal_insufficient_data():
+ s = _make_strategy()
+ # Feed fewer candles than warmup_period
+ for price in [100.0, 101.0, 102.0]:
+ result = s.on_candle(_candle(price))
+ assert result is None
+
+
+def test_macd_buy_signal_on_bullish_crossover():
+ s = _make_strategy()
+ # Declining prices drive MACD histogram negative, then rising prices cross positive
+ prices = [100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88]
+ prices += [89, 91, 94, 98, 103, 109, 116, 124, 133, 143]
+ signal = None
+ for p in prices:
+ result = s.on_candle(_candle(float(p)))
+ if result is not None:
+ signal = result
+ assert signal is not None, "Expected a BUY signal from bullish crossover"
+ assert signal.side == OrderSide.BUY
+
+
+def test_macd_sell_signal_on_bearish_crossover():
+ s = _make_strategy()
+ # Rising prices drive MACD histogram positive, then declining prices cross negative
+ prices = [100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112]
+ prices += [111, 109, 106, 102, 97, 91, 84, 76, 67, 57]
+ signal = None
+ for p in prices:
+ result = s.on_candle(_candle(float(p)))
+ if result is not None:
+ signal = result
+ assert signal is not None, "Expected a SELL signal from bearish crossover"
+ assert signal.side == OrderSide.SELL
+
+
+def test_macd_reset_clears_state():
+ s = _make_strategy()
+ for p in [100, 101, 102, 103, 104, 105, 106, 107, 108]:
+ s.on_candle(_candle(float(p)))
+ assert len(s._closes) > 0
+ s.reset()
+ assert len(s._closes) == 0
+ assert s._prev_histogram is None