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)}
+ |
))}