summaryrefslogtreecommitdiff
path: root/services/strategy-engine/strategies/vwap_strategy.py
diff options
context:
space:
mode:
Diffstat (limited to 'services/strategy-engine/strategies/vwap_strategy.py')
-rw-r--r--services/strategy-engine/strategies/vwap_strategy.py28
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