diff --git a/backend/signal_engine.py b/backend/signal_engine.py index 188579a..301dc99 100644 --- a/backend/signal_engine.py +++ b/backend/signal_engine.py @@ -52,7 +52,8 @@ COOLDOWN_MS = 10 * 60 * 1000 def fetch_market_indicators(symbol: str) -> dict: - """从PG读取最新的market_indicators数据""" + """从PG读取最新的market_indicators数据,解析JSONB提取关键数值""" + import json as _json with get_sync_conn() as conn: with conn.cursor() as cur: indicators = {} @@ -62,7 +63,26 @@ def fetch_market_indicators(symbol: str) -> dict: (symbol, ind_type), ) row = cur.fetchone() - indicators[ind_type] = row[0] if row else None + if not row or row[0] is None: + indicators[ind_type] = None + continue + # value可能是JSON字符串或已解析的dict + val = row[0] + if isinstance(val, str): + try: + val = _json.loads(val) + except Exception: + indicators[ind_type] = None + continue + # 提取关键数值 + if ind_type == "long_short_ratio": + indicators[ind_type] = float(val.get("longShortRatio", 1.0)) + elif ind_type == "top_trader_position": + indicators[ind_type] = float(val.get("longAccount", 0.5)) + elif ind_type == "open_interest_hist": + indicators[ind_type] = float(val.get("sumOpenInterestValue", 0)) + elif ind_type == "coinbase_premium": + indicators[ind_type] = float(val.get("premium_pct", 0)) return indicators @@ -177,6 +197,7 @@ class SymbolState: self.warmup = True self.prev_cvd_fast = 0.0 self.prev_cvd_fast_slope = 0.0 + self.prev_oi_value = 0.0 self.market_indicators = fetch_market_indicators(symbol) self.last_signal_ts = 0 self.last_signal_dir = "" @@ -306,16 +327,21 @@ class SymbolState: top_trader_score = 5 crowding_score = ls_score + top_trader_score - # 3) 环境层(15分) - oi_change = to_float(self.market_indicators.get("open_interest_hist")) - if oi_change is None: - environment_score = 10 - elif oi_change >= 0.03: - environment_score = 15 - elif oi_change > 0: + # 3) 环境层(15分)— OI变化率 + oi_value = to_float(self.market_indicators.get("open_interest_hist")) + if oi_value is None or self.prev_oi_value == 0: environment_score = 10 + oi_change = 0.0 else: - environment_score = 5 + oi_change = (oi_value - self.prev_oi_value) / self.prev_oi_value if self.prev_oi_value > 0 else 0 + if oi_change >= 0.03: + environment_score = 15 + elif oi_change > 0: + environment_score = 10 + else: + environment_score = 5 + if oi_value is not None and oi_value > 0: + self.prev_oi_value = oi_value # 4) 确认层(15分) confirmation_score = 15 if ((direction == "LONG" and cvd_fast > 0 and cvd_mid > 0) or (direction == "SHORT" and cvd_fast < 0 and cvd_mid < 0)) else 0