""" Backtest related Pydantic schemas. """ from datetime import date, datetime from decimal import Decimal from typing import Optional, List, Dict, Any from enum import Enum from pydantic import BaseModel, Field class RebalancePeriod(str, Enum): MONTHLY = "monthly" QUARTERLY = "quarterly" SEMI_ANNUAL = "semi_annual" ANNUAL = "annual" class BacktestStatus(str, Enum): PENDING = "pending" RUNNING = "running" COMPLETED = "completed" FAILED = "failed" class BacktestCreate(BaseModel): """Request to create a new backtest.""" strategy_type: str = Field(..., description="multi_factor, quality, or value_momentum") strategy_params: Dict[str, Any] = Field(default_factory=dict) start_date: date end_date: date rebalance_period: RebalancePeriod = RebalancePeriod.QUARTERLY initial_capital: Decimal = Field(default=Decimal("100000000"), gt=0) commission_rate: Decimal = Field(default=Decimal("0.00015"), ge=0, le=1) slippage_rate: Decimal = Field(default=Decimal("0.001"), ge=0, le=1) benchmark: str = Field(default="KOSPI") top_n: int = Field(default=30, ge=1, le=100) class BacktestMetrics(BaseModel): """Backtest result metrics.""" total_return: Decimal cagr: Decimal mdd: Decimal sharpe_ratio: Decimal volatility: Decimal benchmark_return: Decimal excess_return: Decimal class BacktestResponse(BaseModel): """Backtest response with status and optional results.""" id: int user_id: int strategy_type: str strategy_params: Dict[str, Any] start_date: date end_date: date rebalance_period: str initial_capital: Decimal commission_rate: Decimal slippage_rate: Decimal benchmark: str status: str created_at: datetime completed_at: Optional[datetime] = None error_message: Optional[str] = None result: Optional[BacktestMetrics] = None class Config: from_attributes = True class BacktestListItem(BaseModel): """Backtest item for list view.""" id: int strategy_type: str start_date: date end_date: date rebalance_period: str status: str created_at: datetime total_return: Optional[Decimal] = None cagr: Optional[Decimal] = None mdd: Optional[Decimal] = None class Config: from_attributes = True class EquityCurvePoint(BaseModel): """Single point in equity curve.""" date: date portfolio_value: Decimal benchmark_value: Decimal drawdown: Decimal class Config: from_attributes = True class HoldingItem(BaseModel): """Single holding at a rebalance date.""" ticker: str name: str weight: Decimal shares: int price: Decimal class RebalanceHoldings(BaseModel): """Holdings at a specific rebalance date.""" rebalance_date: date holdings: List[HoldingItem] class TransactionItem(BaseModel): """Single transaction.""" id: int date: date ticker: str action: str shares: int price: Decimal commission: Decimal class Config: from_attributes = True