"""交易记录:字段补全、资金曲线数据。""" from __future__ import annotations from typing import Any TRADE_LOG_EXTRA_COLUMNS = ( "ALTER TABLE trade_logs ADD COLUMN margin_pct REAL", "ALTER TABLE trade_logs ADD COLUMN equity_after REAL", "ALTER TABLE trade_logs ADD COLUMN source TEXT DEFAULT 'local'", "ALTER TABLE trade_logs ADD COLUMN ctp_trade_key TEXT", ) def ensure_trade_log_columns(conn) -> None: for sql in TRADE_LOG_EXTRA_COLUMNS: try: conn.execute(sql) except Exception: pass def calc_equity_after(capital: float, pnl_net: float) -> float | None: cap = float(capital or 0) if cap <= 0: return None return round(cap + float(pnl_net or 0), 2) def enrich_trades_for_records( trades: list[dict[str, Any]], *, initial_capital: float = 0.0, ) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]: """表格仍按 id 降序;资金曲线按平仓时间升序用最新资金绘制。""" rows = [dict(t) for t in trades] chrono = sorted( rows, key=lambda t: ((t.get("close_time") or ""), int(t.get("id") or 0)), ) running = float(initial_capital or 0) curve: list[dict[str, Any]] = [] for t in chrono: pnl_net = float(t.get("pnl_net") or 0) eq = t.get("equity_after") if eq is None: if running > 0: eq = round(running + pnl_net, 2) else: eq = None t["equity_after"] = eq if eq is not None: running = float(eq) if t.get("margin_pct") is None: margin = float(t.get("margin") or 0) cap_before = float(eq or 0) - pnl_net if eq is not None else 0.0 if margin > 0 and cap_before > 0: t["margin_pct"] = round(margin / cap_before * 100, 2) if eq is not None: curve.append({ "time": (t.get("close_time") or "")[:19], "value": float(eq), "id": int(t.get("id") or 0), }) return rows, curve