Files
crypto_monitor/lib/hub/hub_monitor_totals_lib.py
T
dekun b733e551a0 Normalize fullwidth punctuation to ASCII across codebase.
Add scripts/normalize_ambiguous_unicode.py; fix corrupted patch_instance_theme_templates.py. Preserves curly quotes in string literals; removes Git homoglyph warnings on .env.example.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-08 23:42:26 +08:00

112 lines
3.6 KiB
Python

"""监控区看板:三所当日统计聚合."""
from __future__ import annotations
from typing import Any
from lib.hub.hub_options_funds_lib import (
options_float_pnl_usdt,
options_open_position_count as count_options_positions,
)
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
options_open_position_count = 0
float_pnl_u = 0.0
options_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)
opt_snap = row.get("options") if "options" in (row.get("capabilities") or []) else None
opt_count = count_options_positions(opt_snap)
options_open_position_count += opt_count
open_position_count += opt_count
opt_upl = options_float_pnl_usdt(opt_snap)
if opt_upl is not None:
options_float_pnl_u += opt_upl
float_pnl_u += opt_upl
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,
"options_open_position_count": options_open_position_count,
"float_pnl_u": round(float_pnl_u, 4),
"options_float_pnl_u": round(options_float_pnl_u, 4),
}