backend redesign
This commit is contained in:
361
backend.old/src/exchange_kernel/base.py
Normal file
361
backend.old/src/exchange_kernel/base.py
Normal file
@@ -0,0 +1,361 @@
|
||||
"""
|
||||
Base interface for Exchange Kernels.
|
||||
|
||||
Defines the abstract API that all exchange kernel implementations must support.
|
||||
Each exchange (or exchange type) will have its own kernel implementation.
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Callable, Any
|
||||
|
||||
from .models import (
|
||||
OrderIntent,
|
||||
OrderState,
|
||||
Position,
|
||||
AccountState,
|
||||
AssetMetadata,
|
||||
)
|
||||
from .events import BaseEvent
|
||||
from ..schema.order_spec import (
|
||||
StandardOrder,
|
||||
StandardOrderGroup,
|
||||
SymbolMetadata,
|
||||
)
|
||||
|
||||
|
||||
class ExchangeKernel(ABC):
|
||||
"""
|
||||
Abstract base class for exchange kernels.
|
||||
|
||||
An exchange kernel manages the lifecycle of orders on a specific exchange,
|
||||
maintaining both desired state (intents from strategy kernel) and actual
|
||||
state (current orders on exchange), and continuously reconciling them.
|
||||
|
||||
Think of it as a Kubernetes-style controller for trading orders.
|
||||
"""
|
||||
|
||||
def __init__(self, exchange_id: str):
|
||||
"""
|
||||
Initialize the exchange kernel.
|
||||
|
||||
Args:
|
||||
exchange_id: Unique identifier for this exchange instance
|
||||
"""
|
||||
self.exchange_id = exchange_id
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Command API - Strategy kernel sends intents
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@abstractmethod
|
||||
async def place_order(self, order: StandardOrder, metadata: dict[str, Any] | None = None) -> str:
|
||||
"""
|
||||
Place a single order on the exchange.
|
||||
|
||||
This creates an OrderIntent and begins the reconciliation process to
|
||||
get the order onto the exchange.
|
||||
|
||||
Args:
|
||||
order: The order specification
|
||||
metadata: Optional strategy-specific metadata
|
||||
|
||||
Returns:
|
||||
intent_id: Unique identifier for this order intent
|
||||
|
||||
Raises:
|
||||
ValidationError: If order violates market constraints
|
||||
ExchangeError: If exchange rejects the order
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def place_order_group(
|
||||
self,
|
||||
group: StandardOrderGroup,
|
||||
metadata: dict[str, Any] | None = None
|
||||
) -> list[str]:
|
||||
"""
|
||||
Place a group of orders with OCO (One-Cancels-Other) relationship.
|
||||
|
||||
Args:
|
||||
group: Group of orders with OCO mode
|
||||
metadata: Optional strategy-specific metadata
|
||||
|
||||
Returns:
|
||||
intent_ids: List of intent IDs for each order in the group
|
||||
|
||||
Raises:
|
||||
ValidationError: If any order violates market constraints
|
||||
ExchangeError: If exchange rejects the group
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def cancel_order(self, intent_id: str) -> None:
|
||||
"""
|
||||
Cancel an order by intent ID.
|
||||
|
||||
Updates the intent to indicate cancellation is desired, and the
|
||||
reconciliation loop will handle the actual exchange cancellation.
|
||||
|
||||
Args:
|
||||
intent_id: Intent ID of the order to cancel
|
||||
|
||||
Raises:
|
||||
NotFoundError: If intent_id doesn't exist
|
||||
ExchangeError: If exchange rejects cancellation
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def modify_order(
|
||||
self,
|
||||
intent_id: str,
|
||||
new_order: StandardOrder,
|
||||
) -> None:
|
||||
"""
|
||||
Modify an existing order.
|
||||
|
||||
Updates the order intent, and the reconciliation loop will update
|
||||
the exchange order (via modify API if available, or cancel+replace).
|
||||
|
||||
Args:
|
||||
intent_id: Intent ID of the order to modify
|
||||
new_order: New order specification
|
||||
|
||||
Raises:
|
||||
NotFoundError: If intent_id doesn't exist
|
||||
ValidationError: If new order violates market constraints
|
||||
ExchangeError: If exchange rejects modification
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def cancel_all_orders(self, symbol_id: str | None = None) -> int:
|
||||
"""
|
||||
Cancel all orders, optionally filtered by symbol.
|
||||
|
||||
Args:
|
||||
symbol_id: If provided, only cancel orders for this symbol
|
||||
|
||||
Returns:
|
||||
count: Number of orders canceled
|
||||
"""
|
||||
pass
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Query API - Read desired and actual state
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@abstractmethod
|
||||
async def get_order_intent(self, intent_id: str) -> OrderIntent:
|
||||
"""
|
||||
Get the desired order state (what strategy kernel wants).
|
||||
|
||||
Args:
|
||||
intent_id: Intent ID to query
|
||||
|
||||
Returns:
|
||||
The order intent
|
||||
|
||||
Raises:
|
||||
NotFoundError: If intent_id doesn't exist
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_order_state(self, intent_id: str) -> OrderState:
|
||||
"""
|
||||
Get the actual order state (what's currently on exchange).
|
||||
|
||||
Args:
|
||||
intent_id: Intent ID to query
|
||||
|
||||
Returns:
|
||||
The current order state
|
||||
|
||||
Raises:
|
||||
NotFoundError: If intent_id doesn't exist
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_all_intents(self, symbol_id: str | None = None) -> list[OrderIntent]:
|
||||
"""
|
||||
Get all order intents, optionally filtered by symbol.
|
||||
|
||||
Args:
|
||||
symbol_id: If provided, only return intents for this symbol
|
||||
|
||||
Returns:
|
||||
List of order intents
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_all_orders(self, symbol_id: str | None = None) -> list[OrderState]:
|
||||
"""
|
||||
Get all actual order states, optionally filtered by symbol.
|
||||
|
||||
Args:
|
||||
symbol_id: If provided, only return orders for this symbol
|
||||
|
||||
Returns:
|
||||
List of order states
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_positions(self, symbol_id: str | None = None) -> list[Position]:
|
||||
"""
|
||||
Get current positions, optionally filtered by symbol.
|
||||
|
||||
Args:
|
||||
symbol_id: If provided, only return positions for this symbol
|
||||
|
||||
Returns:
|
||||
List of positions
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_account_state(self) -> AccountState:
|
||||
"""
|
||||
Get current account state (balances, margin, etc.).
|
||||
|
||||
Returns:
|
||||
Current account state
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_symbol_metadata(self, symbol_id: str) -> SymbolMetadata:
|
||||
"""
|
||||
Get metadata for a symbol (constraints, capabilities, etc.).
|
||||
|
||||
Args:
|
||||
symbol_id: Symbol to query
|
||||
|
||||
Returns:
|
||||
Symbol metadata
|
||||
|
||||
Raises:
|
||||
NotFoundError: If symbol doesn't exist on this exchange
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_asset_metadata(self, asset_id: str) -> AssetMetadata:
|
||||
"""
|
||||
Get metadata for an asset.
|
||||
|
||||
Args:
|
||||
asset_id: Asset to query
|
||||
|
||||
Returns:
|
||||
Asset metadata
|
||||
|
||||
Raises:
|
||||
NotFoundError: If asset doesn't exist
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def list_symbols(self) -> list[str]:
|
||||
"""
|
||||
List all available symbols on this exchange.
|
||||
|
||||
Returns:
|
||||
List of symbol IDs
|
||||
"""
|
||||
pass
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Event Subscription API
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@abstractmethod
|
||||
def subscribe_events(
|
||||
self,
|
||||
callback: Callable[[BaseEvent], None],
|
||||
event_filter: dict[str, Any] | None = None,
|
||||
) -> str:
|
||||
"""
|
||||
Subscribe to events from this exchange kernel.
|
||||
|
||||
Args:
|
||||
callback: Function to call when events occur
|
||||
event_filter: Optional filter criteria (event_type, symbol_id, etc.)
|
||||
|
||||
Returns:
|
||||
subscription_id: Unique ID for this subscription (for unsubscribe)
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def unsubscribe_events(self, subscription_id: str) -> None:
|
||||
"""
|
||||
Unsubscribe from events.
|
||||
|
||||
Args:
|
||||
subscription_id: Subscription ID returned from subscribe_events
|
||||
"""
|
||||
pass
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Lifecycle Management
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@abstractmethod
|
||||
async def start(self) -> None:
|
||||
"""
|
||||
Start the exchange kernel.
|
||||
|
||||
Initializes connections, starts reconciliation loops, etc.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def stop(self) -> None:
|
||||
"""
|
||||
Stop the exchange kernel.
|
||||
|
||||
Closes connections, stops reconciliation loops, etc.
|
||||
Does NOT cancel open orders - call cancel_all_orders() first if desired.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def health_check(self) -> dict[str, Any]:
|
||||
"""
|
||||
Check health status of the exchange kernel.
|
||||
|
||||
Returns:
|
||||
Health status dict with connection state, latency, error counts, etc.
|
||||
"""
|
||||
pass
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Reconciliation Control (advanced)
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@abstractmethod
|
||||
async def force_reconciliation(self, intent_id: str | None = None) -> None:
|
||||
"""
|
||||
Force immediate reconciliation.
|
||||
|
||||
Args:
|
||||
intent_id: If provided, only reconcile this specific intent.
|
||||
If None, reconcile all intents.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_reconciliation_metrics(self) -> dict[str, Any]:
|
||||
"""
|
||||
Get metrics about the reconciliation process.
|
||||
|
||||
Returns:
|
||||
Metrics dict with reconciliation lag, error rates, retry counts, etc.
|
||||
"""
|
||||
pass
|
||||
Reference in New Issue
Block a user