新增平仓汇总页面,按期货/期权/双买分类统计盈亏和胜率
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
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,
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user