feat: 监控区 2x2 布局与左上今日统计卡
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
"""监控区看板:三所当日统计聚合。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
def _coerce_float(value: Any) -> float | None:
|
||||
if value is None or value == "":
|
||||
return None
|
||||
try:
|
||||
return float(value)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def position_unrealized_pnl(pos: dict[str, Any]) -> float:
|
||||
for key in ("unrealized_pnl", "unrealizedPnl", "upnl"):
|
||||
v = _coerce_float(pos.get(key))
|
||||
if v is not None:
|
||||
return v
|
||||
return 0.0
|
||||
|
||||
|
||||
def _open_positions(agent: dict[str, Any] | None) -> list[dict[str, Any]]:
|
||||
if not isinstance(agent, dict):
|
||||
return []
|
||||
positions = agent.get("positions")
|
||||
if not isinstance(positions, list):
|
||||
return []
|
||||
out: list[dict[str, Any]] = []
|
||||
for p in positions:
|
||||
if not isinstance(p, dict):
|
||||
continue
|
||||
try:
|
||||
c = abs(float(p.get("contracts") or 0))
|
||||
except (TypeError, ValueError):
|
||||
c = 0.0
|
||||
if c > 1e-12:
|
||||
out.append(p)
|
||||
return out
|
||||
|
||||
|
||||
def aggregate_monitor_board_totals(
|
||||
rows: list[dict[str, Any]],
|
||||
*,
|
||||
trading_day: str,
|
||||
reset_hour: int = 8,
|
||||
) -> dict[str, Any]:
|
||||
"""汇总监控 board 各行 → 左上统计卡数据。"""
|
||||
open_count = 0
|
||||
closed_count = 0
|
||||
win_count = 0
|
||||
loss_count = 0
|
||||
win_pnl_u = 0.0
|
||||
loss_pnl_u = 0.0
|
||||
open_position_count = 0
|
||||
float_pnl_u = 0.0
|
||||
|
||||
for row in rows or []:
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
day_stats = row.get("day_stats") if isinstance(row.get("day_stats"), dict) else {}
|
||||
if day_stats.get("ok"):
|
||||
open_count += int(day_stats.get("opens_today") or 0)
|
||||
st = day_stats.get("trade_stats") if isinstance(day_stats.get("trade_stats"), dict) else {}
|
||||
closed_count += int(st.get("closed_count") or 0)
|
||||
win_count += int(st.get("win_count") or 0)
|
||||
loss_count += int(st.get("loss_count") or 0)
|
||||
win_pnl_u += float(st.get("win_pnl_u") or 0)
|
||||
loss_pnl_u += float(st.get("loss_pnl_u") or 0)
|
||||
|
||||
ag = row.get("agent") if isinstance(row.get("agent"), dict) else {}
|
||||
open_pos = _open_positions(ag)
|
||||
open_position_count += len(open_pos)
|
||||
agent_upnl = _coerce_float(ag.get("total_unrealized_pnl"))
|
||||
if agent_upnl is not None:
|
||||
float_pnl_u += agent_upnl
|
||||
else:
|
||||
float_pnl_u += sum(position_unrealized_pnl(p) for p in open_pos)
|
||||
|
||||
return {
|
||||
"trading_day": trading_day,
|
||||
"reset_hour": int(reset_hour),
|
||||
"open_count": open_count,
|
||||
"closed_count": closed_count,
|
||||
"win_count": win_count,
|
||||
"loss_count": loss_count,
|
||||
"win_pnl_u": round(win_pnl_u, 4),
|
||||
"loss_pnl_u": round(loss_pnl_u, 4),
|
||||
"realized_pnl_u": round(win_pnl_u + loss_pnl_u, 4),
|
||||
"open_position_count": open_position_count,
|
||||
"float_pnl_u": round(float_pnl_u, 4),
|
||||
}
|
||||
Reference in New Issue
Block a user