""" Backtesting API endpoints. Responsabilidad: Manejar requests de backtesting (evaluación de modelos). """ from fastapi import APIRouter, Depends, HTTPException, status from app.api.dependencies import get_backtest_use_case from app.application.use_cases.backtest_use_case import BacktestUseCase from app.application.dtos.backtest_dtos import ( BacktestRequestDTO, BacktestResponseDTO ) from app.utils.logger import setup_logger logger = setup_logger(__name__) router = APIRouter(prefix="/backtest", tags=["Backtesting"]) @router.post( "/simple", response_model=BacktestResponseDTO, status_code=status.HTTP_200_OK, summary="Backtesting simple", description="Evalúa pronóstico comparando con valores reales" ) async def backtest_simple( request: BacktestRequestDTO, use_case: BacktestUseCase = Depends(get_backtest_use_case) ): """ Backtesting simple (hold-out). Divide la serie en train/test, genera pronóstico con train, y compara con test para calcular métricas de error. Args: request: Serie completa y parámetros de backtesting use_case: Caso de uso inyectado Returns: Métricas de error (MAE, MAPE, RMSE) y comparación forecast vs actual Example: ```json { "full_series": [100, 102, 105, 103, 108, 112, 115, 118], "test_size": 3, "freq": "D", "quantile_levels": [0.1, 0.5, 0.9] } ``` """ try: logger.info( f"Backtest request: {len(request.full_series)} values, " f"test_size={request.test_size}" ) # Ejecutar use case response = use_case.execute(request) logger.info( f"Backtest completed: MAE={response.metrics.mae:.2f}, " f"MAPE={response.metrics.mape:.2f}%" ) return response except ValueError as e: logger.error(f"Validation error: {e}") raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=str(e) ) except Exception as e: logger.error(f"Unexpected error in backtest: {e}", exc_info=True) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Error interno en backtesting" )