"""实例页:持仓未实现盈亏(实时盈亏)汇总。""" from __future__ import annotations from collections.abc import Callable from typing import Any from lib.hub.hub_position_metrics import parse_position_unrealized_pnl def position_row_contracts(pos: dict[str, Any]) -> float: """持仓张数:与三所 app 内 _position_row_effective_contracts 规则一致。""" if not isinstance(pos, dict): return 0.0 info = pos.get("info") or {} if not isinstance(info, dict): info = {} for val in ( pos.get("contracts"), info.get("positionAmt"), info.get("size"), info.get("pos"), info.get("availPos"), ): if val is None or val == "": continue try: x = abs(float(val)) if x > 0: return x except (TypeError, ValueError): continue return 0.0 def sum_unrealized_pnl_from_positions(positions: list[dict[str, Any]] | None) -> float | None: total = 0.0 found = False for p in positions or []: if not isinstance(p, dict): continue if position_row_contracts(p) <= 1e-12: continue upnl = parse_position_unrealized_pnl(p) if upnl is None: continue found = True total += float(upnl) return round(total, 2) if found else None def _row_field(row: Any, key: str, default: str = "") -> str: if row is None: return default try: if hasattr(row, "keys") and key in row.keys(): val = row[key] elif isinstance(row, dict): val = row.get(key) else: val = None except Exception: val = None return str(val or default).strip() def sum_unrealized_pnl_from_metrics( rows: list[dict[str, Any]] | list[Any], get_metrics_fn: Callable[[str, str], dict[str, Any] | None], ) -> float | None: """按活跃监控单逐笔拉交易所 metrics 汇总(与持仓卡浮盈亏一致)。""" total = 0.0 found = False for row in rows or []: ex_sym = _row_field(row, "exchange_symbol") sym = _row_field(row, "symbol") direction = _row_field(row, "direction", "long").lower() or "long" target = ex_sym or sym if not target: continue metrics = get_metrics_fn(target, direction) if not isinstance(metrics, dict): continue upnl = metrics.get("unrealized_pnl") if upnl is None: continue try: total += float(upnl) found = True except (TypeError, ValueError): continue return round(total, 2) if found else None def fetch_unrealized_pnl(fetch_positions_fn: Callable[[], list[dict[str, Any]] | None]) -> float | None: try: return sum_unrealized_pnl_from_positions(fetch_positions_fn() or []) except Exception: return None def resolve_instance_unrealized_pnl( fetch_positions_fn: Callable[[], list[dict[str, Any]] | None], active_rows: list[Any] | None, get_metrics_fn: Callable[[str, str], dict[str, Any] | None] | None, ) -> float | None: """先全量持仓汇总,失败或无数据时回退到活跃监控单 metrics。""" total = fetch_unrealized_pnl(fetch_positions_fn) if total is not None: return total if active_rows and get_metrics_fn: return sum_unrealized_pnl_from_metrics(active_rows, get_metrics_fn) return None