From 0c12d7621206d414c3fb1dcbd32ecf439029a4a6 Mon Sep 17 00:00:00 2001 From: dekun Date: Sun, 2 Aug 2026 12:32:25 +0800 Subject: [PATCH] Show margin and premium in control positions; align exchange price digits. Co-authored-by: Cursor --- backend/app/api/fleet.py | 5 ++ control/frontend/src/pages/Monitor.tsx | 74 +++++++++++++++++++++++--- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/backend/app/api/fleet.py b/backend/app/api/fleet.py index dddd2ca..b31e308 100644 --- a/backend/app/api/fleet.py +++ b/backend/app/api/fleet.py @@ -185,6 +185,8 @@ async def fleet_status(_tok: Annotated[str, Depends(require_fleet_token)]) -> di "avg_px": pos.get("perp_entry_px"), "mark_px": pos.get("perp_mark_px"), "upl": pos.get("perp_upl"), + "margin": pos.get("perp_margin"), + "premium": None, } ) if pos.get("option_side") or pos.get("option_inst_id"): @@ -197,6 +199,8 @@ async def fleet_status(_tok: Annotated[str, Depends(require_fleet_token)]) -> di "avg_px": pos.get("option_entry_px"), "mark_px": pos.get("option_mark_px"), "upl": pos.get("option_upl"), + "margin": None, + "premium": pos.get("initial_premium"), } ) @@ -262,6 +266,7 @@ async def fleet_status(_tok: Annotated[str, Depends(require_fleet_token)]) -> di "group_id": pos.get("group_id"), "open_at_ms": pos.get("open_at_ms"), "initial_premium": pos.get("initial_premium"), + "perp_margin": pos.get("perp_margin"), "exit_target_usdt": pos.get("exit_target_usdt"), "net_pnl": pos.get("net_pnl"), "perp_upl": pos.get("perp_upl"), diff --git a/control/frontend/src/pages/Monitor.tsx b/control/frontend/src/pages/Monitor.tsx index 37bf5b8..41dd64b 100644 --- a/control/frontend/src/pages/Monitor.tsx +++ b/control/frontend/src/pages/Monitor.tsx @@ -31,6 +31,17 @@ function fmt(v: unknown, digits = 4): string { return n.toFixed(digits); } +/** 价格按交易所常见精度:永续/指数 0.01;期权权利金 0.1 */ +function fmtExPx(kind: unknown, px: unknown): string { + if (px == null || px === "") return "—"; + const n = Number(px); + if (!Number.isFinite(n)) return String(px); + if (String(kind || "").toLowerCase() === "option") { + return (Math.round(n * 10) / 10).toFixed(1); + } + return (Math.round(n * 100) / 100).toFixed(2); +} + function pnlClass(v: unknown): string { const n = Number(v); if (!Number.isFinite(n) || n === 0) return "pnl-flat"; @@ -917,10 +928,14 @@ export default function MonitorPage() { {fmt(detail.strat.option_qty_eth, 4)} ETH {fmt(detail.strat.exit_target_usdt, 2)} USDT - {fmt(detail.index_px, 2)} + {fmtExPx("perp", detail.index_px)} {detail.pair - ? `${detail.pair.expiry_ymd || "?"} @ ${detail.pair.strike ?? "?"}` + ? `${detail.pair.expiry_ymd || "?"} @ ${ + detail.pair.strike != null + ? Math.round(Number(detail.pair.strike)) + : "?" + }` : "—"} @@ -1077,8 +1092,28 @@ export default function MonitorPage() { ) : null} + {detail.position.perp_margin != null ? ( + <> + {" · 保证金 "} + + {fmt(detail.position.perp_margin, 2)} U + + + ) : null} + {detail.position.initial_premium != null ? ( + <> + {" · 权利金 "} + + {fmt(detail.position.initial_premium, 2)} U + + + ) : null} {detail.position.expiry_ymd - ? ` · 到期 ${String(detail.position.expiry_ymd)} @ ${fmt(detail.position.strike, 0)}` + ? ` · 到期 ${String(detail.position.expiry_ymd)} @ ${ + detail.position.strike != null + ? Math.round(Number(detail.position.strike)) + : "—" + }` : ""}

{detailLegs.length ? ( @@ -1092,6 +1127,8 @@ export default function MonitorPage() { 数量 均价 标记 + 保证金 + 权利金 浮盈 @@ -1101,10 +1138,33 @@ export default function MonitorPage() { {String(lg.kind || "—")} {String(lg.side || "—")} {String(lg.inst_id || "—")} - {fmt(lg.qty, 4)} - {fmt(lg.avg_px, 4)} - {fmt(lg.mark_px, 4)} - {fmt(lg.upl, 2)} + {fmt(lg.qty, 2)} + + {fmtExPx(lg.kind, lg.avg_px)} + + + {fmtExPx(lg.kind, lg.mark_px)} + + + {lg.kind === "perp" + ? fmt( + lg.margin ?? detail.position.perp_margin, + 2, + ) + : "—"} + + + {lg.kind === "option" + ? fmt( + lg.premium ?? + detail.position.initial_premium, + 2, + ) + : "—"} + + + {fmt(lg.upl, 2)} + ))}