From 0d82cd2ad3655f0f5bef9b215ed804d0f0a9524a Mon Sep 17 00:00:00 2001 From: dekun Date: Thu, 11 Jun 2026 20:20:13 +0800 Subject: [PATCH] feat: show time-close countdown after symbol in monitor area Move timed-close badge next to contract name on hub board and instance position cards; refresh countdown on board render. Co-authored-by: Cursor --- crypto_monitor_binance/templates/index.html | 13 ++++--- crypto_monitor_gate/templates/index.html | 13 ++++--- crypto_monitor_gate_bot/templates/index.html | 13 ++++--- crypto_monitor_okx/templates/index.html | 13 ++++--- manual_trading_hub/static/app.css | 19 ++++++++++ manual_trading_hub/static/app.js | 40 ++++++++++++++------ manual_trading_hub/static/index.html | 4 +- static/instance_theme.css | 16 ++++++++ strategy_templates/key_monitor_panel.html | 6 +-- 9 files changed, 96 insertions(+), 41 deletions(-) diff --git a/crypto_monitor_binance/templates/index.html b/crypto_monitor_binance/templates/index.html index bd392c2..0038bc0 100644 --- a/crypto_monitor_binance/templates/index.html +++ b/crypto_monitor_binance/templates/index.html @@ -413,6 +413,13 @@
{{ o.exchange_symbol or o.symbol }} + {% if o.time_close_enabled %} + + 时间平仓 {{ o.time_close_hours or '' }}h + · --:--:-- + + {% endif %} {{ '做多' if o.direction == 'long' else '做空' }}
@@ -427,12 +434,6 @@ {% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %} - - 时间平仓 {{ o.time_close_hours or '' }}h - · 倒计时 --:--:-- -
diff --git a/crypto_monitor_gate/templates/index.html b/crypto_monitor_gate/templates/index.html index 44e6381..8527b61 100644 --- a/crypto_monitor_gate/templates/index.html +++ b/crypto_monitor_gate/templates/index.html @@ -393,6 +393,13 @@
{{ o.exchange_symbol or o.symbol }} + {% if o.time_close_enabled %} + + 时间平仓 {{ o.time_close_hours or '' }}h + · --:--:-- + + {% endif %} {{ '做多' if o.direction == 'long' else '做空' }}
@@ -407,12 +414,6 @@ {% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %} - - 时间平仓 {{ o.time_close_hours or '' }}h - · 倒计时 --:--:-- -
diff --git a/crypto_monitor_gate_bot/templates/index.html b/crypto_monitor_gate_bot/templates/index.html index 44e6381..8527b61 100644 --- a/crypto_monitor_gate_bot/templates/index.html +++ b/crypto_monitor_gate_bot/templates/index.html @@ -393,6 +393,13 @@
{{ o.exchange_symbol or o.symbol }} + {% if o.time_close_enabled %} + + 时间平仓 {{ o.time_close_hours or '' }}h + · --:--:-- + + {% endif %} {{ '做多' if o.direction == 'long' else '做空' }}
@@ -407,12 +414,6 @@ {% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %} - - 时间平仓 {{ o.time_close_hours or '' }}h - · 倒计时 --:--:-- -
diff --git a/crypto_monitor_okx/templates/index.html b/crypto_monitor_okx/templates/index.html index 9daa807..8f58eea 100644 --- a/crypto_monitor_okx/templates/index.html +++ b/crypto_monitor_okx/templates/index.html @@ -422,6 +422,13 @@
{{ o.exchange_symbol or o.symbol }} + {% if o.time_close_enabled %} + + 时间平仓 {{ o.time_close_hours or '' }}h + · --:--:-- + + {% endif %} {{ '做多' if o.direction == 'long' else '做空' }}
@@ -436,12 +443,6 @@ {% if o.breakeven_enabled %}移动保本:开 {{ o.breakeven_rr_trigger or '-' }}R→{{ price_fmt(o.symbol, o.breakeven_price) }}{% else %}移动保本:关{% endif %} - - 时间平仓 {{ o.time_close_hours or '' }}h - · 倒计时 --:--:-- -
diff --git a/manual_trading_hub/static/app.css b/manual_trading_hub/static/app.css index 5d633e4..d4cfd81 100644 --- a/manual_trading_hub/static/app.css +++ b/manual_trading_hub/static/app.css @@ -1023,6 +1023,25 @@ body.market-chart-fs-open { min-width: 0; } +.hub-pos-card .pos-symbol-time-close, +.hub-mini-title .pos-symbol-time-close { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 0.72rem; + font-weight: 500; + color: #8fc8ff; + padding: 1px 6px; + border-radius: 4px; + background: rgba(143, 200, 255, 0.1); + white-space: nowrap; + vertical-align: middle; +} +.hub-pos-card .pos-symbol-time-close .pos-time-close-cd, +.hub-mini-title .pos-symbol-time-close .pos-time-close-cd { + font-variant-numeric: tabular-nums; + letter-spacing: 0.03em; +} .hub-pos-card .pos-card-symbol strong { font-size: 14px; color: var(--text); diff --git a/manual_trading_hub/static/app.js b/manual_trading_hub/static/app.js index 98431b0..744696d 100644 --- a/manual_trading_hub/static/app.js +++ b/manual_trading_hub/static/app.js @@ -1495,6 +1495,9 @@ } syncMonitorGridColumns(box, displayRows.length); bindMonitorInteractions(box); + if (window.TimeCloseUI && TimeCloseUI.tickLocalCountdowns) { + TimeCloseUI.tickLocalCountdowns(); + } if (expandedExchangeId && fs && fsInner) { const row = rows.find((r) => String(r.id) === String(expandedExchangeId)); @@ -1505,6 +1508,9 @@ fs.setAttribute("aria-hidden", "false"); document.body.classList.add("hub-fullscreen-open"); bindMonitorInteractions(fsInner); + if (window.TimeCloseUI && TimeCloseUI.tickLocalCountdowns) { + TimeCloseUI.tickLocalCountdowns(); + } fsInner.querySelectorAll(".btn-expand-back").forEach((btn) => { btn.onclick = (ev) => { ev.stopPropagation(); @@ -2073,6 +2079,17 @@ return html; } + function timeCloseSymbolBadgeHtml(item) { + if (!item || !item.time_close_enabled) return ""; + const tcLabel = item.time_close_label || `时间平仓 ${item.time_close_hours || ""}h`; + const tcCd = item.time_close_countdown || "--:--:--"; + const tcAt = item.time_close_at_ms != null ? String(item.time_close_at_ms) : ""; + return ( + `` + + `${esc(tcLabel)} · ${esc(tcCd)}` + ); + } + function renderTrendDcaTable(t, tickMap) { const levels = resolveTrendDcaLevels(t); if (!levels.length) return ""; @@ -2304,26 +2321,18 @@ meta.push( `移动保本:${beOn ? "开" : "关"}` ); - if (mo.time_close_enabled) { - const tcLabel = mo.time_close_label || `时间平仓 ${mo.time_close_hours || ""}h`; - const tcCd = mo.time_close_countdown || "--:--:--"; - const tcAt = mo.time_close_at_ms != null ? String(mo.time_close_at_ms) : ""; - meta.push( - `` + - `${esc(tcLabel)} · 倒计时 ${esc(tcCd)}` - ); - } } else { meta.push("来源: 交易所持仓"); meta.push("风格: —"); meta.push(`移动保本:关`); } const symBeBadge = beSecured ? ` ${breakevenBadgeHtml()}` : ""; + const tcSymBadge = !isTrend && mo.time_close_enabled ? timeCloseSymbolBadgeHtml(mo) : ""; const mktAttrs = marketOpenBtnAttrs(exchangeId, exchangeKey, symbol, pos, monitorOrder, trendPlan); return `
- ${symBeBadge} + ${tcSymBadge}${symBeBadge} ${sideCn}
@@ -2382,8 +2391,14 @@ const amtLine = amtTxt ? `
挂单数量 ${esc(amtTxt)}
` : ""; + const keyTc = + k.time_close_enabled && k.time_close_at_ms + ? timeCloseSymbolBadgeHtml(k) + : k.time_close_enabled && k.time_close_hours + ? `时间平仓 ${esc(k.time_close_hours)}h` + : ""; return `
-
${esc(k.symbol)} · ${esc(mt)}${dir} ${pendingTag}
+
${esc(k.symbol)} ${keyTc} · ${esc(mt)}${dir} ${pendingTag}
上沿 ${esc(k.upper)} / 下沿 ${esc(k.lower)}
${amtLine}
${esc(kp.gate_summary || kp.price_display || kp.price || "—")}${kp.gate_metrics ? ` · ${esc(kp.gate_metrics)}` : ""}
@@ -2398,8 +2413,9 @@ return orders .map((o) => { const sym = o.exchange_symbol || o.symbol || ""; + const tcBadge = o.time_close_enabled ? timeCloseSymbolBadgeHtml(o) : ""; return `
-
#${esc(o.id)} · ${esc(o.symbol || o.exchange_symbol)} · ${renderDirectionHtml(o.direction)}
+
#${esc(o.id)} · ${esc(o.symbol || o.exchange_symbol)} ${tcBadge} · ${renderDirectionHtml(o.direction)}
触发 ${fmtSymbolPrice(o.trigger_price, sym, tickMap)} · SL ${fmtSymbolPrice(o.stop_loss, sym, tickMap)} · TP ${fmtSymbolPrice(o.take_profit, sym, tickMap)} · ${esc(o.trade_style || o.monitor_type || "下单监控")}
`; }) diff --git a/manual_trading_hub/static/index.html b/manual_trading_hub/static/index.html index 371b71d..3b74464 100644 --- a/manual_trading_hub/static/index.html +++ b/manual_trading_hub/static/index.html @@ -15,7 +15,7 @@ - + @@ -589,6 +589,6 @@ - + diff --git a/static/instance_theme.css b/static/instance_theme.css index 0f91b29..4a37a84 100644 --- a/static/instance_theme.css +++ b/static/instance_theme.css @@ -348,6 +348,22 @@ html[data-theme="light"] .pos-meta-item::after { font-variant-numeric: tabular-nums; letter-spacing: 0.02em; } +.pos-symbol-time-close { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 0.72rem; + font-weight: 500; + color: #8fc8ff; + padding: 1px 6px; + border-radius: 4px; + background: rgba(143, 200, 255, 0.1); + white-space: nowrap; +} +.pos-symbol-time-close .pos-time-close-cd { + font-variant-numeric: tabular-nums; + letter-spacing: 0.03em; +} .key-time-close-wrap.is-disabled > label, .order-time-close-wrap.is-disabled > label { opacity: 0.72; diff --git a/strategy_templates/key_monitor_panel.html b/strategy_templates/key_monitor_panel.html index a298414..767026f 100644 --- a/strategy_templates/key_monitor_panel.html +++ b/strategy_templates/key_monitor_panel.html @@ -182,6 +182,9 @@ {{ k.symbol }} + {% if k.time_close_enabled and k.time_close_hours %} + 时间平仓 {{ k.time_close_hours }}h + {% endif %} {% if k.direction == 'watch' %} 双向 {% else %} @@ -207,9 +210,6 @@ 方案: {{ key_sl_tp_mode_label(k) }} {% endif %} 保本: {{ '开' if k.breakeven_enabled else '关' }} - {% if k.time_close_enabled and k.time_close_hours %} - 时间平仓: {{ k.time_close_hours }}h - {% endif %}
现价-