Fix hub options float summary blank when bid book is invalid.

Stop treating total_received=0 as a real bid recycle, fall back to exchange upl for display totals, and keep row/summary aligned.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-07 09:47:14 +08:00
parent d41028b766
commit 4bc238b014
12 changed files with 182 additions and 48 deletions
+43 -8
View File
@@ -3821,6 +3821,30 @@
return vals.reduce((s, v) => s + v, 0);
}
function optionsRowDisplayPnl(p) {
if (!p || typeof p !== "object") return null;
const preview = p.close_preview || {};
// bid 无效时 total_received 常为 0,不能用 0−权利金冒充净亏
if (preview.bid_invalid) {
const upl = p.upl != null ? Number(p.upl) : NaN;
return Number.isFinite(upl) ? upl : null;
}
let net = preview.estimated_pnl;
const covered = Number(preview.covered_sheets);
if (
net == null &&
preview.total_received != null &&
Number.isFinite(covered) &&
covered > 0 &&
p.premium_paid != null
) {
net = Number(preview.total_received) - Number(p.premium_paid);
}
if (net != null && Number.isFinite(Number(net))) return Number(net);
const upl = p.upl != null ? Number(p.upl) : NaN;
return Number.isFinite(upl) ? upl : null;
}
function optionsBalanceFields(opt) {
if (!opt || typeof opt !== "object") {
return { funding: null, trading: null, upl: null };
@@ -3828,6 +3852,23 @@
const bal =
opt.balances && typeof opt.balances === "object" ? opt.balances : {};
const pick = (a, b) => (a != null && a !== "" ? a : b);
let upl =
opt.upl_total_usdc != null && Number.isFinite(Number(opt.upl_total_usdc))
? Number(opt.upl_total_usdc)
: null;
if (upl == null) {
const pos = Array.isArray(opt.positions) ? opt.positions : [];
let sum = 0;
let found = false;
pos.forEach((p) => {
const n = optionsRowDisplayPnl(p);
if (n != null) {
sum += n;
found = true;
}
});
if (found) upl = sum;
}
return {
funding: sumUsdtEquiv(
pick(bal.funding_usdt, opt.funding_usdt),
@@ -3837,10 +3878,7 @@
pick(bal.trading_usdt, opt.trading_usdt),
pick(bal.trading_usdc, opt.trading_usdc)
),
upl:
opt.upl_total_usdc != null && Number.isFinite(Number(opt.upl_total_usdc))
? Number(opt.upl_total_usdc)
: null,
upl,
};
}
@@ -3915,10 +3953,7 @@
? "Put"
: p.opt_type || "—";
const preview = p.close_preview || {};
let net = preview.estimated_pnl;
if (net == null && preview.total_received != null && p.premium_paid != null) {
net = Number(preview.total_received) - Number(p.premium_paid);
}
let net = optionsRowDisplayPnl(p);
let roi = preview.estimated_pnl_ratio_pct;
if (roi == null && net != null && Number(p.premium_paid) > 0) {
roi = (Number(net) / Number(p.premium_paid)) * 100;
+13 -2
View File
@@ -249,14 +249,25 @@
if (!p || typeof p !== "object") return null;
if (p.net_pnl != null && Number.isFinite(Number(p.net_pnl))) return Number(p.net_pnl);
const preview = p.close_preview || {};
if (preview.bid_invalid) {
const upl = p.upl != null ? Number(p.upl) : NaN;
return Number.isFinite(upl) ? upl : null;
}
if (preview.estimated_pnl != null && Number.isFinite(Number(preview.estimated_pnl))) {
return Number(preview.estimated_pnl);
}
if (preview.total_received != null && p.premium_paid != null) {
const covered = Number(preview.covered_sheets);
if (
preview.total_received != null &&
Number.isFinite(covered) &&
covered > 0 &&
p.premium_paid != null
) {
const n = Number(preview.total_received) - Number(p.premium_paid);
return Number.isFinite(n) ? n : null;
}
return null;
const upl = p.upl != null ? Number(p.upl) : NaN;
return Number.isFinite(upl) ? upl : null;
}
function optionsHedgePlanId(p) {
+3 -3
View File
@@ -1757,7 +1757,7 @@
<script src="/assets/archive.js?v=20260724-opt-archive"></script>
<script src="/assets/quotes.js?v=20260717-quotes-feed"></script>
<script src="/assets/funds.js?v=20260717-funds-scroll-fix"></script>
<script src="/assets/dashboard.js?v=20260723-hide-pnl"></script>
<script src="/assets/dashboard.js?v=20260807-opt-float"></script>
<script src="/assets/strategy.js?v=11"></script>
<script src="/assets/amp_stats.js?v=20260728-hedge"></script>
<script src="/assets/help.js?v=1"></script>
@@ -1765,8 +1765,8 @@
<script src="/assets/ai_review_render.js?v=3"></script>
<script src="/assets/time_close_ui.js?v=3"></script>
<script src="/assets/options_expiry_countdown.js?v=1"></script>
<script src="/assets/options_position_cards.js?v=3"></script>
<script src="/assets/options_position_cards.js?v=4"></script>
<script src="/assets/backup.js?v=1"></script>
<script src="/assets/app.js?v=20260805-intraday-close"></script>
<script src="/assets/app.js?v=20260807-opt-float"></script>
</body>
</html>