import logging from datetime import datetime, timedelta, timezone from fastapi import APIRouter, Depends from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.models import BotTrade from app.schemas import BotPerformance router = APIRouter() logger = logging.getLogger(__name__) PERIOD_DAYS = 30 @router.get("/performance", response_model=BotPerformance) async def get_performance(db: AsyncSession = Depends(get_db)): since = datetime.now(timezone.utc).replace(tzinfo=None) - timedelta(days=PERIOD_DAYS) result = await db.execute( select(BotTrade) .where(BotTrade.closed_at.is_not(None)) .where(BotTrade.opened_at >= since) .order_by(BotTrade.opened_at.asc()) ) trades = result.scalars().all() total_trades = len(trades) if total_trades == 0: return BotPerformance( period_days=PERIOD_DAYS, total_trades=0, win_rate=0.0, net_pnl_usd=0.0, avg_hold_seconds=0.0, max_drawdown_pct=0.0, ) winning = sum(1 for t in trades if (t.pnl_usd or 0) > 0) win_rate = winning / total_trades pnl_values = [(t.pnl_usd or 0.0) for t in trades] net_pnl = sum(pnl_values) hold_values = [(t.hold_seconds or 0) for t in trades] avg_hold = sum(hold_values) / len(hold_values) # Max drawdown: running peak → trough of cumulative PnL cumulative = 0.0 peak = 0.0 max_drawdown = 0.0 for pnl in pnl_values: cumulative += pnl if cumulative > peak: peak = cumulative drawdown = (peak - cumulative) / peak * 100 if peak > 0 else 0.0 if drawdown > max_drawdown: max_drawdown = drawdown return BotPerformance( period_days=PERIOD_DAYS, total_trades=total_trades, win_rate=round(win_rate, 4), net_pnl_usd=round(net_pnl, 2), avg_hold_seconds=round(avg_hold, 1), max_drawdown_pct=round(max_drawdown, 4), )