From 0d27e13275b9739bcf64ba2d4456c8d9f9980661 Mon Sep 17 00:00:00 2001 From: dekun Date: Wed, 8 Jul 2026 19:08:08 +0800 Subject: [PATCH] Fix header funds flicker and unify settings page top bar. Preserve SSR fund values when account_snapshot returns null, retry on failure, and show the same instance header panel on system settings. Co-authored-by: Cursor --- lib/common/static/instance_embed.js | 5 +- lib/common/static/instance_live.js | 1 + .../templates/embed_boot_scripts.html | 180 +++++++++------- lib/instance/templates/embed_shell.html | 4 +- lib/instance/templates/index.html | 202 ++++++++++-------- .../templates/instance_header_panel.html | 1 + .../templates/instance_header_stats.html | 18 +- lib/instance/templates/settings_panel.html | 15 +- 8 files changed, 236 insertions(+), 190 deletions(-) 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' %} - + diff --git a/lib/instance/templates/index.html b/lib/instance/templates/index.html index 3614c3c..7d131b3 100644 --- a/lib/instance/templates/index.html +++ b/lib/instance/templates/index.html @@ -68,9 +68,7 @@ {% with msg=get_flashed_messages() %}{% if msg %}
{{ msg[0] }}
{% endif %}{% endwith %} - {% if page != 'settings' %} {% include 'instance_header_panel.html' %} - {% endif %} {% if page != 'settings' and page != 'options' %} {% include 'instance_top_bar.html' %} {% endif %} @@ -1593,18 +1591,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; @@ -1645,87 +1648,112 @@ function formatOptionsFundingLabel(usdc, usdt) { return parts.length ? parts.join(" · ") : "—"; } -function refreshAccountSnapshot(){ - fetch("/api/account_snapshot").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`; - } - 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`; - } - 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 || ""; - } +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); } - if (data.force_close && window.TimeCloseUI && TimeCloseUI.paintForceCloseHeader) { - TimeCloseUI.paintForceCloseHeader(data.force_close); + if((data.active_count||0) >= (data.max_active_positions||{{ max_active_positions }})) parts.push(`持仓 ${data.active_count}/${data.max_active_positions}`); + 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(data.open_guard_blocks_now) parts.push(`未到北京时间 ${data.reset_hour||{{ reset_hour }}}:00`); + canTradeText = parts.length ? `不可开仓(${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`; + } + const allowEl = document.getElementById("allow-open-before-reset"); + const guardStatus = document.getElementById("open-guard-status"); + const resetH = data.reset_hour != null ? data.reset_hour : {{ reset_hour }}; + if(allowEl && typeof data.open_guard_enabled !== "undefined"){ + allowEl.checked = !data.open_guard_enabled; + } + if(guardStatus && typeof data.open_guard_enabled !== "undefined"){ + guardStatus.innerText = data.open_guard_enabled + ? `已限制:${resetH}:00 前不可开仓` + : `已放开:${resetH}:00 前允许开仓`; + } +} +function refreshAccountSnapshot(opts){ + const options = opts || {}; + const qs = options.force ? "?force=1" : ""; + fetch("/api/account_snapshot" + qs).then(r=>r.json()).then(data=>{ + 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; } - 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); - } - if((data.active_count||0) >= (data.max_active_positions||{{ max_active_positions }})) parts.push(`持仓 ${data.active_count}/${data.max_active_positions}`); - 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(data.open_guard_blocks_now) parts.push(`未到北京时间 ${data.reset_hour||{{ reset_hour }}}:00`); - canTradeText = parts.length ? `不可开仓(${parts.join(";")})` : "不可开仓"; + }).catch(()=>{ + if(!options.silent && accountSnapshotRetryCount < 3){ + accountSnapshotRetryCount += 1; + setTimeout(() => refreshAccountSnapshot({ silent: true }), 1200 * accountSnapshotRetryCount); } - 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`; - } - const allowEl = document.getElementById("allow-open-before-reset"); - const guardStatus = document.getElementById("open-guard-status"); - const resetH = data.reset_hour != null ? data.reset_hour : {{ reset_hour }}; - if(allowEl && typeof data.open_guard_enabled !== "undefined"){ - allowEl.checked = !data.open_guard_enabled; - } - if(guardStatus && typeof data.open_guard_enabled !== "undefined"){ - guardStatus.innerText = data.open_guard_enabled - ? `已限制:${resetH}:00 前不可开仓` - : `已放开:${resetH}:00 前允许开仓`; - } - }).catch(()=>{}); + }); } {% if ui_open_guard_enabled %} @@ -1801,7 +1829,7 @@ if(window.ManualOrderRrPreview){ refreshAccountSnapshot(); const settingsRefreshFunds = document.getElementById("settings-refresh-funds"); -if (settingsRefreshFunds) settingsRefreshFunds.addEventListener("click", refreshAccountSnapshot); +if (settingsRefreshFunds) settingsRefreshFunds.addEventListener("click", function(){ refreshAccountSnapshot({ force: true }); }); if (window.AccountRiskBadge) AccountRiskBadge.startTicker(); const _journalFormEl = document.getElementById("journal-form"); if(_journalFormEl){ diff --git a/lib/instance/templates/instance_header_panel.html b/lib/instance/templates/instance_header_panel.html index 09229bb..b42a598 100644 --- a/lib/instance/templates/instance_header_panel.html +++ b/lib/instance/templates/instance_header_panel.html @@ -32,6 +32,7 @@ {{ risk_status.status_label|default('正常') }} {% include 'instance_theme_toggle.html' %} +
diff --git a/lib/instance/templates/instance_header_stats.html b/lib/instance/templates/instance_header_stats.html index bda5660..4a5cea7 100644 --- a/lib/instance/templates/instance_header_stats.html +++ b/lib/instance/templates/instance_header_stats.html @@ -10,40 +10,40 @@
总交易
-
{{ total }}
+
{{ total }}
胜率
-
{{ rate }}%
+
{{ rate }}%
盈亏比
-
{% if profit_loss_ratio is not none %}{{ profit_loss_ratio }}{% else %}—{% endif %}
+
{% if profit_loss_ratio is not none %}{{ profit_loss_ratio }}{% else %}—{% endif %}
总资金
-
{% if total_funds is not none %}{{ funds_fmt(total_funds) }}U{% else %}—{% endif %}
+
{% if total_funds is not none %}{{ funds_fmt(total_funds) }}U{% else %}—{% endif %}
资金账户
-
{% if funding_usdt is not none %}{{ funds_fmt(funding_usdt) }}U{% else %}—{% endif %}
+
{% if funding_usdt is not none %}{{ funds_fmt(funding_usdt) }}U{% else %}—{% endif %}
交易账户
-
{{ funds_fmt(current_capital) }}U
+
{{ funds_fmt(current_capital) }}U
{% if options_enabled %}
期权资金账户
-
{{ options_funding_label(options_funding_usdc, options_funding_usdt) }}
+
{{ options_funding_label(options_funding_usdc, options_funding_usdt) }}
期权交易账户
-
{% if options_trading_usdc is not none %}{{ funds_fmt(options_trading_usdc) }} USDC{% else %}—{% endif %}
+
{% if options_trading_usdc is not none %}{{ funds_fmt(options_trading_usdc) }} USDC{% else %}—{% endif %}
{% endif %}
实时盈亏
-
+
diff --git a/lib/instance/templates/settings_panel.html b/lib/instance/templates/settings_panel.html index 57a01f6..9a43a39 100644 --- a/lib/instance/templates/settings_panel.html +++ b/lib/instance/templates/settings_panel.html @@ -1,18 +1,5 @@ -{# 系统设置:左风控说明 · 右资金划转 + 数据导出 #} +{# 系统设置:左风控说明 · 右资金划转 + 数据导出(顶栏资金与统计见 instance_header_panel) #}
-

风控说明