51b8bb8f8a
Co-authored-by: Cursor <cursoragent@cursor.com>
44 lines
1.3 KiB
Python
44 lines
1.3 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, Depends
|
|
|
|
from ..models.db import get_db
|
|
from .auth import require_user
|
|
|
|
router = APIRouter(prefix="/api/stats", tags=["stats"])
|
|
|
|
|
|
@router.get("/summary")
|
|
async def stats_summary(_user: Annotated[str, Depends(require_user)]) -> dict:
|
|
db = get_db()
|
|
rows = db.fetchall("SELECT * FROM groups WHERE status='closed'")
|
|
n = len(rows)
|
|
wins = sum(1 for r in rows if float(r["realized_pnl"] or 0) > 0)
|
|
total_pnl = sum(float(r["realized_pnl"] or 0) for r in rows)
|
|
total_fees = sum(float(r["fees"] or 0) for r in rows)
|
|
total_slip = sum(float(r["slip_cost"] or 0) for r in rows)
|
|
reasons: dict[str, int] = {}
|
|
for r in rows:
|
|
k = str(r["close_reason"] or "unknown")
|
|
reasons[k] = reasons.get(k, 0) + 1
|
|
curve = [
|
|
{
|
|
"group_id": r["group_id"],
|
|
"realized_pnl": float(r["realized_pnl"] or 0),
|
|
"close_at_ms": r["close_at_ms"],
|
|
}
|
|
for r in sorted(rows, key=lambda x: int(x["close_at_ms"] or 0))
|
|
]
|
|
return {
|
|
"groups": n,
|
|
"wins": wins,
|
|
"win_rate": (wins / n) if n else 0.0,
|
|
"total_pnl": total_pnl,
|
|
"total_fees": total_fees,
|
|
"total_slip": total_slip,
|
|
"close_reasons": reasons,
|
|
"equity_curve": curve,
|
|
}
|