From 2faec2f1f1631bd286a5c55051e582f8abe2898c Mon Sep 17 00:00:00 2001 From: TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> Date: Wed, 1 Apr 2026 16:16:03 +0900 Subject: feat(strategy): add MACD strategy --- .../strategy-engine/tests/test_macd_strategy.py | 80 ++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 services/strategy-engine/tests/test_macd_strategy.py (limited to 'services/strategy-engine/tests') 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 -- cgit v1.2.3