"""Pydantic schemas for request/response validation.""" from datetime import datetime, timezone from decimal import Decimal from typing import Optional, List, Dict, Any from pydantic import BaseModel, Field, ConfigDict, field_validator from enum import Enum class OrderSide(str, Enum): """Order side.""" BUY = "buy" SELL = "sell" class OrderType(str, Enum): """Order type.""" MARKET = "market" LIMIT = "limit" STOP_LOSS = "stop_loss" TAKE_PROFIT = "take_profit" TRAILING_STOP = "trailing_stop" OCO = "oco" ICEBERG = "iceberg" class OrderStatus(str, Enum): """Order status.""" PENDING = "pending" OPEN = "open" PARTIALLY_FILLED = "partially_filled" FILLED = "filled" CANCELLED = "cancelled" REJECTED = "rejected" EXPIRED = "expired" # Trading Schemas class OrderCreate(BaseModel): """Create order request.""" exchange_id: int symbol: str side: OrderSide order_type: OrderType quantity: Decimal price: Optional[Decimal] = None strategy_id: Optional[int] = None paper_trading: bool = True class OrderResponse(BaseModel): """Order response.""" model_config = ConfigDict(from_attributes=True, populate_by_name=True) id: int exchange_id: int strategy_id: Optional[int] symbol: str order_type: OrderType side: OrderSide status: OrderStatus quantity: Decimal price: Optional[Decimal] filled_quantity: Decimal average_fill_price: Optional[Decimal] fee: Decimal paper_trading: bool created_at: datetime updated_at: datetime filled_at: Optional[datetime] @field_validator('created_at', 'updated_at', 'filled_at', mode='after') @classmethod def ensure_utc(cls, v: Optional[datetime]) -> Optional[datetime]: if v and v.tzinfo is None: return v.replace(tzinfo=timezone.utc) return v class PositionResponse(BaseModel): """Position response.""" model_config = ConfigDict(from_attributes=True, populate_by_name=True) symbol: str quantity: Decimal entry_price: Decimal current_price: Decimal unrealized_pnl: Decimal realized_pnl: Decimal # Portfolio Schemas class PortfolioResponse(BaseModel): """Portfolio response.""" positions: List[Dict[str, Any]] performance: Dict[str, float] timestamp: str class PortfolioHistoryResponse(BaseModel): """Portfolio history response.""" dates: List[str] values: List[float] pnl: List[float] # Strategy Schemas class StrategyCreate(BaseModel): """Create strategy request.""" name: str description: Optional[str] = None strategy_type: str class_name: str parameters: Dict[str, Any] = Field(default_factory=dict) timeframes: List[str] = Field(default_factory=lambda: ["1h"]) paper_trading: bool = True schedule: Optional[Dict[str, Any]] = None class StrategyUpdate(BaseModel): """Update strategy request.""" name: Optional[str] = None description: Optional[str] = None parameters: Optional[Dict[str, Any]] = None timeframes: Optional[List[str]] = None enabled: Optional[bool] = None schedule: Optional[Dict[str, Any]] = None class StrategyResponse(BaseModel): """Strategy response.""" model_config = ConfigDict(from_attributes=True, populate_by_name=True) id: int name: str description: Optional[str] strategy_type: str class_name: str parameters: Dict[str, Any] timeframes: List[str] enabled: bool running: bool = False paper_trading: bool version: str schedule: Optional[Dict[str, Any]] created_at: datetime updated_at: datetime @field_validator('created_at', 'updated_at', mode='after') @classmethod def ensure_utc(cls, v: Optional[datetime]) -> Optional[datetime]: if v and v.tzinfo is None: return v.replace(tzinfo=timezone.utc) return v # Backtesting Schemas class BacktestRequest(BaseModel): """Backtest request.""" strategy_id: int symbol: str exchange: str timeframe: str start_date: datetime end_date: datetime initial_capital: Decimal = Decimal("100.0") slippage: float = 0.001 fee_rate: float = 0.001 class BacktestResponse(BaseModel): """Backtest response.""" backtest_id: Optional[int] = None results: Dict[str, Any] status: str = "completed" # Exchange Schemas class ExchangeResponse(BaseModel): """Exchange response.""" model_config = ConfigDict(from_attributes=True, populate_by_name=True) id: int name: str sandbox: bool read_only: bool enabled: bool created_at: datetime updated_at: datetime @field_validator('created_at', 'updated_at', mode='after') @classmethod def ensure_utc(cls, v: Optional[datetime]) -> Optional[datetime]: if v and v.tzinfo is None: return v.replace(tzinfo=timezone.utc) return v # WebSocket Messages class PriceUpdate(BaseModel): """Price update message.""" exchange: str symbol: str price: Decimal timestamp: datetime class OrderUpdate(BaseModel): """Order update message.""" order_id: int status: OrderStatus filled_quantity: Optional[Decimal] = None timestamp: datetime