From 24bb8532c47c562d601959cc7eefc566a19e465d Mon Sep 17 00:00:00 2001 From: dekun Date: Tue, 11 Aug 2026 11:21:30 +0800 Subject: [PATCH] fix(options): soft-poll chain quotes so list asks stay fresh SSE only refreshed positions; chain asks were one-shot until manual reload, which could mislead open decisions. Co-authored-by: Cursor --- lib/common/static/options_panel.js | 49 ++++++++++++++++++++++-- lib/options/templates/options_panel.html | 2 +- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/lib/common/static/options_panel.js b/lib/common/static/options_panel.js index 677e3da..b8504d3 100644 --- a/lib/common/static/options_panel.js +++ b/lib/common/static/options_panel.js @@ -37,9 +37,14 @@ let selectSeq = 0; let refreshAllTimer = null; let pendingRefreshTimer = null; + let chainSoftTimer = null; + let lastChainSoftAt = 0; + let chainQuotedAt = 0; let pendingTtlSeconds = 600; const POSITIONS_STALE_MS = 45000; const PENDING_POLL_MS = 8000; + /** 链卖一/买一静默刷新节流:无推送,靠拉;过密会撞 OKX 50011 */ + const CHAIN_SOFT_POLL_MS = 15000; const orderPanelHome = (function () { const host = document.getElementById("opt-order-panel-host"); return host ? host.parentElement : null; @@ -632,6 +637,15 @@ if (el) el.textContent = fmt(buf, 2); } + function fmtChainQuotedAt() { + if (!chainQuotedAt) return ""; + const d = new Date(chainQuotedAt); + const pad = function (n) { + return n < 10 ? "0" + n : String(n); + }; + return pad(d.getHours()) + ":" + pad(d.getMinutes()) + ":" + pad(d.getSeconds()); + } + function renderIndexLine() { const idx = state.chain && state.chain.index_px; const dte = state.chain && state.chain.chain_max_dte_days; @@ -645,12 +659,36 @@ const line = document.getElementById("opt-index-line"); if (line) { const liqHint = askLiqFilterOn() ? "仅显示卖一深度≥1张" : "显示全部卖一(含估算~)"; + const ageHint = chainQuotedAt ? " · 链报价 " + fmtChainQuotedAt() + "(约每15s静默刷新)" : ""; line.textContent = "指数 " + state.underlying + " ≈ " + fmt(idx, 2) + - " · 默认最近一期 · " + liqHint + " · 实值含平值 · 虚值=价外"; + " · 默认最近一期 · " + liqHint + " · 实值含平值 · 虚值=价外" + ageHint; } } + function softRefreshChainThrottled(force) { + if (document.hidden) return; + if (!document.getElementById("options-root")) return; + const now = Date.now(); + if (!force && now - lastChainSoftAt < CHAIN_SOFT_POLL_MS) return; + lastChainSoftAt = now; + void loadChain({ soft: true }); + } + + function startChainSoftPoll() { + if (chainSoftTimer) return; + chainSoftTimer = setInterval(function () { + if (!document.getElementById("options-root")) { + if (chainSoftTimer) { + clearInterval(chainSoftTimer); + chainSoftTimer = null; + } + return; + } + softRefreshChainThrottled(false); + }, CHAIN_SOFT_POLL_MS); + } + function pickNearestExpiry(exps) { if (!exps || !exps.length) return ""; const now = Date.now(); @@ -1269,6 +1307,8 @@ panelCache.chain = d; panelCache.underlying = uly; panelCache.optType = state.optType; + chainQuotedAt = Date.now(); + lastChainSoftAt = chainQuotedAt; syncAskLiqFilterFromChain(d); if (!soft) { state.selectedInst = null; @@ -2206,6 +2246,7 @@ updateUnderlyingLabel(); refreshPendingOrders(); startPendingOrdersPoll(); + startChainSoftPoll(); const hasCache = chainHasExpiries(panelCache.chain) && panelCache.underlying === state.underlying && @@ -2215,8 +2256,8 @@ renderExpiries(); renderStrikes(); refreshAllPositions(); - // 后台静默刷新,避免缓存过期后到期日变空 - loadChain({ soft: true }); + // 后台静默刷新,避免缓存过期后到期日变空 / 卖一过期 + softRefreshChainThrottled(true); return; } requestAnimationFrame(function () { @@ -2340,6 +2381,8 @@ window.OptionsPanelLive = { refreshSoft: function () { refreshAllPositions(); + // embed SSE 只通知「该拉了」,不推送链报价;这里节流拉新鲜卖一/买一 + softRefreshChainThrottled(false); }, refreshChain: loadChain, }; diff --git a/lib/options/templates/options_panel.html b/lib/options/templates/options_panel.html index f345380..7ba1c7b 100644 --- a/lib/options/templates/options_panel.html +++ b/lib/options/templates/options_panel.html @@ -322,4 +322,4 @@ - +