""" Data models for the Exchange Kernel. Defines order intents, order state, positions, assets, and account state. """ from enum import StrEnum from typing import Any from pydantic import BaseModel, Field from ..schema.order_spec import ( StandardOrder, StandardOrderStatus, AssetType, Float, Uint64, ) # --------------------------------------------------------------------------- # Order Intent and State # --------------------------------------------------------------------------- class OrderIntent(BaseModel): """ Desired order state from the strategy kernel. This represents what the strategy wants, not what currently exists. The exchange kernel will work to reconcile actual state with this intent. """ model_config = {"extra": "forbid"} intent_id: str = Field(description="Unique identifier for this intent (client-assigned)") order: StandardOrder = Field(description="The desired order specification") group_id: str | None = Field(default=None, description="Group ID for OCO relationships") created_at: Uint64 = Field(description="When this intent was created") updated_at: Uint64 = Field(description="When this intent was last modified") metadata: dict[str, Any] = Field(default_factory=dict, description="Strategy-specific metadata") class ReconciliationStatus(StrEnum): """Status of reconciliation between intent and actual state""" PENDING = "PENDING" # Not yet submitted to exchange SUBMITTING = "SUBMITTING" # Currently being submitted ACTIVE = "ACTIVE" # Successfully placed on exchange RECONCILING = "RECONCILING" # Intent changed, updating exchange order FAILED = "FAILED" # Failed to submit or reconcile COMPLETED = "COMPLETED" # Order fully filled CANCELED = "CANCELED" # Order canceled class OrderState(BaseModel): """ Actual current state of an order on the exchange. This represents reality - what the exchange reports about the order. May differ from OrderIntent during reconciliation. """ model_config = {"extra": "forbid"} intent_id: str = Field(description="Links back to the OrderIntent") exchange_order_id: str = Field(description="Exchange-assigned order ID") status: StandardOrderStatus = Field(description="Current order status from exchange") reconciliation_status: ReconciliationStatus = Field(description="Reconciliation state") last_sync_at: Uint64 = Field(description="Last time we synced with exchange") error_message: str | None = Field(default=None, description="Error details if FAILED") # --------------------------------------------------------------------------- # Position and Asset Models # --------------------------------------------------------------------------- class AssetMetadata(BaseModel): """ Metadata describing an asset type. Provides context for positions, balances, and trading. """ model_config = {"extra": "forbid"} asset_id: str = Field(description="Unique asset identifier") symbol: str = Field(description="Asset symbol (e.g., 'BTC', 'ETH', 'USD')") asset_type: AssetType = Field(description="Type of asset") name: str = Field(description="Full name") # Contract specifications (for derivatives) contract_size: Float | None = Field(default=None, description="Contract multiplier") settlement_asset: str | None = Field(default=None, description="Settlement currency") expiry_timestamp: Uint64 | None = Field(default=None, description="Expiration timestamp") # Trading parameters tick_size: Float | None = Field(default=None, description="Minimum price increment") lot_size: Float | None = Field(default=None, description="Minimum quantity increment") # Margin requirements (for leveraged products) initial_margin_rate: Float | None = Field(default=None, description="Initial margin requirement") maintenance_margin_rate: Float | None = Field(default=None, description="Maintenance margin requirement") # Additional metadata metadata: dict[str, Any] = Field(default_factory=dict, description="Exchange-specific metadata") class Asset(BaseModel): """ An asset holding (spot, margin, derivative position, etc.) """ model_config = {"extra": "forbid"} asset_id: str = Field(description="References AssetMetadata") quantity: Float = Field(description="Amount held (positive or negative for short positions)") available: Float = Field(description="Amount available for trading (not locked in orders)") locked: Float = Field(description="Amount locked in open orders") # For derivative positions entry_price: Float | None = Field(default=None, description="Average entry price") mark_price: Float | None = Field(default=None, description="Current mark price") liquidation_price: Float | None = Field(default=None, description="Estimated liquidation price") unrealized_pnl: Float | None = Field(default=None, description="Unrealized profit/loss") realized_pnl: Float | None = Field(default=None, description="Realized profit/loss") # Margin info margin_used: Float | None = Field(default=None, description="Margin allocated to this position") updated_at: Uint64 = Field(description="Last update timestamp") class Position(BaseModel): """ A trading position (spot, margin, perpetual, futures, etc.) Tracks both the asset holdings and associated metadata. """ model_config = {"extra": "forbid"} position_id: str = Field(description="Unique position identifier") symbol_id: str = Field(description="Trading symbol") asset: Asset = Field(description="Asset holding details") metadata: AssetMetadata = Field(description="Asset metadata") # Position-level info leverage: Float | None = Field(default=None, description="Current leverage") side: str | None = Field(default=None, description="LONG or SHORT (for derivatives)") updated_at: Uint64 = Field(description="Last update timestamp") class Balance(BaseModel): """Account balance for a single currency/asset""" model_config = {"extra": "forbid"} asset_id: str = Field(description="Asset identifier") total: Float = Field(description="Total balance") available: Float = Field(description="Available for trading") locked: Float = Field(description="Locked in orders/positions") # For margin accounts borrowed: Float = Field(default=0.0, description="Borrowed amount (margin)") interest: Float = Field(default=0.0, description="Accrued interest") updated_at: Uint64 = Field(description="Last update timestamp") class AccountState(BaseModel): """ Complete account state including balances, positions, and margin info. """ model_config = {"extra": "forbid"} account_id: str = Field(description="Account identifier") exchange: str = Field(description="Exchange identifier") balances: list[Balance] = Field(default_factory=list, description="All asset balances") positions: list[Position] = Field(default_factory=list, description="All open positions") # Margin account info total_equity: Float | None = Field(default=None, description="Total account equity") total_margin_used: Float | None = Field(default=None, description="Total margin in use") total_available_margin: Float | None = Field(default=None, description="Available margin") margin_level: Float | None = Field(default=None, description="Margin level (equity/margin_used)") # Risk metrics total_unrealized_pnl: Float | None = Field(default=None, description="Total unrealized P&L") total_realized_pnl: Float | None = Field(default=None, description="Total realized P&L") updated_at: Uint64 = Field(description="Last update timestamp") metadata: dict[str, Any] = Field(default_factory=dict, description="Exchange-specific data")