diff options
Diffstat (limited to 'services/strategy-engine/strategies/vwap_strategy.py')
| -rw-r--r-- | services/strategy-engine/strategies/vwap_strategy.py | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/services/strategy-engine/strategies/vwap_strategy.py b/services/strategy-engine/strategies/vwap_strategy.py index d220832..c525ff3 100644 --- a/services/strategy-engine/strategies/vwap_strategy.py +++ b/services/strategy-engine/strategies/vwap_strategy.py @@ -32,6 +32,14 @@ class VwapStrategy(BaseStrategy): if self._quantity <= 0: raise ValueError(f"Quantity must be positive, got {self._quantity}") + self._init_filters( + require_trend=False, + 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._cumulative_tp_vol = 0.0 self._cumulative_vol = 0.0 @@ -39,7 +47,17 @@ class VwapStrategy(BaseStrategy): self._was_below_vwap = False self._was_above_vwap = False + def _vwap_conviction(self, deviation: float) -> float: + """Map VWAP deviation magnitude to conviction (0.1-1.0). + + Further from VWAP = stronger mean reversion signal. + """ + magnitude = abs(deviation) + # Scale: at threshold -> 0.3, at 5x threshold -> ~1.0 + return min(1.0, max(0.1, magnitude / self._deviation_threshold * 0.3)) + def on_candle(self, candle: Candle) -> Signal | None: + self._update_filter_data(candle) high = float(candle.high) low = float(candle.low) close = float(candle.close) @@ -69,25 +87,31 @@ class VwapStrategy(BaseStrategy): # Mean reversion from below: was below VWAP, now back near it if self._was_below_vwap and abs(deviation) <= self._deviation_threshold: self._was_below_vwap = False - return Signal( + conviction = self._vwap_conviction(deviation) + signal = Signal( strategy=self.name, symbol=candle.symbol, side=OrderSide.BUY, price=candle.close, quantity=self._quantity, + conviction=conviction, reason=f"VWAP mean reversion BUY: deviation {deviation:.4f} within threshold {self._deviation_threshold}", ) + return self._apply_filters(signal) # Mean reversion from above: was above VWAP, now back near it if self._was_above_vwap and abs(deviation) <= self._deviation_threshold: self._was_above_vwap = False - return Signal( + conviction = self._vwap_conviction(deviation) + signal = Signal( strategy=self.name, symbol=candle.symbol, side=OrderSide.SELL, price=candle.close, quantity=self._quantity, + conviction=conviction, reason=f"VWAP mean reversion SELL: deviation {deviation:.4f} within threshold {self._deviation_threshold}", ) + return self._apply_filters(signal) return None |
