Align dashboard PnL columns with monitor; add back-to-dashboard button.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1059,6 +1059,30 @@ def resolve_position_monitor_source(pos: dict, hub_mon: Optional[dict]) -> str:
|
||||
return candidates[0][1]
|
||||
|
||||
|
||||
def resolve_position_reward_at_tp(pos: dict, hub_mon: Optional[dict]) -> Optional[float]:
|
||||
"""与监控区「盈利金额」一致:优先匹配下单监控 reward_at_tp_usdt,否则仓位自身字段."""
|
||||
sym = str(pos.get("symbol") or "")
|
||||
side = str(pos.get("side") or "")
|
||||
if isinstance(hub_mon, dict) and hub_mon.get("ok") is not False and sym:
|
||||
# 与前端 findMonitorOrder 一致:先扫 orders
|
||||
for o in hub_mon.get("orders") or []:
|
||||
if isinstance(o, dict) and _monitor_item_matches_position(o, sym, side):
|
||||
v = _safe_float(o.get("reward_at_tp_usdt"))
|
||||
if v is not None:
|
||||
return v
|
||||
for r in hub_mon.get("rolls") or []:
|
||||
if isinstance(r, dict) and _monitor_item_matches_position(r, sym, side):
|
||||
v = _safe_float(r.get("reward_at_tp_usdt"))
|
||||
if v is not None:
|
||||
return v
|
||||
for t in hub_mon.get("trends") or []:
|
||||
if isinstance(t, dict) and _monitor_item_matches_position(t, sym, side):
|
||||
v = _safe_float(t.get("reward_at_tp_usdt"))
|
||||
if v is not None:
|
||||
return v
|
||||
return _safe_float(pos.get("reward_at_tp_usdt"))
|
||||
|
||||
|
||||
def _options_source_label(p: dict) -> str:
|
||||
"""看板期权来源:期期/永期对冲,其余为纯期权."""
|
||||
source = str(p.get("source") or "").strip()
|
||||
@@ -1105,6 +1129,7 @@ def format_dashboard_account_detail(ac: dict) -> dict[str, Any]:
|
||||
notional = _safe_float(p.get("notional_usdt"))
|
||||
if notional is None:
|
||||
notional = _safe_float(p.get("notional"))
|
||||
reward_tp = resolve_position_reward_at_tp(p, hub_mon)
|
||||
position_lines.append(
|
||||
{
|
||||
"kind": "position",
|
||||
@@ -1117,6 +1142,7 @@ def format_dashboard_account_detail(ac: dict) -> dict[str, Any]:
|
||||
"mark_price": mark,
|
||||
"mark_price_fmt": p.get("mark_price_fmt"),
|
||||
"notional_usdt": notional,
|
||||
"reward_at_tp_usdt": round(reward_tp, 4) if reward_tp is not None else None,
|
||||
"text": f"{sym} {side}",
|
||||
"pnl": round(upnl, 4),
|
||||
}
|
||||
|
||||
@@ -2528,6 +2528,17 @@
|
||||
renderMonitorGrid(lastMonitorRows);
|
||||
};
|
||||
});
|
||||
fsInner.querySelectorAll(".btn-expand-dashboard").forEach((btn) => {
|
||||
btn.onclick = (ev) => {
|
||||
ev.stopPropagation();
|
||||
closeExchangeFullscreen();
|
||||
if (window.hubNavigateTo) window.hubNavigateTo("/dashboard");
|
||||
else {
|
||||
history.pushState({}, "", "/dashboard");
|
||||
setActiveNav();
|
||||
}
|
||||
};
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("renderFullscreenExchange", err);
|
||||
closeExchangeFullscreen();
|
||||
@@ -4000,6 +4011,7 @@
|
||||
</div>
|
||||
<div class="fs-head-actions">
|
||||
<button type="button" class="ghost btn-expand-back">返回监控</button>
|
||||
<button type="button" class="ghost btn-expand-dashboard">返回数据看板</button>
|
||||
${flaskOpen ? `<a class="btn-link btn-open-instance btn-open-trade" href="#" data-ex-id="${esc(row.id)}" data-next="/trade" data-new-tab="1">打开实例</a>` : ""}
|
||||
${flaskOpen ? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/trade">下单</a>` : ""}
|
||||
${flaskOpen ? `<a class="btn-link btn-open-instance" href="#" data-ex-id="${esc(row.id)}" data-next="/key_monitor">监控位</a>` : ""}
|
||||
|
||||
@@ -273,6 +273,11 @@ body.hub-page-dashboard .page#page-dashboard {
|
||||
color: color-mix(in srgb, var(--dash-accent) 80%, #fff);
|
||||
}
|
||||
|
||||
.dash-tp-profit {
|
||||
color: var(--dash-accent);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.dash-empty-inline {
|
||||
padding: 8px 0 4px;
|
||||
font-size: 0.78rem;
|
||||
|
||||
@@ -130,14 +130,16 @@
|
||||
return "—";
|
||||
}
|
||||
|
||||
function floatPctText(pnl, notional) {
|
||||
const n = Number(pnl);
|
||||
const notion = Number(notional);
|
||||
if (!Number.isFinite(n) || !Number.isFinite(notion) || Math.abs(notion) < 1e-8) return "—";
|
||||
const pct = (n / Math.abs(notion)) * 100;
|
||||
const abs = Math.abs(pct).toFixed(2);
|
||||
if (Math.abs(pct) < 1e-9) return "0.00%";
|
||||
return `${pct > 0 ? "+" : "-"}${abs}%`;
|
||||
function tpProfitCell(ln) {
|
||||
const n = ln && ln.reward_at_tp_usdt != null ? Number(ln.reward_at_tp_usdt) : NaN;
|
||||
if (!Number.isFinite(n)) return "—";
|
||||
return `<span class="dash-tp-profit">${fmt(n, 2)}U</span>`;
|
||||
}
|
||||
|
||||
function floatPnlCell(ln) {
|
||||
const pnl = ln && ln.pnl != null ? Number(ln.pnl) : NaN;
|
||||
if (!Number.isFinite(pnl)) return "—";
|
||||
return `<span class="${pnlClass(pnl)}">${fmt(pnl, 2)}</span>`;
|
||||
}
|
||||
|
||||
function collectUnifiedPositions(accounts) {
|
||||
@@ -184,8 +186,6 @@
|
||||
const side = esc((ln && ln.side) || "—");
|
||||
const contracts =
|
||||
ln && ln.contracts != null && ln.contracts !== "" ? esc(String(ln.contracts)) : "—";
|
||||
const pnl = ln && ln.pnl != null ? Number(ln.pnl) : NaN;
|
||||
const pct = floatPctText(pnl, ln && ln.notional_usdt);
|
||||
return `<tr>
|
||||
<td>${exchangeLinkCell(ac)}</td>
|
||||
<td>${sourceTypeCell(source)}</td>
|
||||
@@ -194,8 +194,8 @@
|
||||
<td>${priceCell(ln && ln.entry_price_fmt, ln && ln.entry_price)}</td>
|
||||
<td>${priceCell(ln && ln.mark_price_fmt, ln && ln.mark_price)}</td>
|
||||
<td>${contracts}</td>
|
||||
<td class="${pnlClass(pnl)}">${Number.isFinite(pnl) ? pnlSigned(pnl, 2) : "—"}</td>
|
||||
<td class="${pnlClass(pnl)}">${pct}</td>
|
||||
<td>${tpProfitCell(ln)}</td>
|
||||
<td>${floatPnlCell(ln)}</td>
|
||||
</tr>`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<link rel="stylesheet" href="/assets/trade_stats_calendar.css?v=4" />
|
||||
<link rel="stylesheet" href="/assets/account_risk_badge.css?v=4" />
|
||||
<script src="/assets/account_risk_badge.js?v=4"></script>
|
||||
<link rel="stylesheet" href="/assets/dashboard.css?v=20260720-dash-pos-type" />
|
||||
<link rel="stylesheet" href="/assets/dashboard.css?v=20260720-dash-pnl-align" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-bg" aria-hidden="true"></div>
|
||||
@@ -1385,7 +1385,7 @@
|
||||
<script src="/assets/archive.js?v=20260717-archive-cal-chart"></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=20260720-dash-pos-type"></script>
|
||||
<script src="/assets/dashboard.js?v=20260720-dash-pnl-align"></script>
|
||||
<script src="/assets/strategy.js?v=8"></script>
|
||||
<script src="/assets/help.js?v=1"></script>
|
||||
<script src="/assets/logs.js?v=1"></script>
|
||||
@@ -1394,6 +1394,6 @@
|
||||
<script src="/assets/options_expiry_countdown.js?v=1"></script>
|
||||
<script src="/assets/options_position_cards.js?v=2"></script>
|
||||
<script src="/assets/backup.js?v=1"></script>
|
||||
<script src="/assets/app.js?v=20260720-autofill"></script>
|
||||
<script src="/assets/app.js?v=20260720-dash-back"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user