diff options
| author | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-04-02 09:44:43 +0900 |
|---|---|---|
| committer | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-04-02 09:44:43 +0900 |
| commit | b9d21e2e2f7ae096c2f8a01bb142a685683b5b90 (patch) | |
| tree | a031989228ded9ff1e6d47840124ea5dcc9a9a3c /services/order-executor/src/order_executor | |
| parent | bb2e387f870495703fd663ca8f525028c3a8ced5 (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/order-executor/src/order_executor')
| -rw-r--r-- | services/order-executor/src/order_executor/risk_manager.py | 30 |
1 files changed, 22 insertions, 8 deletions
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 |
