diff --git a/manual_trading_hub/hub.py b/manual_trading_hub/hub.py index 3bba1fc..8e39b6c 100644 --- a/manual_trading_hub/hub.py +++ b/manual_trading_hub/hub.py @@ -1062,8 +1062,8 @@ def _merge_flask_exchange_tpsl(agent_row: dict, snap: dict | None, hub_mon: dict async def _fetch_exchange_flask_bundle( client: httpx.AsyncClient, ex: dict -) -> tuple[dict | None, dict | None, list | None, dict | None]: - """单所 Flask:monitor / meta / price_snapshot(有 flask_url 时)并行拉取。""" +) -> tuple[dict | None, dict | None, list | None, dict | None, dict | None]: + """单所 Flask:monitor / meta / price_snapshot / account(有 flask_url 时)并行拉取。""" caps = ex.get("capabilities") or [] tasks = [ _fetch_flask_json(client, ex, "/api/hub/monitor"), @@ -1071,28 +1071,43 @@ async def _fetch_exchange_flask_bundle( ] has_flask = bool((ex.get("flask_url") or "").strip()) if has_flask: - tasks.append(_fetch_flask_json(client, ex, "/api/price_snapshot")) + tasks.extend( + [ + _fetch_flask_json(client, ex, "/api/price_snapshot"), + _fetch_flask_json(client, ex, "/api/hub/account"), + ] + ) results = await asyncio.gather(*tasks) hub_mon = results[0] meta = results[1] snap = results[2] if has_flask and len(results) > 2 else None + account = results[3] if has_flask and len(results) > 3 else None key_prices = None want_prices = HUB_BOARD_KEY_PRICES and "key" in caps if want_prices and isinstance(snap, dict): key_prices = snap.get("key_prices") - return hub_mon, meta, key_prices, snap if isinstance(snap, dict) else None + return ( + hub_mon, + meta, + key_prices, + snap if isinstance(snap, dict) else None, + account if isinstance(account, dict) else None, + ) async def _assemble_board_row( client: httpx.AsyncClient, ex: dict, agent_row: dict ) -> dict: - hub_mon, meta, key_prices, snap = await _fetch_exchange_flask_bundle(client, ex) + hub_mon, meta, key_prices, snap, account = await _fetch_exchange_flask_bundle( + client, ex + ) if isinstance(hub_mon, dict): _merge_flask_order_price_fields(hub_mon, snap) _merge_flask_exchange_tpsl(agent_row, snap, hub_mon if isinstance(hub_mon, dict) else None) _merge_flask_position_breakeven(agent_row, snap, hub_mon if isinstance(hub_mon, dict) else None) _merge_flask_position_mark_price(agent_row, snap, hub_mon if isinstance(hub_mon, dict) else None) flask_ok = isinstance(hub_mon, dict) and hub_mon.get("ok") is not False + acct_ok = isinstance(account, dict) and account.get("ok") is not False raw_review = (ex.get("review_url") or "").strip() review_link = browser_url(raw_review) if raw_review else default_review_url( ex.get("flask_url") @@ -1107,6 +1122,10 @@ async def _assemble_board_row( "flask_error": _flask_error_from_hub_mon(hub_mon if isinstance(hub_mon, dict) else None), "meta": (meta or {}).get("meta") if isinstance(meta, dict) else meta, "key_prices": key_prices, + "funding_usdt": account.get("funding_usdt") if acct_ok else None, + "trading_usdt": account.get("trading_usdt") if acct_ok else None, + "available_trading_usdt": account.get("available_trading_usdt") if acct_ok else None, + "account_ok": acct_ok, } diff --git a/manual_trading_hub/static/app.css b/manual_trading_hub/static/app.css index c3772dc..7635104 100644 --- a/manual_trading_hub/static/app.css +++ b/manual_trading_hub/static/app.css @@ -1354,7 +1354,7 @@ body.market-chart-fs-open { .stat-row { display: grid; - grid-template-columns: 1fr 1fr; + grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-bottom: 12px; } @@ -2463,12 +2463,16 @@ body.login-page { } .stat-row { - grid-template-columns: 1fr 1fr; - gap: 8px; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 6px; } .stat-value { - font-size: 15px; + font-size: 14px; + } + + .stat-label { + font-size: 9px; } .exchange-fullscreen { diff --git a/manual_trading_hub/static/app.js b/manual_trading_hub/static/app.js index 0b0c85e..c32c612 100644 --- a/manual_trading_hub/static/app.js +++ b/manual_trading_hub/static/app.js @@ -854,7 +854,11 @@ const pos = Array.isArray(ag.positions) ? ag.positions : []; const flaskOk = row.flask_ok !== false && hm.ok !== false; const upnl = Number(ag.total_unrealized_pnl); - const balance = Number(ag.balance_usdt); + const tradingBal = Number(row.trading_usdt); + const balance = + Number.isFinite(tradingBal) && tradingBal > 0 + ? tradingBal + : Number(ag.balance_usdt); const sortUpnl = Number.isFinite(upnl) ? upnl : 0; if (!row.http_ok) { @@ -2298,12 +2302,18 @@ `; } + function renderAccountStatRow(row, ag) { + const upnl = ag.total_unrealized_pnl; + return `