Fix OKX header trade stats stuck at zero after settings shell load.

Always SSR records summary on embed shell (including settings/risk/env), and refresh total/win-rate/PL ratio via account_snapshot so soft-nav cannot leave the strip blank.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-17 13:03:04 +08:00
parent 3a20546782
commit f27b4bc1ec
7 changed files with 72 additions and 5 deletions
+6 -1
View File
@@ -7458,6 +7458,9 @@ def api_account_snapshot():
active_pnl_rows = conn.execute(
"SELECT exchange_symbol, symbol, direction FROM order_monitors WHERE status='active'"
).fetchall()
from lib.instance.instance_embed_context_lib import header_trade_stats_for_window, total_funds_usdt
header_trade_stats = header_trade_stats_for_window(conn, _list_window_from_request(), APP_TZ)
conn.close()
can_trade = can_trade_new_open(
time_allows=trading_day_reset_allows_new_open(now),
@@ -7468,7 +7471,6 @@ def api_account_snapshot():
extra_blocks=not risk_status.get("can_trade", True),
)
available_trading_usdt = get_available_trading_usdt()
from lib.instance.instance_embed_context_lib import total_funds_usdt
unrealized_pnl = None
if exchange_private_api_configured():
@@ -7498,6 +7500,9 @@ def api_account_snapshot():
"daily_open_alert_threshold": DAILY_OPEN_ALERT_THRESHOLD,
"manual_min_planned_rr": MANUAL_MIN_PLANNED_RR,
"trading_day": trading_day,
"total": header_trade_stats["total"],
"rate": header_trade_stats["rate"],
"profit_loss_ratio": header_trade_stats.get("profit_loss_ratio"),
"risk_status": risk_status,
**force_close_template_context(
FORCE_CLOSE_ENABLED,
+6 -1
View File
@@ -7274,6 +7274,9 @@ def api_account_snapshot():
active_pnl_rows = conn.execute(
"SELECT exchange_symbol, symbol, direction FROM order_monitors WHERE status='active'"
).fetchall()
from lib.instance.instance_embed_context_lib import header_trade_stats_for_window, total_funds_usdt
header_trade_stats = header_trade_stats_for_window(conn, _list_window_from_request(), APP_TZ)
conn.close()
can_trade = can_trade_new_open(
time_allows=trading_day_reset_allows_new_open(now),
@@ -7284,7 +7287,6 @@ def api_account_snapshot():
extra_blocks=not risk_status.get("can_trade", True),
)
available_trading_usdt = get_available_trading_usdt()
from lib.instance.instance_embed_context_lib import total_funds_usdt
unrealized_pnl = None
if exchange_private_api_configured():
@@ -7317,6 +7319,9 @@ def api_account_snapshot():
"daily_open_alert_threshold": DAILY_OPEN_ALERT_THRESHOLD,
"manual_min_planned_rr": MANUAL_MIN_PLANNED_RR,
"trading_day": trading_day,
"total": header_trade_stats["total"],
"rate": header_trade_stats["rate"],
"profit_loss_ratio": header_trade_stats.get("profit_loss_ratio"),
"risk_status": risk_status,
**force_close_template_context(
FORCE_CLOSE_ENABLED,
+6 -1
View File
@@ -6942,6 +6942,9 @@ def api_account_snapshot():
active_pnl_rows = conn.execute(
"SELECT exchange_symbol, symbol, direction FROM order_monitors WHERE status='active'"
).fetchall()
from lib.instance.instance_embed_context_lib import header_trade_stats_for_window, total_funds_usdt
header_trade_stats = header_trade_stats_for_window(conn, _list_window_from_request(), APP_TZ)
conn.close()
open_guard_blocks_now = open_guard_enabled and now.hour < TRADING_DAY_RESET_HOUR
can_trade = can_trade_new_open(
@@ -6953,7 +6956,6 @@ def api_account_snapshot():
extra_blocks=not risk_status.get("can_trade", True),
)
available_trading_usdt = get_available_trading_usdt()
from lib.instance.instance_embed_context_lib import total_funds_usdt
unrealized_pnl = None
if exchange_private_api_configured():
@@ -7021,6 +7023,9 @@ def api_account_snapshot():
"reset_hour": TRADING_DAY_RESET_HOUR,
"manual_min_planned_rr": MANUAL_MIN_PLANNED_RR,
"trading_day": trading_day,
"total": header_trade_stats["total"],
"rate": header_trade_stats["rate"],
"profit_loss_ratio": header_trade_stats.get("profit_loss_ratio"),
"risk_status": risk_status,
**force_close_template_context(
FORCE_CLOSE_ENABLED,
+18 -2
View File
@@ -38,11 +38,11 @@ def embed_render_plan(page: str, embed_mode: str | None) -> EmbedRenderPlan:
)
is_shell = embed_mode == "shell"
is_strategy = page in EMBED_STRATEGY_PAGES
is_settings_like = page in ("settings", "risk_policy", "env_config")
return EmbedRenderPlan(
exchange_capitals=is_shell,
records_rows=page == "records",
records_summary=is_shell and page != "records" and not is_settings_like,
# 顶栏常驻:设置/风控/env 也要统计,否则首屏 SSR 为 0 后软切 tab 不会重绘顶栏
records_summary=is_shell and page != "records",
key_history=page == "key_monitor",
key_list=page in ("key_monitor", "trade") or is_strategy,
orders=page == "trade" or is_strategy,
@@ -157,5 +157,21 @@ def trade_records_summary(conn, start_bj: str, end_bj: str, tr_ts: str) -> dict[
}
def header_trade_stats_for_window(conn, list_window: dict[str, Any], app_tz) -> dict[str, Any]:
"""account_snapshot / 顶栏刷新:按当前列表窗返回总交易/胜率/盈亏比."""
from lib.common.history_window_lib import sql_list_time_field, utc_window_to_bj_sql_strings
start_bj, end_bj = utc_window_to_bj_sql_strings(
list_window["start_utc"], list_window["end_utc"], app_tz
)
tr_ts = sql_list_time_field("closed_at", "created_at", "opened_at")
summary = trade_records_summary(conn, start_bj, end_bj, tr_ts)
return {
"total": summary["total"],
"rate": summary["rate"],
"profit_loss_ratio": summary.get("profit_loss_ratio"),
}
def minimal_stats_bundle(reset_hour: int) -> dict[str, Any]:
return {"stats_reset_hour": reset_hour, "segments": []}
@@ -1178,6 +1178,20 @@ function applyAccountSnapshot(data){
if(typeof data.unrealized_pnl !== "undefined"){
updateRealtimePnl(data.unrealized_pnl);
}
if(typeof data.total !== "undefined" && data.total !== null){
setFundsFieldText("stat-total", String(data.total));
}
if(typeof data.rate !== "undefined" && data.rate !== null){
setFundsFieldText("stat-rate", `${Number(data.rate)}%`);
}
if(typeof data.profit_loss_ratio !== "undefined"){
setFundsFieldText(
"stat-pl-ratio",
data.profit_loss_ratio != null && data.profit_loss_ratio !== ""
? String(data.profit_loss_ratio)
: "—"
);
}
if(typeof data.available_trading_usdt !== "undefined" && data.available_trading_usdt !== null){
latestAvailableUsdt = Number(data.available_trading_usdt);
}
+14
View File
@@ -1659,6 +1659,20 @@ function applyAccountSnapshot(data){
if(typeof data.unrealized_pnl !== "undefined"){
updateRealtimePnl(data.unrealized_pnl);
}
if(typeof data.total !== "undefined" && data.total !== null){
setFundsFieldText("stat-total", String(data.total));
}
if(typeof data.rate !== "undefined" && data.rate !== null){
setFundsFieldText("stat-rate", `${Number(data.rate)}%`);
}
if(typeof data.profit_loss_ratio !== "undefined"){
setFundsFieldText(
"stat-pl-ratio",
data.profit_loss_ratio != null && data.profit_loss_ratio !== ""
? String(data.profit_loss_ratio)
: "—"
);
}
if(typeof data.available_trading_usdt !== "undefined" && data.available_trading_usdt !== null){
latestAvailableUsdt = Number(data.available_trading_usdt);
}
+8
View File
@@ -17,6 +17,14 @@ def test_embed_shell_trade_summary_only():
assert plan.records_rows is False
def test_embed_shell_settings_still_loads_header_summary():
plan = embed_render_plan("settings", "shell")
assert plan.records_summary is True
assert plan.records_rows is False
plan_risk = embed_render_plan("risk_policy", "shell")
assert plan_risk.records_summary is True
def test_embed_records_page_loads_rows():
plan = embed_render_plan("records", "fragment")
assert plan.records_rows is True