Align options realtime PnL with bid-net and show totals in stats.

Header float PnL now uses bid recycle minus premium like position cards. Stats adds realized/open/total net PnL.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-15 22:00:45 +08:00
parent 60f3437c73
commit ee7be3e7f3
14 changed files with 198 additions and 19 deletions
+22
View File
@@ -1476,6 +1476,19 @@
}
}
function paintPnlStat(el, value) {
if (!el) return;
if (value == null || value === "" || Number.isNaN(Number(value))) {
el.textContent = "—";
el.classList.remove("pos-pnl-profit", "pos-pnl-loss");
return;
}
const n = Number(value);
el.textContent = (n > 0 ? "+" : "") + fmt(n, 2) + " USDC";
el.classList.toggle("pos-pnl-profit", n > 0);
el.classList.toggle("pos-pnl-loss", n < 0);
}
async function refreshStats() {
const d = await apiJson("/api/options/stats");
const winEl = document.getElementById("opt-stats-winrate");
@@ -1487,14 +1500,23 @@
const winHoldEl = document.getElementById("opt-stats-win-hold");
const lossHoldEl = document.getElementById("opt-stats-loss-hold");
const openHoldEl = document.getElementById("opt-stats-open-hold");
const totalPnlEl = document.getElementById("opt-stats-total-pnl");
const netRealizedEl = document.getElementById("opt-stats-net-realized");
const openFloatEl = document.getElementById("opt-stats-open-float");
const statEls = [winEl, plrEl, closedEl, profitEl, lossEl, avgHoldEl, winHoldEl, lossHoldEl, openHoldEl];
if (!d.ok) {
statEls.forEach(function (el) {
if (el) el.textContent = "—";
});
paintPnlStat(totalPnlEl, null);
paintPnlStat(netRealizedEl, null);
paintPnlStat(openFloatEl, null);
paintStatsCharts(null);
return;
}
paintPnlStat(totalPnlEl, d.total_pnl);
paintPnlStat(netRealizedEl, d.net_realized_pnl);
paintPnlStat(openFloatEl, d.open_float_pnl);
if (winEl) winEl.textContent = d.total_closed ? d.win_rate + "%" : "0%";
if (plrEl) {
plrEl.textContent = d.profit_loss_ratio != null ? String(d.profit_loss_ratio) : "—";