diff --git a/manual_trading_hub/agent.py b/manual_trading_hub/agent.py
index 8b35169..353ab6e 100644
--- a/manual_trading_hub/agent.py
+++ b/manual_trading_hub/agent.py
@@ -408,6 +408,24 @@ def _position_entry_price(p: dict[str, Any]) -> float | None:
return None
+def _position_mark_price(p: dict[str, Any]) -> float | None:
+ """四所 ccxt 持仓统一解析标记价(用于强平/浮盈计算)。"""
+ info = p.get("info") or {}
+ if not isinstance(info, dict):
+ info = {}
+ for key in (
+ p.get("markPrice"),
+ p.get("mark_price"),
+ info.get("markPx"),
+ info.get("mark_price"),
+ info.get("markPrice"),
+ ):
+ px = _finite_or_none(key)
+ if px is not None and px > 0:
+ return px
+ return None
+
+
def _extract_usdt_total(balance: dict[str, Any]) -> float | None:
"""从 ccxt balance 结构中尽量取出 USDT 总额(与 crypto_monitor_binance 一致)。"""
usdt_info = balance.get("USDT") or {}
@@ -583,6 +601,10 @@ def _status_inner(x_control_token: str | None) -> Any:
notional_f = None
entry_f = _position_entry_price(p)
_, entry_fmt, price_tick = _position_price_fmt(ex, sym, entry_f)
+ mark_f = _position_mark_price(p)
+ _, mark_fmt, mark_tick = _position_price_fmt(ex, sym, mark_f)
+ if price_tick is None and mark_tick is not None:
+ price_tick = mark_tick
positions_out.append(
{
"symbol": sym,
@@ -593,6 +615,8 @@ def _status_inner(x_control_token: str | None) -> Any:
"unrealized_pnl": _finite_or_none(upnl_f),
"entry_price": entry_f,
"entry_price_fmt": entry_fmt,
+ "mark_price": mark_f,
+ "mark_price_fmt": mark_fmt,
"price_tick": _finite_or_none(price_tick) if price_tick is not None else None,
}
)
diff --git a/manual_trading_hub/static/app.js b/manual_trading_hub/static/app.js
index e7f425a..d6e210f 100644
--- a/manual_trading_hub/static/app.js
+++ b/manual_trading_hub/static/app.js
@@ -261,6 +261,18 @@
return fmtSymbolPrice(positionEntryPrice(pos), pos && pos.symbol, tickMap);
}
+ function positionMarkPrice(pos) {
+ if (!pos) return null;
+ const n = Number(pos.mark_price);
+ if (!Number.isFinite(n) || n <= 0) return null;
+ return n;
+ }
+
+ function fmtMarkPrice(pos, tickMap) {
+ if (pos && pos.mark_price_fmt) return String(pos.mark_price_fmt);
+ return fmtSymbolPrice(positionMarkPrice(pos), pos && pos.symbol, tickMap);
+ }
+
function pnlCls(v) {
const n = Number(v);
if (!Number.isFinite(n) || n === 0) return "";
@@ -1301,6 +1313,7 @@
${meta.map((m) => `${m}`).join("")}
开仓价${fmtEntryPrice(pos, tickMap)}
+
标记价${fmtMarkPrice(pos, tickMap)}
止损${sl != null && sl !== "" ? fmtSymbolPrice(sl, symbol, tickMap) : "—"}
止盈${tpMonitored ? "程序监控" : tp != null && tp !== "" ? fmtSymbolPrice(tp, symbol, tickMap) : "—"}
盈亏比${tpMonitored ? "—" : rr != null ? fmt(rr, 2) + ":1" : "-:1"}
@@ -1396,11 +1409,12 @@
const symBeBadge = beSecured ? ` ${breakevenBadgeHtml()}` : "";
return `