""" Pydantic schemas for API request/response models. """ from datetime import datetime from typing import Any from pydantic import BaseModel, Field # --- Strategy Schemas --- class StrategyParam(BaseModel): """Single strategy parameter definition.""" name: str value: Any param_type: str = Field(description="Type: int, float, bool, list") min_value: float | None = None max_value: float | None = None description: str | None = None class StrategyInfo(BaseModel): """Strategy information with parameters.""" name: str display_name: str market_type: str default_leverage: int default_params: dict[str, Any] grid_params: dict[str, Any] class StrategiesResponse(BaseModel): """Response for GET /api/strategies.""" strategies: list[StrategyInfo] # --- Symbol/Data Schemas --- class SymbolInfo(BaseModel): """Available symbol information.""" symbol: str exchange: str market_type: str timeframes: list[str] start_date: str | None = None end_date: str | None = None row_count: int = 0 class DataStatusResponse(BaseModel): """Response for GET /api/data/status.""" symbols: list[SymbolInfo] # --- Backtest Schemas --- class BacktestRequest(BaseModel): """Request body for POST /api/backtest.""" strategy: str symbol: str exchange: str = "okx" timeframe: str = "1h" market_type: str = "perpetual" start_date: str | None = None end_date: str | None = None init_cash: float = 10000.0 leverage: int | None = None fees: float | None = None slippage: float = 0.001 sl_stop: float | None = None tp_stop: float | None = None sl_trail: bool = False params: dict[str, Any] = Field(default_factory=dict) class TradeRecord(BaseModel): """Single trade record.""" entry_time: str exit_time: str | None = None entry_price: float exit_price: float | None = None size: float direction: str pnl: float | None = None return_pct: float | None = None status: str = "closed" class EquityPoint(BaseModel): """Single point on equity curve.""" timestamp: str value: float drawdown: float = 0.0 class BacktestMetrics(BaseModel): """Backtest performance metrics.""" total_return: float benchmark_return: float = 0.0 alpha: float = 0.0 sharpe_ratio: float max_drawdown: float win_rate: float total_trades: int profit_factor: float | None = None avg_trade_return: float | None = None total_fees: float = 0.0 total_funding: float = 0.0 liquidation_count: int = 0 liquidation_loss: float = 0.0 adjusted_return: float | None = None class BacktestResult(BaseModel): """Complete backtest result.""" run_id: str strategy: str symbol: str market_type: str timeframe: str start_date: str end_date: str leverage: int params: dict[str, Any] metrics: BacktestMetrics equity_curve: list[EquityPoint] trades: list[TradeRecord] created_at: str class BacktestSummary(BaseModel): """Summary for backtest list view.""" run_id: str strategy: str symbol: str market_type: str timeframe: str total_return: float sharpe_ratio: float max_drawdown: float total_trades: int created_at: str params: dict[str, Any] class BacktestListResponse(BaseModel): """Response for GET /api/backtests.""" runs: list[BacktestSummary] total: int # --- Comparison Schemas --- class CompareRequest(BaseModel): """Request body for POST /api/compare.""" run_ids: list[str] = Field(min_length=2, max_length=5) class CompareResult(BaseModel): """Comparison of multiple backtest runs.""" runs: list[BacktestResult] param_diff: dict[str, list[Any]]