summaryrefslogtreecommitdiff
path: root/services/order-executor/src/order_executor
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/order-executor/src/order_executor
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/order-executor/src/order_executor')
-rw-r--r--services/order-executor/src/order_executor/risk_manager.py30
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