Files
crypto_trader/backend/core/schemas.py

214 lines
5.2 KiB
Python
Raw Normal View History

"""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