9deb58a38a
Co-authored-by: Cursor <cursoragent@cursor.com>
94 lines
3.0 KiB
Python
94 lines
3.0 KiB
Python
"""监控区看板:三所当日统计聚合。"""
|
|
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),
|
|
}
|