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 --- .../src/order_executor/risk_manager.py | 30 ++++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'services/order-executor/src/order_executor') diff --git a/services/order-executor/src/order_executor/risk_manager.py b/services/order-executor/src/order_executor/risk_manager.py index 94d15c2..5a05746 100644 --- a/services/order-executor/src/order_executor/risk_manager.py +++ b/services/order-executor/src/order_executor/risk_manager.py @@ -212,8 +212,16 @@ class RiskManager: prices_a = prices_a[-min_len:] prices_b = prices_b[-min_len:] - returns_a = [(prices_a[i] - prices_a[i-1]) / prices_a[i-1] for i in range(1, len(prices_a)) if prices_a[i-1] != 0] - returns_b = [(prices_b[i] - prices_b[i-1]) / prices_b[i-1] for i in range(1, len(prices_b)) if prices_b[i-1] != 0] + returns_a = [ + (prices_a[i] - prices_a[i - 1]) / prices_a[i - 1] + for i in range(1, len(prices_a)) + if prices_a[i - 1] != 0 + ] + returns_b = [ + (prices_b[i] - prices_b[i - 1]) / prices_b[i - 1] + for i in range(1, len(prices_b)) + if prices_b[i - 1] != 0 + ] if len(returns_a) < 3 or len(returns_b) < 3: return None @@ -225,7 +233,9 @@ class RiskManager: mean_a = sum(returns_a) / len(returns_a) mean_b = sum(returns_b) / len(returns_b) - cov = sum((a - mean_a) * (b - mean_b) for a, b in zip(returns_a, returns_b)) / len(returns_a) + cov = sum((a - mean_a) * (b - mean_b) for a, b in zip(returns_a, returns_b)) / len( + returns_a + ) std_a = math.sqrt(sum((a - mean_a) ** 2 for a in returns_a) / len(returns_a)) std_b = math.sqrt(sum((b - mean_b) ** 2 for b in returns_b) / len(returns_b)) @@ -253,7 +263,11 @@ class RiskManager: if not hist or len(hist) < 5: continue prices = list(hist) - returns = [(prices[i] - prices[i-1]) / prices[i-1] for i in range(1, len(prices)) if prices[i-1] != 0] + returns = [ + (prices[i] - prices[i - 1]) / prices[i - 1] + for i in range(1, len(prices)) + if prices[i - 1] != 0 + ] if returns: all_returns.append(returns) weight = float(pos.quantity * pos.current_price / balance) @@ -280,15 +294,15 @@ class RiskManager: return abs(var_return) * 100 # As percentage - def check_portfolio_exposure(self, positions: dict[str, Position], balance: Decimal) -> RiskCheckResult: + def check_portfolio_exposure( + self, positions: dict[str, Position], balance: Decimal + ) -> RiskCheckResult: """Check total portfolio exposure.""" if balance <= 0: return RiskCheckResult(allowed=True, reason="OK") total_exposure = sum( - pos.quantity * pos.current_price - for pos in positions.values() - if pos.quantity > 0 + pos.quantity * pos.current_price for pos in positions.values() if pos.quantity > 0 ) exposure_ratio = total_exposure / balance -- cgit v1.2.3