Move fleet stats to nav page; backfill funds and loss metrics from curve/status.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-02 12:43:17 +08:00
parent 921e96321f
commit cd46d7748c
5 changed files with 237 additions and 164 deletions
+44 -3
View File
@@ -278,6 +278,26 @@ async def node_status(
return await _collect_one_status(node)
def _max_single_loss_from_curve(curve: list[Any]) -> float:
pnls = [float(x.get("realized_pnl") or 0) for x in curve if isinstance(x, dict)]
if not pnls:
return 0.0
worst = min(pnls)
return float(worst) if worst < 0 else 0.0
def _loss_streak_from_curve(curve: list[Any]) -> int:
streak = 0
for item in reversed(curve):
if not isinstance(item, dict):
continue
if float(item.get("realized_pnl") or 0) < 0:
streak += 1
else:
break
return streak
async def _collect_one_stats(node: dict[str, Any]) -> dict[str, Any]:
base = {
"id": node["id"],
@@ -304,16 +324,37 @@ async def _collect_one_stats(node: dict[str, Any]) -> dict[str, Any]:
if code >= 400 or not isinstance(data, dict):
base["error"] = _http_detail(data) if data else f"HTTP {code}"
return base
curve = data.get("equity_curve") if isinstance(data.get("equity_curve"), list) else []
max_loss = data.get("max_single_loss")
if max_loss is None:
max_loss = _max_single_loss_from_curve(curve)
loss_streak = data.get("loss_streak")
if loss_streak is None:
loss_streak = _loss_streak_from_curve(curve)
latest_funds = data.get("latest_funds")
if latest_funds is None:
# 旧版策略机 stats 无资金字段:回落 status.latest_funds
try:
sc, sd = await call_node(node, "GET", "/api/fleet/status", timeout=8.0)
if sc < 400 and isinstance(sd, dict) and sd.get("latest_funds") is not None:
latest_funds = sd.get("latest_funds")
except Exception:
pass
if latest_funds is None:
latest_funds = 0.0
base.update(
{
"ok": True,
"latest_funds": data.get("latest_funds"),
"latest_funds": latest_funds,
"groups": data.get("groups"),
"fees_perp": data.get("fees_perp"),
"fees_option": data.get("fees_option"),
"total_fees": data.get("total_fees"),
"max_single_loss": data.get("max_single_loss"),
"loss_streak": data.get("loss_streak"),
"max_single_loss": max_loss,
"loss_streak": loss_streak,
"total_pnl": data.get("total_pnl"),
"mode": data.get("mode"),
}