summaryrefslogtreecommitdiff
path: root/services/strategy-engine/strategies/grid_strategy.py
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-02 09:44:43 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-02 09:44:43 +0900
commitb9d21e2e2f7ae096c2f8a01bb142a685683b5b90 (patch)
treea031989228ded9ff1e6d47840124ea5dcc9a9a3c /services/strategy-engine/strategies/grid_strategy.py
parentbb2e387f870495703fd663ca8f525028c3a8ced5 (diff)
feat: add market sentiment filters (Fear & Greed, CryptoPanic, CryptoQuant)
- 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
Diffstat (limited to 'services/strategy-engine/strategies/grid_strategy.py')
-rw-r--r--services/strategy-engine/strategies/grid_strategy.py21
1 files changed, 12 insertions, 9 deletions
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