""" Buy Signals API Endpoints """ from typing import List, Optional from datetime import datetime, timedelta from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, desc from app.core.database import get_db from app.models.signal import BuySignal from app.schemas.signal import SignalResponse, SignalWithDetails router = APIRouter() @router.get("/", response_model=List[SignalResponse]) async def list_signals( db: AsyncSession = Depends(get_db), status: Optional[str] = Query("active", description="Signal status: active, triggered, expired"), min_confidence: float = Query(0.5, ge=0, le=1, description="Minimum confidence score"), skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=100), ): """List buy signals ordered by confidence.""" query = select(BuySignal).where(BuySignal.confidence_score >= min_confidence) if status: query = query.where(BuySignal.status == status) query = query.order_by(desc(BuySignal.confidence_score)).offset(skip).limit(limit) result = await db.execute(query) return result.scalars().all() @router.get("/top") async def get_top_signals( db: AsyncSession = Depends(get_db), limit: int = Query(10, ge=1, le=20), ): """Get top buy signals by confidence score.""" query = ( select(BuySignal) .where(BuySignal.status == "active") .order_by(desc(BuySignal.confidence_score)) .limit(limit) ) result = await db.execute(query) signals = result.scalars().all() return { "count": len(signals), "signals": signals, } @router.get("/stock/{symbol}", response_model=List[SignalResponse]) async def get_signals_for_stock( symbol: str, db: AsyncSession = Depends(get_db), include_historical: bool = Query(False, description="Include past signals"), ): """Get buy signals for a specific stock.""" # We need to join with stocks table # For now, placeholder return [] @router.get("/{signal_id}", response_model=SignalWithDetails) async def get_signal( signal_id: UUID, db: AsyncSession = Depends(get_db), ): """Get detailed information about a specific signal.""" query = select(BuySignal).where(BuySignal.id == signal_id) result = await db.execute(query) signal = result.scalar_one_or_none() if not signal: raise HTTPException(status_code=404, detail="Signal not found") return signal @router.post("/{signal_id}/trigger") async def trigger_signal( signal_id: UUID, db: AsyncSession = Depends(get_db), ): """Mark a signal as triggered (you bought the stock).""" query = select(BuySignal).where(BuySignal.id == signal_id) result = await db.execute(query) signal = result.scalar_one_or_none() if not signal: raise HTTPException(status_code=404, detail="Signal not found") signal.status = "triggered" signal.triggered_at = datetime.utcnow() await db.commit() return {"message": "Signal marked as triggered", "signal_id": signal_id} @router.post("/{signal_id}/dismiss") async def dismiss_signal( signal_id: UUID, db: AsyncSession = Depends(get_db), ): """Dismiss a signal (not interested).""" query = select(BuySignal).where(BuySignal.id == signal_id) result = await db.execute(query) signal = result.scalar_one_or_none() if not signal: raise HTTPException(status_code=404, detail="Signal not found") signal.status = "cancelled" await db.commit() return {"message": "Signal dismissed", "signal_id": signal_id}