币本位盈亏双显ETH/U(按指数换算);平仓卖币改为卖光交易户可用余额

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-20 17:45:32 +08:00
parent d4d2110412
commit f5c553844f
9 changed files with 235 additions and 48 deletions
+33 -6
View File
@@ -782,13 +782,37 @@
return fmt(n, 2);
}
function fmtOptPnlText(v, ccy) {
function spotPxFromOptMeta(optMeta, p) {
if (p) {
const n = Number(p.idx_px != null ? p.idx_px : p.idxPx != null ? p.idxPx : p.index_px);
if (Number.isFinite(n) && n > 0) return n;
}
if (optMeta) {
const n = Number(optMeta.options_index_px != null ? optMeta.options_index_px : optMeta.index_px);
if (Number.isFinite(n) && n > 0) return n;
const pos = Array.isArray(optMeta.positions) ? optMeta.positions : [];
for (let i = 0; i < pos.length; i++) {
const px = Number(pos[i] && (pos[i].idx_px != null ? pos[i].idx_px : pos[i].idxPx));
if (Number.isFinite(px) && px > 0) return px;
}
}
return null;
}
function fmtOptPnlText(v, ccy, spotPx) {
if (v === null || v === undefined || Number.isNaN(Number(v))) return "—";
const n = Number(v);
const unit = String(ccy || "USDC").toUpperCase();
const sign = n > 0 ? "+" : "";
if (unit === "ETH" || unit === "BTC") {
return `${sign}${fmtOptPnlAmt(n, unit)} ${unit}`;
const coin = `${sign}${fmtOptPnlAmt(Math.abs(n), unit)}`;
const signedCoin = n < 0 ? `-${fmtOptPnlAmt(Math.abs(n), unit)}` : coin;
const px = Number(spotPx);
if (!Number.isFinite(px) || !(px > 0)) return `${signedCoin} ${unit}`;
const u = n * px;
const uAbs = Math.abs(u).toFixed(2);
const uTxt = u < 0 ? `-${uAbs}` : u > 0 ? `+${uAbs}` : uAbs;
return `${signedCoin} ${unit} / ${uTxt}U`;
}
return `${sign}${fmt(n, 2)}U`;
}
@@ -3948,9 +3972,10 @@
: "—";
const tradeTxt = formatCoinTradingLabel(usdt, eth, btc);
const pnlCcy = optionsPanelCcy(optMeta);
const spotPx = spotPxFromOptMeta(optMeta);
const pnlTxt = upnl == null || Number.isNaN(Number(upnl))
? "—"
: `<span class="${pnlCls(upnl)}">${fmtOptPnlText(upnl, pnlCcy)}</span>`;
: `<span class="${pnlCls(upnl)}">${fmtOptPnlText(upnl, pnlCcy, spotPx)}</span>`;
return `<div class="${rowCls}">
<div class="stat-box"><div class="stat-label">资金账户</div><div class="stat-value">${fundTxt}</div></div>
<div class="stat-box"><div class="stat-label">交易账户</div><div class="stat-value">${tradeTxt}</div></div>
@@ -4116,7 +4141,7 @@
${renderOptionsTargetCell(target, p)}`;
if (showPnl) {
const premCcy = optPremiumCcyOf(p);
html += `<td class="${pnlCls(net)}">${net == null ? "—" : fmtOptPnlText(net, premCcy)}</td>
html += `<td class="${pnlCls(net)}">${net == null ? "—" : fmtOptPnlText(net, premCcy, spotPxFromOptMeta(null, p))}</td>
<td class="${pnlCls(net)}">${roi == null ? "—" : esc(Number(roi).toFixed(2)) + "%"}</td>`;
}
html += "</tr>";
@@ -4602,6 +4627,7 @@
let pnlShow = upnl;
let pnlSuffix = "";
let pnlUnit = "U";
let pnlSpotPx = null;
if (hasOptCap) {
if (opt.enabled === false) {
optLine = "期权未启用";
@@ -4629,13 +4655,14 @@
parts.push(`交易 ${fmt(bal.trading, 2)}U`);
}
if (optUpl != null && Number.isFinite(Number(optUpl))) {
parts.push(`浮盈 ${fmtOptPnlText(optUpl, optCcy)}`);
parts.push(`浮盈 ${fmtOptPnlText(optUpl, optCcy, spotPxFromOptMeta(opt))}`);
}
if (optUpl != null && Number.isFinite(Number(optUpl)) && openCount === 0) {
// 永续空仓时主数字优先展示期权浮盈,避免一直显示 0U
pnlShow = optUpl;
pnlSuffix = "期权";
pnlUnit = optCcy;
pnlSpotPx = spotPxFromOptMeta(opt);
}
}
optLine = parts.join(" · ");
@@ -4646,7 +4673,7 @@
const strategyStats = renderCardStrategyStats(row, hm, flaskOk);
const tilePnlHtml =
pnlUnit === "ETH" || pnlUnit === "BTC"
? `${fmtOptPnlAmt(pnlShow, pnlUnit)} <small>${esc(pnlUnit)}${pnlSuffix ? " · " + esc(pnlSuffix) : ""}</small>`
? `${fmtOptPnlText(pnlShow, pnlUnit, pnlSpotPx)} <small>${pnlSuffix ? esc(pnlSuffix) : ""}</small>`
: `${fmt(pnlShow, 2)} <small>U${pnlSuffix ? " · " + esc(pnlSuffix) : ""}</small>`;
return `<div class="card hub-tile ${tileCls}" data-ex-id="${esc(row.id)}">
<div class="hub-tile-body card-expand-zone" title="点击进入全屏详情">
+17 -3
View File
@@ -51,14 +51,20 @@
return "USDC";
}
function pnlSignedOpt(v, ccy) {
function pnlSignedOpt(v, ccy, spotPx) {
const n = Number(v);
if (!Number.isFinite(n)) return "—";
const unit = String(ccy || "USDC").toUpperCase();
if (unit === "ETH" || unit === "BTC") {
const abs = Math.abs(n).toFixed(8).replace(/\.?0+$/, "") || "0";
const sign = n > 0 ? "+" : n < 0 ? "-" : "";
return `${sign}${abs} ${unit}`;
const coinTxt = `${sign}${abs} ${unit}`;
const px = Number(spotPx);
if (!Number.isFinite(px) || !(px > 0)) return coinTxt;
const u = n * px;
const uAbs = Math.abs(u).toFixed(2);
const uSign = u < 0 ? "-" : u > 0 ? "+" : "";
return `${coinTxt} / ${uSign}${uAbs}U`;
}
return pnlSigned(n, 2);
}
@@ -361,7 +367,15 @@
<td>${p.idx_px != null ? fmt(p.idx_px, 0) : "—"}</td>
<td><span class="${targetCls}">${esc(target)}</span></td>`;
if (showPnl) {
html += `<td class="${pnlClass(net)}">${net != null ? pnlSignedOpt(net, optPremiumCcyOf(p)) : "—"}</td>
html += `<td class="${pnlClass(net)}">${
net != null
? pnlSignedOpt(
net,
optPremiumCcyOf(p),
Number(p.idx_px != null ? p.idx_px : p.idxPx) || null
)
: "—"
}</td>
<td class="${pnlClass(roi)}">${roi != null ? esc(Number(roi).toFixed(2)) + "%" : "—"}</td>`;
}
html += "</tr>";