diff options
| author | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-04-01 18:44:20 +0900 |
|---|---|---|
| committer | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-04-01 18:44:20 +0900 |
| commit | cb55c81dbc43df83ef4d5b717fe22b4d04a93d2e (patch) | |
| tree | 26ef6f6a89233fa8cf74ea6467b07f1158d75ff1 /services/strategy-engine/strategies/macd_strategy.py | |
| parent | 0b0aace94fa633cd7a90c95ee89658167a8afd35 (diff) | |
feat(strategy): apply filters, conviction scoring, and ATR stops to all strategies
Diffstat (limited to 'services/strategy-engine/strategies/macd_strategy.py')
| -rw-r--r-- | services/strategy-engine/strategies/macd_strategy.py | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/services/strategy-engine/strategies/macd_strategy.py b/services/strategy-engine/strategies/macd_strategy.py index bf30ed3..67c5e44 100644 --- a/services/strategy-engine/strategies/macd_strategy.py +++ b/services/strategy-engine/strategies/macd_strategy.py @@ -43,11 +43,30 @@ class MacdStrategy(BaseStrategy): if self._quantity <= 0: raise ValueError(f"Quantity must be positive, got {self._quantity}") + self._init_filters( + require_trend=True, + adx_threshold=float(params.get("adx_threshold", 25.0)), + min_volume_ratio=float(params.get("min_volume_ratio", 0.5)), + atr_stop_multiplier=float(params.get("atr_stop_multiplier", 2.0)), + atr_tp_multiplier=float(params.get("atr_tp_multiplier", 3.0)), + ) + def reset(self) -> None: self._closes.clear() self._prev_histogram = None + def _macd_conviction(self, histogram_value: float, price: float) -> float: + """Map histogram magnitude to conviction (0.1-1.0). + + Normalize by price to make it scale-independent. + """ + if price == 0: + return 0.5 + normalized = abs(histogram_value) / price * 1000 # scale to reasonable range + return min(1.0, max(0.1, normalized)) + def on_candle(self, candle: Candle) -> Signal | None: + self._update_filter_data(candle) self._closes.append(float(candle.close)) if len(self._closes) < self.warmup_period: @@ -65,6 +84,7 @@ class MacdStrategy(BaseStrategy): signal = None if self._prev_histogram is not None: + conviction = self._macd_conviction(current_histogram, float(candle.close)) # Bullish crossover: histogram crosses from negative to positive if self._prev_histogram <= 0 and current_histogram > 0: signal = Signal( @@ -73,6 +93,7 @@ class MacdStrategy(BaseStrategy): side=OrderSide.BUY, price=candle.close, quantity=self._quantity, + conviction=conviction, reason=f"MACD bullish crossover: histogram {self._prev_histogram:.6f} -> {current_histogram:.6f}", ) # Bearish crossover: histogram crosses from positive to negative @@ -83,8 +104,11 @@ class MacdStrategy(BaseStrategy): side=OrderSide.SELL, price=candle.close, quantity=self._quantity, + conviction=conviction, reason=f"MACD bearish crossover: histogram {self._prev_histogram:.6f} -> {current_histogram:.6f}", ) self._prev_histogram = current_histogram - return signal + if signal is not None: + return self._apply_filters(signal) + return None |
