Files
crypto_trader/backend/core/schemas.py
kfox 7bd6be64a4
Some checks are pending
Documentation / build-docs (push) Waiting to run
Tests / test (macos-latest, 3.11) (push) Waiting to run
Tests / test (macos-latest, 3.12) (push) Waiting to run
Tests / test (macos-latest, 3.13) (push) Waiting to run
Tests / test (macos-latest, 3.14) (push) Waiting to run
Tests / test (ubuntu-latest, 3.11) (push) Waiting to run
Tests / test (ubuntu-latest, 3.12) (push) Waiting to run
Tests / test (ubuntu-latest, 3.13) (push) Waiting to run
Tests / test (ubuntu-latest, 3.14) (push) Waiting to run
feat: Add core trading modules for risk management, backtesting, and execution algorithms, alongside a new ML transparency widget and related frontend dependencies.
2025-12-31 21:25:06 -05:00

255 lines
6.5 KiB
Python

"""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
# Advanced order parameters
take_profit_price: Optional[Decimal] = None
stop_loss_price: Optional[Decimal] = None
trail_percent: Optional[Decimal] = None # For trailing stop (e.g., 0.02 for 2%)
# For bracket orders
bracket_take_profit: Optional[Decimal] = None
bracket_stop_loss: Optional[Decimal] = None
# For OCO orders
oco_price: Optional[Decimal] = None # Second order price for OCO
# For iceberg orders
visible_quantity: Optional[Decimal] = None # Visible quantity for iceberg
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 WalkForwardRequest(BaseModel):
"""Walk-forward analysis request."""
strategy_id: int
symbol: str
exchange: str
timeframe: str
start_date: datetime
end_date: datetime
train_period_days: int = 90
test_period_days: int = 30
step_days: int = 30
initial_capital: Decimal = Decimal("10000.0")
parameter_grid: Optional[Dict[str, List[Any]]] = None
optimization_metric: str = "sharpe_ratio"
class MonteCarloRequest(BaseModel):
"""Monte Carlo simulation request."""
strategy_id: int
symbol: str
exchange: str
timeframe: str
start_date: datetime
end_date: datetime
initial_capital: Decimal = Decimal("10000.0")
num_simulations: int = 1000
parameter_ranges: Optional[Dict[str, List[float]]] = None # {param_name: [min, max]}
random_seed: Optional[int] = None
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