diff --git a/lib/common/static/instance_embed.js b/lib/common/static/instance_embed.js index 0963b12..7d00bad 100644 --- a/lib/common/static/instance_embed.js +++ b/lib/common/static/instance_embed.js @@ -99,6 +99,9 @@ if (typeof global.initStatsSegmentFromUrl === "function") global.initStatsSegmentFromUrl(); } if (!revisit) { + if (typeof global.refreshAccountSnapshot === "function") { + global.refreshAccountSnapshot({ silent: true }); + } if (typeof global.refreshPriceSnapshotConditional === "function") { global.refreshPriceSnapshotConditional(); } @@ -240,7 +243,7 @@ function syncShellChrome(tab) { const onSettings = tab === "settings"; - document.querySelectorAll(".instance-header-panel, .instance-top-bar").forEach((el) => { + document.querySelectorAll(".instance-top-bar").forEach((el) => { el.hidden = onSettings; }); } diff --git a/lib/common/static/instance_live.js b/lib/common/static/instance_live.js index 05bdace..ce30606 100644 --- a/lib/common/static/instance_live.js +++ b/lib/common/static/instance_live.js @@ -47,6 +47,7 @@ if (!ver) return; if (reason === "connect") { localLiveVersion = ver; + scheduleRefresh(); return; } if (ver === localLiveVersion) return; diff --git a/lib/instance/templates/embed_boot_scripts.html b/lib/instance/templates/embed_boot_scripts.html index 609ff47..8339139 100644 --- a/lib/instance/templates/embed_boot_scripts.html +++ b/lib/instance/templates/embed_boot_scripts.html @@ -1039,18 +1039,23 @@ function refreshOrderDefaults(){ } function paintRealtimePnl(v){ - const pnlEl = document.getElementById("realtime-pnl"); - if(!pnlEl) return; + const nodes = document.querySelectorAll('[data-funds-field="realtime-pnl"]'); + if(!nodes.length) return; if(v === null || v === undefined || Number.isNaN(Number(v))){ - pnlEl.innerText = "—"; - pnlEl.classList.remove("pnl-pos", "pnl-neg"); + nodes.forEach((pnlEl) => { + pnlEl.innerText = "—"; + pnlEl.classList.remove("pnl-pos", "pnl-neg"); + }); return; } const n = Number(v); const sign = n > 0 ? "+" : ""; - pnlEl.innerText = `${sign}${n.toFixed(2)}U`; - pnlEl.classList.toggle("pnl-pos", n > 0); - pnlEl.classList.toggle("pnl-neg", n < 0); + const text = `${sign}${n.toFixed(2)}U`; + nodes.forEach((pnlEl) => { + pnlEl.innerText = text; + pnlEl.classList.toggle("pnl-pos", n > 0); + pnlEl.classList.toggle("pnl-neg", n < 0); + }); } function sumOrdersFloatPnl(orders){ if(!orders || !orders.length) return null; @@ -1091,81 +1096,104 @@ function formatOptionsFundingLabel(usdc, usdt) { return parts.length ? parts.join(" · ") : "—"; } +function setFundsFieldText(field, text){ + if(text == null || text === "") return; + document.querySelectorAll(`[data-funds-field="${field}"]`).forEach((el) => { + el.innerText = text; + }); +} +function accountSnapshotFundingMissing(data){ + if(!data || typeof data !== "object") return true; + const hasFunding = data.funding_usdt != null && data.funding_usdt !== ""; + const hasTotal = data.total_funds != null && data.total_funds !== ""; + const hasTrading = data.current_capital != null && data.current_capital !== ""; + return !hasFunding && !hasTotal && !hasTrading; +} +let accountSnapshotRetryCount = 0; +function applyAccountSnapshot(data){ + if(!data || typeof data !== "object") return; + if(data.funding_usdt != null && data.funding_usdt !== ""){ + setFundsFieldText("total-capital", `${Number(data.funding_usdt).toFixed(2)}U`); + } + if(data.total_funds != null && data.total_funds !== ""){ + setFundsFieldText("total-funds", `${Number(data.total_funds).toFixed(2)}U`); + } + if(data.current_capital != null && data.current_capital !== "" && !Number.isNaN(Number(data.current_capital))){ + setFundsFieldText("current-capital", `${Number(data.current_capital).toFixed(2)}U`); + } + if(data.options_funding_usdc != null || data.options_funding_usdt != null){ + const optFunding = formatOptionsFundingLabel(data.options_funding_usdc, data.options_funding_usdt); + if(optFunding !== "—") setFundsFieldText("options-funding-usdc", optFunding); + } + if(data.options_trading_usdc != null && data.options_trading_usdc !== ""){ + setFundsFieldText("options-trading-usdc", `${Number(data.options_trading_usdc).toFixed(2)} USDC`); + } + if(typeof data.unrealized_pnl !== "undefined"){ + paintRealtimePnl(data.unrealized_pnl); + } + if(typeof data.available_trading_usdt !== "undefined" && data.available_trading_usdt !== null){ + latestAvailableUsdt = Number(data.available_trading_usdt); + } + if(data.risk_status){ + document.querySelectorAll("#account-risk-badge").forEach((badge) => { + if(window.AccountRiskBadge){ + AccountRiskBadge.applyToElement(badge, data.risk_status); + }else{ + const st = data.risk_status.status || "normal"; + badge.className = "risk-status-badge risk-status-" + st; + badge.innerText = data.risk_status.status_label || "正常"; + badge.title = data.risk_status.reason || ""; + } + }); + } + if(data.force_close && window.TimeCloseUI && TimeCloseUI.paintForceCloseHeader){ + TimeCloseUI.paintForceCloseHeader(data.force_close); + } + let canTradeText = "可开仓"; + if(!data.can_trade){ + const parts = []; + if(data.risk_status && data.risk_status.can_trade === false && data.risk_status.reason){ + parts.push(data.risk_status.reason); + } + const ac = Number(data.active_count || 0); + const max = Number(data.max_active_positions || {{ max_active_positions }}); + if(ac >= max) parts.push(`持仓 ${ac}/${max}`); + const hard = Number(data.daily_open_hard_limit != null ? data.daily_open_hard_limit : {{ daily_open_hard_limit }}); + const opens = Number(data.opens_today); + if(hard > 0 && !Number.isNaN(opens) && opens >= hard) parts.push(`本交易日开仓 ${opens}/${hard} 已达上限`); + if(!parts.length) parts.push(`未到北京时间 {{ reset_hour }}:00`); + else parts.push(`或未到北京时间 {{ reset_hour }}:00`); + canTradeText = `不可开仓(${parts.join(";")})`; + } + const opensToday = Number(data.opens_today); + const hardLim = Number(data.daily_open_hard_limit != null ? data.daily_open_hard_limit : {{ daily_open_hard_limit }}); + const alertLim = Number(data.daily_open_alert_threshold != null ? data.daily_open_alert_threshold : {{ daily_open_alert_threshold }}); + const openCntTxt = !Number.isNaN(opensToday) + ? `本交易日开仓 ${opensToday}${hardLim > 0 ? ` / 硬上限 ${hardLim}` : ""}(AI 提醒 ${alertLim})` + : ""; + const tip = document.getElementById("order-rule-tip"); + const avail = (latestAvailableUsdt !== null && !Number.isNaN(latestAvailableUsdt)) ? `;交易账户可用约${latestAvailableUsdt.toFixed(2)}U` : ""; + if(tip){ + tip.innerText = `规则:最多 ${data.max_active_positions || {{ max_active_positions }}} 仓;BTC {{ btc_leverage }}x / 山寨 {{ alt_leverage }}x;${openCntTxt ? openCntTxt + ";" : ""}${canTradeText}${avail};人工开仓盈亏比不得低于 {{ manual_min_planned_rr }}:1`; + } +} function refreshAccountSnapshot(opts){ const options = opts || {}; const qs = options.force ? "?force=1" : ""; fetch("/api/account_snapshot" + qs).then(r=>r.json()).then(data=>{ - if (typeof data.funding_usdt !== "undefined") { - const el = document.getElementById("total-capital"); - if(el) el.innerText = (data.funding_usdt === null || data.funding_usdt === undefined) ? "—" : `${Number(data.funding_usdt).toFixed(2)}U`; + applyAccountSnapshot(data); + if(accountSnapshotFundingMissing(data) && !options.force && accountSnapshotRetryCount < 3){ + accountSnapshotRetryCount += 1; + setTimeout(() => refreshAccountSnapshot({ silent: true, force: accountSnapshotRetryCount >= 2 }), 1200 * accountSnapshotRetryCount); + }else if(!accountSnapshotFundingMissing(data)){ + accountSnapshotRetryCount = 0; } - if (typeof data.total_funds !== "undefined") { - const el = document.getElementById("total-funds"); - if(el) el.innerText = (data.total_funds === null || data.total_funds === undefined) ? "—" : `${Number(data.total_funds).toFixed(2)}U`; + }).catch(()=>{ + if(!options.silent && accountSnapshotRetryCount < 3){ + accountSnapshotRetryCount += 1; + setTimeout(() => refreshAccountSnapshot({ silent: true }), 1200 * accountSnapshotRetryCount); } - if (typeof data.current_capital !== "undefined") { - const el = document.getElementById("current-capital"); - if(el) el.innerText = `${Number(data.current_capital).toFixed(2)}U`; - } - if (typeof data.options_funding_usdc !== "undefined" || typeof data.options_funding_usdt !== "undefined") { - const el = document.getElementById("options-funding-usdc"); - if (el) el.innerText = formatOptionsFundingLabel(data.options_funding_usdc, data.options_funding_usdt); - } - if (typeof data.options_trading_usdc !== "undefined") { - const el = document.getElementById("options-trading-usdc"); - if (el) el.innerText = (data.options_trading_usdc === null || data.options_trading_usdc === undefined) - ? "—" : `${Number(data.options_trading_usdc).toFixed(2)} USDC`; - } - if (typeof data.unrealized_pnl !== "undefined") { - paintRealtimePnl(data.unrealized_pnl); - } - if (typeof data.available_trading_usdt !== "undefined" && data.available_trading_usdt !== null) { - latestAvailableUsdt = Number(data.available_trading_usdt); - } - if (data.risk_status) { - const badge = document.getElementById("account-risk-badge"); - if (badge) { - if (window.AccountRiskBadge) { - AccountRiskBadge.applyToElement(badge, data.risk_status); - } else { - const st = data.risk_status.status || "normal"; - badge.className = "risk-status-badge risk-status-" + st; - badge.innerText = data.risk_status.status_label || "正常"; - badge.title = data.risk_status.reason || ""; - } - } - } - if (data.force_close && window.TimeCloseUI && TimeCloseUI.paintForceCloseHeader) { - TimeCloseUI.paintForceCloseHeader(data.force_close); - } - let canTradeText = "可开仓"; - if (!data.can_trade) { - const parts = []; - if (data.risk_status && data.risk_status.can_trade === false && data.risk_status.reason) { - parts.push(data.risk_status.reason); - } - const ac = Number(data.active_count || 0); - const max = Number(data.max_active_positions || {{ max_active_positions }}); - if (ac >= max) parts.push(`持仓 ${ac}/${max}`); - const hard = Number(data.daily_open_hard_limit != null ? data.daily_open_hard_limit : {{ daily_open_hard_limit }}); - const opens = Number(data.opens_today); - if (hard > 0 && !Number.isNaN(opens) && opens >= hard) parts.push(`本交易日开仓 ${opens}/${hard} 已达上限`); - if (!parts.length) parts.push(`未到北京时间 {{ reset_hour }}:00`); - else parts.push(`或未到北京时间 {{ reset_hour }}:00`); - canTradeText = `不可开仓(${parts.join(";")})`; - } - const opensToday = Number(data.opens_today); - const hardLim = Number(data.daily_open_hard_limit != null ? data.daily_open_hard_limit : {{ daily_open_hard_limit }}); - const alertLim = Number(data.daily_open_alert_threshold != null ? data.daily_open_alert_threshold : {{ daily_open_alert_threshold }}); - const openCntTxt = !Number.isNaN(opensToday) - ? `本交易日开仓 ${opensToday}${hardLim > 0 ? ` / 硬上限 ${hardLim}` : ""}(AI 提醒 ${alertLim})` - : ""; - const tip = document.getElementById("order-rule-tip"); - const avail = (latestAvailableUsdt !== null && !Number.isNaN(latestAvailableUsdt)) ? `;交易账户可用约${latestAvailableUsdt.toFixed(2)}U` : ""; - if(tip){ - tip.innerText = `规则:最多 ${data.max_active_positions || {{ max_active_positions }}} 仓;BTC {{ btc_leverage }}x / 山寨 {{ alt_leverage }}x;${openCntTxt ? openCntTxt + ";" : ""}${canTradeText}${avail};人工开仓盈亏比不得低于 {{ manual_min_planned_rr }}:1`; - } - }).catch(()=>{}); + }); } const orderSymbolEl = document.getElementById("order-symbol"); diff --git a/lib/instance/templates/embed_shell.html b/lib/instance/templates/embed_shell.html index f5a0b4c..8d1c860 100644 --- a/lib/instance/templates/embed_shell.html +++ b/lib/instance/templates/embed_shell.html @@ -43,9 +43,7 @@
- {% if initial_tab != 'settings' %} {% include 'instance_header_panel.html' %} - {% endif %} {% if initial_tab != 'settings' and include_transfer_block %} {% include 'instance_top_bar.html' %} {% endif %} @@ -91,6 +89,6 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj {% include 'embed_boot_scripts.html' %} - +