Files
ai/backend.old/src/exchange_kernel/models.py
2026-03-11 18:47:11 -04:00

195 lines
7.7 KiB
Python

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