From 424cb993f833670f432db8a7b6c36246738e7f4a Mon Sep 17 00:00:00 2001 From: root Date: Sat, 28 Feb 2026 06:09:32 +0000 Subject: [PATCH] feat: signal history list + always compute scoring even without signal --- backend/main.py | 17 +++++++++ backend/signal_engine.py | 15 ++++---- frontend/app/signals/page.tsx | 67 +++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/backend/main.py b/backend/main.py index 7dbc0ad..8940139 100644 --- a/backend/main.py +++ b/backend/main.py @@ -461,6 +461,23 @@ async def get_market_indicators(user: dict = Depends(get_current_user)): return result +@app.get("/api/signals/history") +async def get_signal_history( + symbol: str = "BTC", + limit: int = 50, + user: dict = Depends(get_current_user), +): + """返回最近的信号历史(只返回有信号的记录)""" + sym_full = symbol.upper() + "USDT" + rows = await async_fetch( + "SELECT ts, score, signal FROM signal_indicators " + "WHERE symbol = $1 AND signal IS NOT NULL " + "ORDER BY ts DESC LIMIT $2", + sym_full, limit + ) + return {"symbol": symbol, "count": len(rows), "data": rows} + + @app.get("/api/signals/trades") async def get_signal_trades( status: str = "all", diff --git a/backend/signal_engine.py b/backend/signal_engine.py index bf23c31..2101555 100644 --- a/backend/signal_engine.py +++ b/backend/signal_engine.py @@ -241,15 +241,18 @@ class SymbolState: if self.warmup or price == 0 or atr == 0: return result - if now_ms - self.last_signal_ts < COOLDOWN_MS: - return result + + # 判断倾向方向(用于评分展示,即使冷却或方向不一致也计算) + no_direction = False + in_cooldown = (now_ms - self.last_signal_ts < COOLDOWN_MS) if cvd_fast > 0 and cvd_mid > 0: direction = "LONG" elif cvd_fast < 0 and cvd_mid < 0: direction = "SHORT" else: - return result + direction = "LONG" if cvd_fast > 0 else "SHORT" + no_direction = True # V5.1 五层评分体系(总分100,方向层可因加速额外+5) # 1) 方向层(45分 + 5加速分) @@ -345,13 +348,13 @@ class SymbolState: "auxiliary": {"score": aux_score, "coinbase_premium": coinbase_premium}, } - if total_score >= 85: + if total_score >= 85 and not no_direction and not in_cooldown: result["signal"] = direction result["tier"] = "heavy" - elif total_score >= 75: + elif total_score >= 75 and not no_direction and not in_cooldown: result["signal"] = direction result["tier"] = "standard" - elif total_score >= 60: + elif total_score >= 60 and not no_direction and not in_cooldown: result["signal"] = direction result["tier"] = "light" else: diff --git a/frontend/app/signals/page.tsx b/frontend/app/signals/page.tsx index 52a16a3..d9af84b 100644 --- a/frontend/app/signals/page.tsx +++ b/frontend/app/signals/page.tsx @@ -162,6 +162,70 @@ function MarketIndicatorsCards({ symbol }: { symbol: Symbol }) { ); } +// ─── 信号历史 ──────────────────────────────────────────────────── + +interface SignalRecord { + ts: number; + score: number; + signal: string; +} + +function bjtFull(ms: number) { + const d = new Date(ms + 8 * 3600 * 1000); + return `${String(d.getUTCMonth() + 1).padStart(2, "0")}-${String(d.getUTCDate()).padStart(2, "0")} ${String(d.getUTCHours()).padStart(2, "0")}:${String(d.getUTCMinutes()).padStart(2, "0")}:${String(d.getUTCSeconds()).padStart(2, "0")}`; +} + +function SignalHistory({ symbol }: { symbol: Symbol }) { + const [data, setData] = useState([]); + + useEffect(() => { + const fetchData = async () => { + try { + const res = await authFetch(`/api/signals/history?symbol=${symbol}&limit=20`); + if (!res.ok) return; + const json = await res.json(); + setData(json.data || []); + } catch {} + }; + fetchData(); + const iv = setInterval(fetchData, 15000); + return () => clearInterval(iv); + }, [symbol]); + + if (data.length === 0) return null; + + return ( +
+
+

最近信号

+

最近20条有效信号记录(北京时间)

+
+
+ {data.map((s, i) => ( +
+
+ + {s.signal === "LONG" ? "🟢 LONG" : "🔴 SHORT"} + + {bjtFull(s.ts)} +
+
+ {s.score}/100 + = 85 ? "bg-red-100 text-red-700" : + s.score >= 75 ? "bg-blue-100 text-blue-700" : + "bg-slate-100 text-slate-600" + }`}> + {s.score >= 85 ? "加仓" : s.score >= 75 ? "标准" : "轻仓"} + +
+
+ ))} +
+
+ ); +} + // ─── 实时指标卡片 ──────────────────────────────────────────────── function IndicatorCards({ symbol }: { symbol: Symbol }) { @@ -410,6 +474,9 @@ export default function SignalsPage() { + {/* 信号历史 */} + + {/* CVD三轨图 */}