feat: display five GLB PnL series with distinct colors
Deploy production / deploy (push) Successful in 56s
Deploy production / deploy (push) Successful in 56s
This commit is contained in:
+35
-5
@@ -251,7 +251,7 @@ def summary(item: Alpha, research: Research):
|
||||
return result
|
||||
|
||||
|
||||
def pnl_points(raw):
|
||||
def pnl_points(raw, column=None):
|
||||
"""Use schema column names, preserving missing values rather than creating zero PnL."""
|
||||
records = raw.get("records")
|
||||
schema = raw.get("schema") or {}
|
||||
@@ -261,6 +261,7 @@ def pnl_points(raw):
|
||||
else:
|
||||
names = [p.get("name", "") if isinstance(p, dict) else str(p) for p in properties]
|
||||
normalized = [name.lower() for name in names]
|
||||
value_names = (column,) if column else ("pnl", "value")
|
||||
if not isinstance(records, list):
|
||||
raise ValueError("PnL 缺少 records")
|
||||
points = []
|
||||
@@ -268,15 +269,17 @@ def pnl_points(raw):
|
||||
if isinstance(row, dict):
|
||||
row = {str(k).lower(): v for k, v in row.items()}
|
||||
timestamp = next((row[k] for k in ("date", "datetime", "timestamp") if k in row), None)
|
||||
value = next((row[k] for k in ("pnl", "value") if k in row), None)
|
||||
value = next((row[k] for k in value_names if k in row), None)
|
||||
else:
|
||||
date_i = next(
|
||||
(i for i, n in enumerate(normalized) if n in ("date", "datetime", "timestamp")), None
|
||||
)
|
||||
pnl_i = next((i for i, n in enumerate(normalized) if n in ("pnl", "value")), None)
|
||||
if date_i is None or pnl_i is None or not isinstance(row, list) or len(row) <= max(date_i, pnl_i):
|
||||
pnl_i = next((i for i, n in enumerate(normalized) if n in value_names), None)
|
||||
if date_i is None or pnl_i is None or not isinstance(row, list) or len(row) <= date_i:
|
||||
raise ValueError("PnL schema 无法识别日期或数值列")
|
||||
timestamp, value = row[date_i], row[pnl_i]
|
||||
if len(row) <= pnl_i and column is None:
|
||||
raise ValueError("PnL schema 无法识别日期或数值列")
|
||||
timestamp, value = row[date_i], row[pnl_i] if len(row) > pnl_i else None
|
||||
if timestamp is not None:
|
||||
if isinstance(timestamp, (int, float)):
|
||||
from datetime import timezone
|
||||
@@ -286,3 +289,30 @@ def pnl_points(raw):
|
||||
).isoformat()
|
||||
points.append({"date": str(timestamp), "value": number(value)})
|
||||
return sorted(points, key=lambda p: p["date"])
|
||||
|
||||
|
||||
def glb_pnl_series(raw, points):
|
||||
"""Read GLB display series from cached raw data; keep the correlation baseline intact.
|
||||
|
||||
Missing columns are omitted, while missing values remain gaps. Legacy caches
|
||||
containing only normalized points still return their overall PnL.
|
||||
"""
|
||||
series = [{"id": "pnl", "label": "总体 PnL", "points": points}]
|
||||
schema = raw.get("schema") or {}
|
||||
properties = schema.get("properties", []) if isinstance(schema, dict) else schema
|
||||
names = properties if isinstance(properties, dict) else [
|
||||
p.get("name", "") if isinstance(p, dict) else str(p) for p in properties
|
||||
]
|
||||
available = {name.lower() for name in names}
|
||||
for row in raw.get("records", []):
|
||||
if isinstance(row, dict):
|
||||
available.update(str(key).lower() for key in row)
|
||||
for column, label in (
|
||||
("investability-constrained-pnl", "可投资性约束 PnL"),
|
||||
("amer-pnl", "AMER PnL"),
|
||||
("apac-pnl", "APAC PnL"),
|
||||
("emea-pnl", "EMEA PnL"),
|
||||
):
|
||||
if column in available:
|
||||
series.append({"id": column, "label": label, "points": pnl_points(raw, column)})
|
||||
return series
|
||||
|
||||
Reference in New Issue
Block a user