From 98038b1945dd97718fad55bde2cc5f0c9544ff61 Mon Sep 17 00:00:00 2001 From: dekun Date: Wed, 3 Jun 2026 23:25:43 +0800 Subject: [PATCH] feat(hub): show key/trend/roll counts on monitor cards Add per-card strategy stats chips for breakout, fib, and watch key levels plus trend and roll plan counts when non-zero. Co-authored-by: Cursor --- manual_trading_hub/static/app.css | 33 ++++++++++++++ manual_trading_hub/static/app.js | 67 ++++++++++++++++++++++++++++ manual_trading_hub/static/index.html | 4 +- 3 files changed, 102 insertions(+), 2 deletions(-) diff --git a/manual_trading_hub/static/app.css b/manual_trading_hub/static/app.css index 144923f..fbd80f1 100644 --- a/manual_trading_hub/static/app.css +++ b/manual_trading_hub/static/app.css @@ -1280,6 +1280,39 @@ body.market-chart-fs-open { border-bottom: 1px dashed var(--border-soft); } +.card-strategy-stats { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin: 10px 0 4px; + padding-top: 8px; + border-top: 1px dashed var(--border-soft); +} + +.card-stat-chip { + display: inline-flex; + align-items: center; + padding: 3px 8px; + border-radius: 6px; + font-size: 11px; + line-height: 1.3; + color: var(--accent); + background: var(--accent-dim); + border: 1px solid var(--border-soft); +} + +.hub-tile .card-strategy-stats { + margin: 4px 0 0; + padding-top: 6px; + border-top: none; + gap: 4px; +} + +.hub-tile .card-stat-chip { + font-size: 10px; + padding: 2px 6px; +} + .pos-action-group { display: inline-flex; flex-direction: row; diff --git a/manual_trading_hub/static/app.js b/manual_trading_hub/static/app.js index 105684e..5062498 100644 --- a/manual_trading_hub/static/app.js +++ b/manual_trading_hub/static/app.js @@ -1606,6 +1606,68 @@ `; } + const KEY_BUCKET_FIB_TYPES = new Set([ + "斐波回调0.618", + "斐波回调0.786", + "关键位斐波0.618", + "关键位斐波0.786", + ]); + const KEY_BUCKET_BREAKOUT_TYPES = new Set([ + "箱体突破", + "收敛突破", + "关键位箱体突破", + "关键位收敛突破", + "关键位收敛结构", + ]); + const KEY_BUCKET_WATCH_TYPES = new Set([ + "关键阻力位", + "关键支撑位", + "关键位监控", + ]); + + function classifyKeyMonitorBucket(monitorType) { + const t = String(monitorType || "").trim(); + if (!t) return "watch"; + if (KEY_BUCKET_FIB_TYPES.has(t) || /斐波/.test(t)) return "fib"; + if (KEY_BUCKET_BREAKOUT_TYPES.has(t) || /突破/.test(t)) return "breakout"; + if (KEY_BUCKET_WATCH_TYPES.has(t) || /阻力|支撑/.test(t)) return "watch"; + return "watch"; + } + + function countKeyMonitorsByBucket(keys) { + const counts = { breakout: 0, fib: 0, watch: 0 }; + (keys || []).forEach((k) => { + if (!k || typeof k !== "object") return; + const bucket = classifyKeyMonitorBucket(k.monitor_type || k.type); + if (bucket === "breakout") counts.breakout += 1; + else if (bucket === "fib") counts.fib += 1; + else counts.watch += 1; + }); + return counts; + } + + function renderCardStrategyStats(row, hm, flaskOk) { + if (!flaskOk || !hm || typeof hm !== "object") return ""; + const caps = row.capabilities || []; + const chips = []; + if (caps.includes("key")) { + const kc = countKeyMonitorsByBucket(hm.keys || []); + if (kc.breakout > 0) chips.push(`突破 ${kc.breakout}`); + if (kc.fib > 0) chips.push(`斐波 ${kc.fib}`); + if (kc.watch > 0) chips.push(`监控 ${kc.watch}`); + } + if (caps.includes("trend")) { + const trendN = Array.isArray(hm.trends) ? hm.trends.length : 0; + if (trendN > 0) chips.push(`趋势回调 ${trendN}`); + } + const rollN = Array.isArray(hm.rolls) ? hm.rolls.length : 0; + if (rollN > 0) chips.push(`顺势加仓 ${rollN}`); + if (!chips.length) return ""; + return `
${chips + .map((label) => `${esc(label)}`) + .join("")}
`; + } + function renderGridPositionsTable(exchangeId, exchangeKey, positions, orders, trends, tickMap) { const rows = positions .map((p) => @@ -1646,6 +1708,7 @@ } else { inner += '
无持仓
'; } + inner += renderCardStrategyStats(row, hm, flaskOk); inner += `
点击标题栏进入全屏 · 委托 / 关键位 / 下单监控 / 趋势回调 / 顺势加仓
`; return inner; } @@ -1925,6 +1988,9 @@ const tsShort = ts ? ts.slice(-8) : "—"; const posLine = openCount > 0 ? `${openCount}仓 · ${alert.summary}` : alert.summary; + const hm = row.hub_monitor || {}; + const flaskOk = row.flask_ok !== false && hm.ok !== false; + const strategyStats = renderCardStrategyStats(row, hm, flaskOk); return `
@@ -1933,6 +1999,7 @@
${fmt(upnl, 2)} U
${esc(posLine)}
+ ${strategyStats}
UPD ${esc(tsShort)}
`; diff --git a/manual_trading_hub/static/index.html b/manual_trading_hub/static/index.html index 8abd24a..1685344 100644 --- a/manual_trading_hub/static/index.html +++ b/manual_trading_hub/static/index.html @@ -8,7 +8,7 @@ - + @@ -246,6 +246,6 @@
- +