From b9d21e2e2f7ae096c2f8a01bb142a685683b5b90 Mon Sep 17 00:00:00 2001 From: TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> Date: Thu, 2 Apr 2026 09:44:43 +0900 Subject: feat: add market sentiment filters (Fear & Greed, CryptoPanic, CryptoQuant) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SentimentProvider: fetches Fear & Greed Index (free, no key), CryptoPanic news sentiment (free key), CryptoQuant exchange netflow (free key) - SentimentData: aggregated should_buy/should_block logic - Fear < 30 = buy opportunity, Greed > 80 = block buying - Negative news < -0.5 = block buying - Exchange outflow = bullish, inflow = bearish - Integrated into Asian Session RSI strategy as entry filter - All providers optional — disabled when API key missing - 14 sentiment tests + 386 total tests passing --- .../strategy-engine/strategies/grid_strategy.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'services/strategy-engine/strategies/grid_strategy.py') diff --git a/services/strategy-engine/strategies/grid_strategy.py b/services/strategy-engine/strategies/grid_strategy.py index 07ccaba..283bfe5 100644 --- a/services/strategy-engine/strategies/grid_strategy.py +++ b/services/strategy-engine/strategies/grid_strategy.py @@ -40,9 +40,7 @@ class GridStrategy(BaseStrategy): f"got lower={self._lower_price}, upper={self._upper_price}" ) if self._exit_threshold_pct <= 0: - raise ValueError( - f"exit_threshold_pct must be > 0, got {self._exit_threshold_pct}" - ) + raise ValueError(f"exit_threshold_pct must be > 0, got {self._exit_threshold_pct}") if self._grid_count < 2: raise ValueError(f"Grid grid_count must be >= 2, got {self._grid_count}") if self._quantity <= 0: @@ -90,12 +88,17 @@ class GridStrategy(BaseStrategy): if not self._out_of_range: self._out_of_range = True # Exit signal — close positions - return self._apply_filters(Signal( - strategy=self.name, symbol=candle.symbol, - side=OrderSide.SELL, price=candle.close, - quantity=self._quantity, conviction=0.8, - reason=f"Grid: price {price:.2f} broke out of range [{self._grid_levels[0]:.2f}, {self._grid_levels[-1]:.2f}]", - )) + return self._apply_filters( + Signal( + strategy=self.name, + symbol=candle.symbol, + side=OrderSide.SELL, + price=candle.close, + quantity=self._quantity, + conviction=0.8, + reason=f"Grid: price {price:.2f} broke out of range [{self._grid_levels[0]:.2f}, {self._grid_levels[-1]:.2f}]", + ) + ) return None # Already out of range, no more signals else: self._out_of_range = False -- cgit v1.2.3