from fastapi import APIRouter, Depends, Request from fastapi.responses import HTMLResponse from sqlalchemy.orm import Session from app.database import get_db from app.models import Trade, OptionTrade, DualOptionTrade router = APIRouter(prefix="/summary", tags=["summary"]) WEEKDAYS = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"] def _stats(records, pnl_fn=None) -> dict: """Compute summary stats for a list of closed trade records.""" if pnl_fn is None: pnl_fn = lambda r: r.pnl total = len(records) total_pnl = sum(pnl_fn(r) or 0 for r in records) wins = sum(1 for r in records if (pnl_fn(r) or 0) > 0) open_fee = sum((r.open_fee or 0) for r in records) close_fee = sum((r.close_fee or 0) for r in records) total_fee = open_fee + close_fee # For dual options, also include call/put specific fees if records and hasattr(records[0], 'call_open_fee'): open_fee = sum((r.call_open_fee or 0) + (r.put_open_fee or 0) for r in records) close_fee = sum((r.call_close_fee or 0) + (r.put_close_fee or 0) for r in records) total_fee = open_fee + close_fee return { "count": total, "pnl": total_pnl, "wins": wins, "win_rate": round(wins / total * 100, 1) if total > 0 else 0, "open_fee": open_fee, "close_fee": close_fee, "total_fee": total_fee, } @router.get("/", response_class=HTMLResponse) def summary_page(request: Request, db: Session = Depends(get_db)): # Futures future_trades = ( db.query(Trade).filter(Trade.status == "closed") .order_by(Trade.close_date.desc()).all() ) future_stats = _stats(future_trades) # Options option_trades = ( db.query(OptionTrade).filter(OptionTrade.status == "closed") .order_by(OptionTrade.close_date.desc()).all() ) option_stats = _stats(option_trades) # Dual options dual_trades = ( db.query(DualOptionTrade).filter(DualOptionTrade.status == "closed") .order_by(DualOptionTrade.close_date.desc()).all() ) dual_stats = _stats(dual_trades) # Aggregate total_count = future_stats["count"] + option_stats["count"] + dual_stats["count"] total_pnl = future_stats["pnl"] + option_stats["pnl"] + dual_stats["pnl"] total_wins = future_stats["wins"] + option_stats["wins"] + dual_stats["wins"] total_win_rate = round(total_wins / total_count * 100, 1) if total_count > 0 else 0 total_fee = future_stats["total_fee"] + option_stats["total_fee"] + dual_stats["total_fee"] template = request.app.state.templates.get_template("summary.html") return HTMLResponse( template.render( request=request, active_nav="summary", total_count=total_count, total_pnl=total_pnl, total_wins=total_wins, total_win_rate=total_win_rate, total_fee=total_fee, future_stats=future_stats, future_trades=future_trades, option_stats=option_stats, option_trades=option_trades, dual_stats=dual_stats, dual_trades=dual_trades, weekdays=WEEKDAYS, ) )