195 lines
7.7 KiB
Python
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")
|