feat数据统计曲线改为各机累计已实现盈亏叠加,不再用余额采样。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+84
-7
@@ -1,12 +1,12 @@
|
||||
"""中控统计汇总:KPI 对比 + 余额曲线."""
|
||||
"""中控统计汇总:KPI 对比 + 已实现盈亏曲线."""
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from lib.bridge_client_lib import pull_all_enabled, pull_all_stats
|
||||
from lib.bridge_client_lib import pull_all_enabled, pull_all_pnl_curves, pull_all_stats
|
||||
from lib.cash_sample_lib import (
|
||||
first_cash_by_instance,
|
||||
query_cash_series,
|
||||
record_cash_samples_from_overview,
|
||||
)
|
||||
|
||||
@@ -185,7 +185,84 @@ def build_stats_summary(
|
||||
|
||||
|
||||
def build_stats_curve(range_key: str = "7d") -> dict[str, Any]:
|
||||
# 曲线只读本地采样库;余额采样由总览常驻 pull 负责
|
||||
data = query_cash_series(range_key=range_key)
|
||||
data["ok"] = True
|
||||
return data
|
||||
"""多机累计已实现盈亏曲线(各机台阶叠加;划转/提现不影响)."""
|
||||
rk = normalize_window(range_key)
|
||||
now_ms = int(time.time() * 1000)
|
||||
rows = pull_all_pnl_curves(rk)
|
||||
series: list[dict[str, Any]] = []
|
||||
by_id: dict[Any, list[dict[str, float]]] = {}
|
||||
start_ms = None
|
||||
end_ms = now_ms
|
||||
for row in rows:
|
||||
iid = row.get("id")
|
||||
pts_raw = row.get("points") if isinstance(row.get("points"), list) else []
|
||||
pts: list[dict[str, float]] = []
|
||||
for p in pts_raw:
|
||||
if not isinstance(p, dict):
|
||||
continue
|
||||
try:
|
||||
t = int(p.get("t"))
|
||||
v = float(p.get("v"))
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
pts.append({"t": t, "v": v})
|
||||
pts.sort(key=lambda x: x["t"])
|
||||
if row.get("start_ms") is not None:
|
||||
try:
|
||||
sm = int(row.get("start_ms"))
|
||||
start_ms = sm if start_ms is None else min(start_ms, sm)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
if row.get("end_ms") is not None:
|
||||
try:
|
||||
end_ms = max(end_ms, int(row.get("end_ms")))
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
by_id[iid] = pts
|
||||
series.append(
|
||||
{
|
||||
"id": iid,
|
||||
"name": row.get("name") or str(iid),
|
||||
"online": bool(row.get("online")),
|
||||
"error": row.get("error") or "",
|
||||
"points": pts,
|
||||
"trade_count": int(row.get("trade_count") or 0),
|
||||
"latest": row.get("latest"),
|
||||
}
|
||||
)
|
||||
|
||||
# 合计:按 1 分钟桶,各机该桶最后值求和并前向填充
|
||||
last_in_bucket: dict[int, dict[Any, float]] = {}
|
||||
for iid, pts in by_id.items():
|
||||
for p in pts:
|
||||
bt = (int(p["t"]) // 60000) * 60000
|
||||
last_in_bucket.setdefault(bt, {})[iid] = float(p["v"])
|
||||
running: dict[Any, float] = {}
|
||||
total_pts: list[dict[str, float]] = []
|
||||
for bt in sorted(last_in_bucket.keys()):
|
||||
running.update(last_in_bucket[bt])
|
||||
if running:
|
||||
total_pts.append({"t": bt, "v": round(sum(running.values()), 4)})
|
||||
|
||||
if start_ms is None:
|
||||
if rk in ("today", "1d"):
|
||||
import datetime as dt
|
||||
|
||||
start = dt.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
start_ms = int(start.timestamp() * 1000)
|
||||
elif rk in ("30d", "30"):
|
||||
start_ms = now_ms - 30 * 86400 * 1000
|
||||
elif rk in ("all", "0"):
|
||||
start_ms = 0
|
||||
else:
|
||||
start_ms = now_ms - 7 * 86400 * 1000
|
||||
|
||||
return {
|
||||
"ok": True,
|
||||
"metric": "realized_pnl",
|
||||
"series": series,
|
||||
"total": total_pts,
|
||||
"range": rk,
|
||||
"start_ms": start_ms,
|
||||
"end_ms": end_ms,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user