feat: add versioned research templates and alpha variants
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
"""Read-only baseline comparison over explicit local Alpha and PnL snapshots."""
|
||||
|
||||
import math
|
||||
|
||||
from fastapi import HTTPException
|
||||
|
||||
from ..models import Alpha, Pnl
|
||||
from .serialization import encode_snapshot as jsonable_encoder
|
||||
|
||||
|
||||
async def compare(db, alpha_ids):
|
||||
if len(set(alpha_ids)) != len(alpha_ids):
|
||||
raise HTTPException(422, "比较项不能重复")
|
||||
rows, by_id = [], {}
|
||||
for alpha_id in alpha_ids:
|
||||
alpha = await db.get(Alpha, alpha_id)
|
||||
if not alpha:
|
||||
raise HTTPException(404, f"Alpha {alpha_id} 尚未同步")
|
||||
pnl = await db.get(Pnl, alpha_id)
|
||||
by_id[alpha_id] = (
|
||||
{
|
||||
p["date"][:10]: p["value"]
|
||||
for p in pnl.points
|
||||
if type(p.get("value")) in (int, float) and math.isfinite(p["value"])
|
||||
}
|
||||
if pnl
|
||||
else {}
|
||||
)
|
||||
rows.append(
|
||||
{
|
||||
"alpha_id": alpha.id,
|
||||
"expression": alpha.expression,
|
||||
"settings": alpha.settings,
|
||||
"metrics": alpha.is_metrics,
|
||||
"observed_at": alpha.synced_at,
|
||||
"pnl_fetched_at": pnl.fetched_at if pnl else None,
|
||||
}
|
||||
)
|
||||
common = sorted(set.intersection(*(set(points) for points in by_id.values())))
|
||||
for row in rows:
|
||||
points = by_id[row["alpha_id"]]
|
||||
row["pnl"] = [{"date": date, "value": points[date] - points[common[0]]} for date in common]
|
||||
return jsonable_encoder(
|
||||
{
|
||||
"baseline_alpha_id": alpha_ids[0],
|
||||
"items": rows,
|
||||
"common_dates": common,
|
||||
"window": {"from": common[0], "to": common[-1]} if common else None,
|
||||
"different_settings": any(row["settings"] != rows[0]["settings"] for row in rows[1:]),
|
||||
"note": "PnL 按共同日期展示并从窗口起点归零;缓存缺失时请在 Alpha 详情获取 PnL",
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user