diff --git a/crypto_monitor_okx/app.py b/crypto_monitor_okx/app.py index b034de4..5aef30f 100644 --- a/crypto_monitor_okx/app.py +++ b/crypto_monitor_okx/app.py @@ -6613,6 +6613,7 @@ def render_main_page(page="trade", embed_mode=None): show_perp_funds_enabled, total_funds_usdt, trade_records_summary, + trading_account_label, ) plan = embed_render_plan(page, embed_mode) @@ -6628,6 +6629,7 @@ def render_main_page(page="trade", embed_mode=None): options_trading_usdt = None options_funding_eth = None options_trading_eth = None + options_trading_btc = None options_margin_mode = "usdc" options_underly = "ETH" if ( @@ -6643,8 +6645,9 @@ def render_main_page(page="trade", embed_mode=None): options_funding_usdc = _op.get("funding_usdc") options_funding_usdt = _op.get("funding_usdt") options_trading_usdt = _op.get("trading_usdt") - options_funding_eth = _op.get("funding_coin") - options_trading_eth = _op.get("trading_coin") + options_funding_eth = _op.get("funding_eth") + options_trading_eth = _op.get("trading_eth") + options_trading_btc = _op.get("trading_btc") options_margin_mode = _op.get("options_margin_mode") or "usdc" options_underly = _op.get("options_underly") or "ETH" except Exception: @@ -6654,6 +6657,7 @@ def render_main_page(page="trade", embed_mode=None): options_trading_usdt = None options_funding_eth = None options_trading_eth = None + options_trading_btc = None options_margin_mode = "usdc" options_underly = "ETH" recommended_capital = get_recommended_capital(current_capital) @@ -6809,6 +6813,7 @@ def render_main_page(page="trade", embed_mode=None): options_trading_usdt=options_trading_usdt, options_funding_eth=options_funding_eth, options_trading_eth=options_trading_eth, + options_trading_btc=options_trading_btc, options_margin_mode=options_margin_mode, options_underly=options_underly, trading_day=trading_day, @@ -6876,9 +6881,10 @@ def render_main_page(page="trade", embed_mode=None): key_rule_ctx=key_rule_ctx, funds_fmt=format_funds_u, options_funding_label=options_funding_label, + trading_account_label=trading_account_label, exchange_display=EXCHANGE_DISPLAY_NAME, options_enabled=OKX_OPTIONS_ENABLED, - show_perp_funds=_show_perp_funds, + show_perp_funds=_show_perp_funds or (options_margin_mode == "coin"), options_nav_visible=True, okx_trade_mode=_okx_trade_mode, options_open_allowed=_okx_trade_mode == "options", @@ -7070,6 +7076,7 @@ def api_account_snapshot(): options_trading_usdt = None options_funding_eth = None options_trading_eth = None + options_trading_btc = None options_margin_mode = "usdc" options_underly = "ETH" if OKX_OPTIONS_ENABLED and exchange_options.apiKey: @@ -7081,8 +7088,9 @@ def api_account_snapshot(): options_funding_usdc = _op.get("funding_usdc") options_funding_usdt = _op.get("funding_usdt") options_trading_usdt = _op.get("trading_usdt") - options_funding_eth = _op.get("funding_coin") - options_trading_eth = _op.get("trading_coin") + options_funding_eth = _op.get("funding_eth") + options_trading_eth = _op.get("trading_eth") + options_trading_btc = _op.get("trading_btc") options_margin_mode = _op.get("options_margin_mode") or "usdc" options_underly = _op.get("options_underly") or "ETH" except Exception: @@ -7092,6 +7100,7 @@ def api_account_snapshot(): options_trading_usdt = None options_funding_eth = None options_trading_eth = None + options_trading_btc = None options_margin_mode = "usdc" options_underly = "ETH" recommended_capital = get_recommended_capital(current_capital) @@ -7167,7 +7176,7 @@ def api_account_snapshot(): unrealized_pnl = merge_unrealized_pnl_components(unrealized_pnl, options_unrealized_pnl) except Exception: options_unrealized_pnl = None - _show_perp_funds = show_perp_funds_enabled(exchange_key="okx") + _show_perp_funds = show_perp_funds_enabled(exchange_key="okx") or (options_margin_mode == "coin") return jsonify({ "funding_usdt": funding_usdt, "current_capital": current_capital, @@ -7178,6 +7187,7 @@ def api_account_snapshot(): "options_trading_usdt": options_trading_usdt, "options_funding_eth": options_funding_eth, "options_trading_eth": options_trading_eth, + "options_trading_btc": options_trading_btc, "options_margin_mode": options_margin_mode, "options_underly": options_underly, "total_funds": total_funds_usdt( diff --git a/lib/instance/instance_embed_context_lib.py b/lib/instance/instance_embed_context_lib.py index 22704da..c695b1e 100644 --- a/lib/instance/instance_embed_context_lib.py +++ b/lib/instance/instance_embed_context_lib.py @@ -107,10 +107,39 @@ def options_funding_label( margin_mode: str | None = None, underly: str = "ETH", ) -> str: - """期权侧顶栏文案. + """期权侧顶栏文案(仅 USDC 模式使用;币本位不展示期权资金/交易两列).""" + if funding_usdc is None: + return "—" + try: + return f"{float(funding_usdc):.2f} USDC" + except (TypeError, ValueError): + return "—" - USDC 模式:仅 USDC. - 币本位:USDT + 标的币(ETH/BTC). + +def _fmt_coin_amount(v: float | None) -> str | None: + if v is None: + return None + try: + n = float(v) + except (TypeError, ValueError): + return None + if abs(n) < 1e-12: + return None + txt = f"{n:.6f}".rstrip("0").rstrip(".") + return txt or None + + +def trading_account_label( + usdt: float | None, + eth: float | None = None, + btc: float | None = None, + *, + margin_mode: str | None = None, +) -> str: + """交易账户顶栏文案. + + 币本位:USDT / ETH / BTC(有余额才带上,不显示其它币种). + 其它模式:xx.xxU. """ try: from lib.options.options_margin_mode_lib import normalize_options_margin_mode @@ -118,29 +147,26 @@ def options_funding_label( mode = normalize_options_margin_mode(margin_mode) except Exception: mode = str(margin_mode or "usdc").strip().lower() or "usdc" - if mode == "coin": - parts: list[str] = [] - if funding_usdt is not None: - try: - parts.append(f"{float(funding_usdt):.2f} USDT") - except (TypeError, ValueError): - pass - coin = funding_eth - ccy = (underly or "ETH").strip().upper() or "ETH" - if coin is not None: - try: - n = float(coin) - txt = f"{n:.6f}".rstrip("0").rstrip(".") - parts.append(f"{txt or '0'} {ccy}") - except (TypeError, ValueError): - pass - return " / ".join(parts) if parts else "—" - if funding_usdc is None: - return "—" - try: - return f"{float(funding_usdc):.2f} USDC" - except (TypeError, ValueError): - return "—" + if mode != "coin": + if usdt is None: + return "—" + try: + return f"{float(usdt):.2f}U" + except (TypeError, ValueError): + return "—" + parts: list[str] = [] + if usdt is not None: + try: + parts.append(f"{float(usdt):.2f} USDT") + except (TypeError, ValueError): + pass + eth_txt = _fmt_coin_amount(eth) + if eth_txt is not None: + parts.append(f"{eth_txt} ETH") + btc_txt = _fmt_coin_amount(btc) + if btc_txt is not None: + parts.append(f"{btc_txt} BTC") + return " / ".join(parts) if parts else "—" def total_funds_usdt( diff --git a/lib/instance/templates/embed_boot_scripts.html b/lib/instance/templates/embed_boot_scripts.html index a289fc5..db2edf3 100644 --- a/lib/instance/templates/embed_boot_scripts.html +++ b/lib/instance/templates/embed_boot_scripts.html @@ -1137,27 +1137,35 @@ function paintRealtimePnlFromSnapshot(data){ } function formatOptionsFundingLabel(usdc, usdt, eth, marginMode, underly) { - const mode = String(marginMode || "usdc").toLowerCase(); - if (mode === "coin") { - const parts = []; - if (usdt !== null && usdt !== undefined && usdt !== "") { - const n = Number(usdt); - if (!Number.isNaN(n)) parts.push(`${n.toFixed(2)} USDT`); - } - if (eth !== null && eth !== undefined && eth !== "") { - const n = Number(eth); - if (!Number.isNaN(n)) { - const txt = String(n.toFixed(6)).replace(/\.?0+$/, ""); - parts.push(`${txt || "0"} ${String(underly || "ETH").toUpperCase()}`); - } - } - return parts.length ? parts.join(" / ") : "—"; - } if (usdc === null || usdc === undefined || usdc === "") return "—"; const n = Number(usdc); if (Number.isNaN(n)) return "—"; return `${n.toFixed(2)} USDC`; } +function formatTradingAccountLabel(usdt, eth, btc, marginMode) { + const mode = String(marginMode || "usdc").toLowerCase(); + if (mode !== "coin") { + if (usdt === null || usdt === undefined || usdt === "") return "—"; + const n = Number(usdt); + if (Number.isNaN(n)) return "—"; + return `${n.toFixed(2)}U`; + } + const parts = []; + if (usdt !== null && usdt !== undefined && usdt !== "") { + const n = Number(usdt); + if (!Number.isNaN(n)) parts.push(`${n.toFixed(2)} USDT`); + } + const pushCoin = (v, ccy) => { + if (v === null || v === undefined || v === "") return; + const n = Number(v); + if (Number.isNaN(n) || Math.abs(n) < 1e-12) return; + const txt = String(n.toFixed(6)).replace(/\.?0+$/, ""); + parts.push(`${txt || "0"} ${ccy}`); + }; + pushCoin(eth, "ETH"); + pushCoin(btc, "BTC"); + return parts.length ? parts.join(" / ") : "—"; +} function setFundsFieldText(field, text){ if(text == null || text === "") return; @@ -1171,6 +1179,11 @@ function applyPerpFundsVisibility(show){ el.style.display = on ? "" : "none"; }); } +function applyOptionsFundsVisibility(show){ + document.querySelectorAll("[data-options-funds='1']").forEach((el) => { + el.style.display = show ? "" : "none"; + }); +} function accountSnapshotFundingMissing(data){ if(!data || typeof data !== "object") return true; if(data.show_perp_funds === false){ @@ -1190,9 +1203,13 @@ function accountSnapshotFundingMissing(data){ let accountSnapshotRetryCount = 0; function applyAccountSnapshot(data){ if(!data || typeof data !== "object") return; + const coinMode = String(data.options_margin_mode || "usdc").toLowerCase() === "coin"; if(typeof data.show_perp_funds !== "undefined"){ - applyPerpFundsVisibility(data.show_perp_funds); + applyPerpFundsVisibility(data.show_perp_funds !== false || coinMode); + } else if (coinMode) { + applyPerpFundsVisibility(true); } + applyOptionsFundsVisibility(!coinMode); if(data.funding_usdt != null && data.funding_usdt !== ""){ setFundsFieldText("total-capital", `${Number(data.funding_usdt).toFixed(2)}U`); } @@ -1200,9 +1217,17 @@ function applyAccountSnapshot(data){ 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`); + setFundsFieldText( + "current-capital", + formatTradingAccountLabel( + data.current_capital, + data.options_trading_eth, + data.options_trading_btc, + data.options_margin_mode + ) + ); } - if(data.options_funding_usdc != null || data.options_funding_usdt != null || data.options_funding_eth != null){ + if(!coinMode && (data.options_funding_usdc != null || data.options_funding_usdt != null || data.options_funding_eth != null)){ const optFunding = formatOptionsFundingLabel( data.options_funding_usdc, data.options_funding_usdt, @@ -1212,7 +1237,7 @@ function applyAccountSnapshot(data){ ); setFundsFieldText("options-funding-usdc", optFunding); } - if(data.options_trading_usdc != null || data.options_trading_usdt != null || data.options_trading_eth != null){ + if(!coinMode && (data.options_trading_usdc != null || data.options_trading_usdt != null || data.options_trading_eth != null)){ const optTrading = formatOptionsFundingLabel( data.options_trading_usdc, data.options_trading_usdt, diff --git a/lib/instance/templates/index.html b/lib/instance/templates/index.html index 74564c1..b6466ad 100644 --- a/lib/instance/templates/index.html +++ b/lib/instance/templates/index.html @@ -1618,27 +1618,35 @@ function paintRealtimePnlFromSnapshot(data){ } function formatOptionsFundingLabel(usdc, usdt, eth, marginMode, underly) { - const mode = String(marginMode || "usdc").toLowerCase(); - if (mode === "coin") { - const parts = []; - if (usdt != null && usdt !== "") { - const n = Number(usdt); - if (!Number.isNaN(n)) parts.push(`${n.toFixed(2)} USDT`); - } - if (eth != null && eth !== "") { - const n = Number(eth); - if (!Number.isNaN(n)) { - const txt = String(n.toFixed(6)).replace(/\.?0+$/, ""); - parts.push(`${txt || "0"} ${String(underly || "ETH").toUpperCase()}`); - } - } - return parts.length ? parts.join(" / ") : "—"; - } if(usdc == null || usdc === "") return "—"; const n = Number(usdc); if(Number.isNaN(n)) return "—"; return `${n.toFixed(2)} USDC`; } +function formatTradingAccountLabel(usdt, eth, btc, marginMode) { + const mode = String(marginMode || "usdc").toLowerCase(); + if (mode !== "coin") { + if (usdt == null || usdt === "") return "—"; + const n = Number(usdt); + if (Number.isNaN(n)) return "—"; + return `${n.toFixed(2)}U`; + } + const parts = []; + if (usdt != null && usdt !== "") { + const n = Number(usdt); + if (!Number.isNaN(n)) parts.push(`${n.toFixed(2)} USDT`); + } + const pushCoin = (v, ccy) => { + if (v == null || v === "") return; + const n = Number(v); + if (Number.isNaN(n) || Math.abs(n) < 1e-12) return; + const txt = String(n.toFixed(6)).replace(/\.?0+$/, ""); + parts.push(`${txt || "0"} ${ccy}`); + }; + pushCoin(eth, "ETH"); + pushCoin(btc, "BTC"); + return parts.length ? parts.join(" / ") : "—"; +} function setFundsFieldText(field, text){ if(text == null || text === "") return; @@ -1652,6 +1660,11 @@ function applyPerpFundsVisibility(show){ el.style.display = on ? "" : "none"; }); } +function applyOptionsFundsVisibility(show){ + document.querySelectorAll("[data-options-funds='1']").forEach((el) => { + el.style.display = show ? "" : "none"; + }); +} function accountSnapshotFundingMissing(data){ if(!data || typeof data !== "object") return true; if(data.show_perp_funds === false){ @@ -1671,9 +1684,13 @@ function accountSnapshotFundingMissing(data){ let accountSnapshotRetryCount = 0; function applyAccountSnapshot(data){ if(!data || typeof data !== "object") return; + const coinMode = String(data.options_margin_mode || "usdc").toLowerCase() === "coin"; if(typeof data.show_perp_funds !== "undefined"){ - applyPerpFundsVisibility(data.show_perp_funds); + applyPerpFundsVisibility(data.show_perp_funds !== false || coinMode); + } else if (coinMode) { + applyPerpFundsVisibility(true); } + applyOptionsFundsVisibility(!coinMode); if(data.funding_usdt != null && data.funding_usdt !== ""){ setFundsFieldText("total-capital", `${Number(data.funding_usdt).toFixed(2)}U`); } @@ -1681,9 +1698,17 @@ function applyAccountSnapshot(data){ 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`); + setFundsFieldText( + "current-capital", + formatTradingAccountLabel( + data.current_capital, + data.options_trading_eth, + data.options_trading_btc, + data.options_margin_mode + ) + ); } - if(data.options_funding_usdc != null || data.options_funding_usdt != null || data.options_funding_eth != null){ + if(!coinMode && (data.options_funding_usdc != null || data.options_funding_usdt != null || data.options_funding_eth != null)){ const optFunding = formatOptionsFundingLabel( data.options_funding_usdc, data.options_funding_usdt, @@ -1693,7 +1718,7 @@ function applyAccountSnapshot(data){ ); setFundsFieldText("options-funding-usdc", optFunding); } - if(data.options_trading_usdc != null || data.options_trading_usdt != null || data.options_trading_eth != null){ + if(!coinMode && (data.options_trading_usdc != null || data.options_trading_usdt != null || data.options_trading_eth != null)){ const optTrading = formatOptionsFundingLabel( data.options_trading_usdc, data.options_trading_usdt, diff --git a/lib/instance/templates/instance_header_panel.html b/lib/instance/templates/instance_header_panel.html index f2cb7a4..aacd106 100644 --- a/lib/instance/templates/instance_header_panel.html +++ b/lib/instance/templates/instance_header_panel.html @@ -38,11 +38,13 @@ {% include 'instance_header_stats.html' %}