diff --git a/hub_ohlcv_lib.py b/hub_ohlcv_lib.py index 7e9ee2b..6213c11 100644 --- a/hub_ohlcv_lib.py +++ b/hub_ohlcv_lib.py @@ -67,6 +67,20 @@ def normalize_chart_timeframe(raw: str | None, default: str = "5m") -> str: return tf if tf in CHART_TIMEFRAMES else default +def normalize_perpetual_symbol(symbol: str) -> str: + """BTC/USDT → BTC/USDT:USDT(与四所 ccxt swap 行情一致)。""" + sym = (symbol or "").strip().upper() + if not sym: + return "" + if ":" in sym: + return sym + if "/" in sym: + base, quote = sym.split("/", 1) + quote_clean = quote.split(":")[0] + return f"{base}/{quote_clean}:{quote_clean}" + return sym + + def sync_timeframe_for_display(timeframe: str) -> str: """展示周期对应的入库 / 同步周期。""" tf = normalize_chart_timeframe(timeframe) diff --git a/hub_symbol_archive_lib.py b/hub_symbol_archive_lib.py index 4ced9d4..92e470a 100644 --- a/hub_symbol_archive_lib.py +++ b/hub_symbol_archive_lib.py @@ -17,6 +17,7 @@ from hub_ohlcv_lib import ( TIMEFRAME_MS, aggregate_ohlcv_bars, normalize_chart_timeframe, + normalize_perpetual_symbol, ) from hub_trades_lib import ( display_entry_type_label, @@ -927,10 +928,13 @@ def resolve_archive_chart( if not candles: return {"ok": False, "msg": "视窗内无 K 线"} + ex_sym = normalize_perpetual_symbol(sym) return { "ok": True, "exchange_key": ex_k, "symbol": sym, + "exchange_symbol": ex_sym, + "market_type": "swap", "timeframe": tf, "mode": (mode or "hold").strip().lower(), "range_mode": rm, diff --git a/manual_trading_hub/static/app.css b/manual_trading_hub/static/app.css index 547c137..1b931a7 100644 --- a/manual_trading_hub/static/app.css +++ b/manual_trading_hub/static/app.css @@ -5800,13 +5800,15 @@ body.funds-fullscreen-open { cursor: pointer; } .archive-trade-row.is-active { - background: var(--inset-surface); + background: color-mix(in srgb, var(--accent) 16%, var(--inset-surface)); + box-shadow: inset 3px 0 0 var(--accent); } .archive-trade-row.archive-trade-sick td { color: var(--red); } .archive-trade-row.archive-trade-sick.is-active { - background: var(--inset-surface); + background: color-mix(in srgb, var(--accent) 12%, color-mix(in srgb, var(--red) 8%, var(--panel))); + box-shadow: inset 3px 0 0 var(--accent); } .archive-trade-row.archive-trade-sick .archive-tag-select, .archive-trade-row.archive-trade-sick .archive-note-input { diff --git a/manual_trading_hub/static/archive.js b/manual_trading_hub/static/archive.js index 82bda7c..68cce59 100644 --- a/manual_trading_hub/static/archive.js +++ b/manual_trading_hub/static/archive.js @@ -66,6 +66,8 @@ let inited = false; let markAuto = true; let lastCandles = []; + let chartExchangeSymbol = ""; + let chartMarketType = "swap"; let searchTimer = null; function esc(s) { @@ -309,13 +311,27 @@ scheduleChartResize(); } + function formatChartContractLabel(sym, exchangeSymbol, marketType) { + const base = String(sym || "—"); + const mt = String(marketType || "").toLowerCase(); + if (mt === "swap" || (exchangeSymbol && String(exchangeSymbol).indexOf(":") >= 0)) { + return base + " 永续"; + } + return base; + } + function updateChartTitle() { if (!elChartTitle) return; if (!selected) { elChartTitle.textContent = "—"; return; } - elChartTitle.textContent = selected.symbol + " · " + exchangeLabel(selected.exchange_key); + const label = formatChartContractLabel( + selected.symbol, + chartExchangeSymbol, + chartMarketType + ); + elChartTitle.textContent = label + " · " + exchangeLabel(selected.exchange_key); } async function apiFetch(url, opts) { @@ -871,6 +887,8 @@ setStatus(j.detail || "K 线加载失败"); return; } + chartExchangeSymbol = j.exchange_symbol || ""; + chartMarketType = j.market_type || "swap"; if (chart) { destroyChart(); } @@ -900,7 +918,14 @@ } updateChartTitle(); scheduleChartResize(); - setStatus("K 线 " + candles.length + " 根 · " + timeframe); + setStatus( + "K 线 " + + candles.length + + " 根 · " + + timeframe + + " · " + + formatChartContractLabel(selected.symbol, chartExchangeSymbol, chartMarketType) + ); } async function openTradeChart(tr) { @@ -913,6 +938,7 @@ } selected = { exchange_key: exKey, symbol: sym }; selectedTradeId = String(tr.trade_id || tr.id); + renderTrades(); setChartOpen(true); await loadSymbolTradesForChart(exKey, sym); await loadChart(); diff --git a/manual_trading_hub/static/index.html b/manual_trading_hub/static/index.html index 2e51e7d..6a66161 100644 --- a/manual_trading_hub/static/index.html +++ b/manual_trading_hub/static/index.html @@ -15,7 +15,7 @@ - +
@@ -584,7 +584,7 @@ - +