""" Pattern Intelligence Router. Endpoints for candlestick pattern detection, ML-based prediction, pattern catalog, and historical accuracy analysis. """ from __future__ import annotations import logging from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field from app.dependencies import get_current_user from app.models.user import User logger = logging.getLogger(__name__) router = APIRouter(prefix="/patterns", tags=["Pattern Intelligence"]) # ── Schemas ────────────────────────────────────────────────────────────── class PatternAnalyzeRequest(BaseModel): ticker: str = Field(..., min_length=1, max_length=20) period: str = Field("2y", description="Historical data period") horizon: int = Field(5, ge=1, le=30, description="Prediction horizon in days") class MultiAnalyzeRequest(BaseModel): tickers: List[str] = Field(..., min_items=1, max_items=10) period: str = Field("2y") horizon: int = Field(5, ge=1, le=30) class BacktestAccuracyRequest(BaseModel): ticker: str = Field(..., min_length=1, max_length=20) period: str = Field("5y") horizon: int = Field(5, ge=1, le=30) # ── Endpoints ──────────────────────────────────────────────────────────── @router.post("/analyze") async def analyze_patterns( data: PatternAnalyzeRequest, user: User = Depends(get_current_user), ): """ Detect candlestick patterns and predict price direction using pattern-aware LightGBM model with advanced mathematical features. Returns: - Predicted direction (strong_up / neutral / strong_down) - Confidence and probability distribution - Detected patterns with reliability scores - Top feature importances - Advanced feature values (Hurst, Fractal, Entropy, etc.) """ from app.services.ml.pattern_recognition.predictor import predict_with_patterns try: result = await predict_with_patterns( ticker=data.ticker, period=data.period, horizon=data.horizon, ) return result except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error("Pattern analysis failed for %s: %s", data.ticker, e, exc_info=True) raise HTTPException(status_code=500, detail="Pattern analysis failed") @router.post("/multi-analyze") async def multi_analyze( data: MultiAnalyzeRequest, user: User = Depends(get_current_user), ): """Analyze multiple tickers and return comparative results.""" from app.services.ml.pattern_recognition.predictor import analyze_multiple try: results = await analyze_multiple( tickers=data.tickers, period=data.period, horizon=data.horizon, ) return results except Exception as e: logger.error("Multi-analysis failed: %s", e, exc_info=True) raise HTTPException(status_code=500, detail="Multi-analysis failed") @router.get("/catalog") async def pattern_catalog( user: User = Depends(get_current_user), ): """ Get the full catalog of all 35+ supported candlestick and chart patterns with descriptions and reliability ratings. """ from app.services.ml.pattern_recognition.pattern_detector import pattern_detector return { "total_patterns": len(pattern_detector.get_pattern_catalog()), "patterns": pattern_detector.get_pattern_catalog(), } @router.post("/backtest-accuracy") async def backtest_accuracy( data: BacktestAccuracyRequest, user: User = Depends(get_current_user), ): """ Backtest pattern detection accuracy on historical data. For each pattern type, returns occurrences, win rate, average return, and actual vs theoretical reliability. """ from app.services.ml.pattern_recognition.predictor import backtest_pattern_accuracy try: result = await backtest_pattern_accuracy( ticker=data.ticker, period=data.period, horizon=data.horizon, ) return result except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error("Backtest accuracy failed for %s: %s", data.ticker, e, exc_info=True) raise HTTPException(status_code=500, detail="Backtest accuracy failed") @router.post("/clear-cache") async def clear_pattern_cache( user: User = Depends(get_current_user), ): """Clear the pattern predictor model cache.""" from app.services.ml.pattern_recognition.predictor import clear_cache count = clear_cache() return {"cleared": count}