This document explains how to add support for new exchanges to the modular trading bot.
The trading bot has been modularized to support multiple exchanges through a plugin-like architecture. Each exchange is implemented as a separate client that inherits from BaseExchangeClient.
exchanges/
├── __init__.py # Module initialization
├── base.py # Base exchange client interface
├── edgex.py # EdgeX exchange implementation
├── factory.py # Exchange factory for dynamic selection
└── your_exchange.py # Your new exchange implementation
Create a new file exchanges/your_exchange.py that implements the BaseExchangeClient interface:
from .base import BaseExchangeClient, OrderResult, OrderInfo
from typing import Dict, Any, List, Optional
class YourExchangeClient(BaseExchangeClient):
"""Your exchange client implementation."""
def __init__(self, config: Dict[str, Any]):
super().__init__(config)
# Initialize your exchange-specific client here
self.client = YourExchangeSDK(...)
def _validate_config(self) -> None:
"""Validate exchange-specific configuration."""
# Check for required API keys, endpoints, etc.
pass
async def connect(self) -> None:
"""Connect to the exchange (WebSocket, etc.)."""
# Establish connection to your exchange
pass
async def disconnect(self) -> None:
"""Disconnect from the exchange."""
# Clean up connections
pass
def get_exchange_name(self) -> str:
"""Get the exchange name."""
return "your_exchange"
def setup_order_update_handler(self, handler) -> None:
"""Setup order update handler for WebSocket."""
# Set up WebSocket or polling for order updates
pass
async def place_open_order(self, contract_id: str, quantity: float, direction: str) -> OrderResult:
"""Place an open order."""
# Implement order placement logic
pass
async def place_close_order(self, contract_id: str, quantity: float, price: float, side: str) -> OrderResult:
"""Place a close order."""
# Implement close order placement logic
pass
async def cancel_order(self, order_id: str) -> OrderResult:
"""Cancel an order."""
# Implement order cancellation logic
pass
async def get_order_info(self, order_id: str) -> Optional[OrderInfo]:
"""Get order information."""
# Implement order info retrieval
pass
async def get_active_orders(self, contract_id: str) -> List[OrderInfo]:
"""Get active orders for a contract."""
# Implement active orders retrieval
pass
async def get_account_positions(self) -> Dict[str, Any]:
"""Get account positions."""
# Implement positions retrieval
passAdd your exchange to the factory in exchanges/factory.py:
from .your_exchange import YourExchangeClient
class ExchangeFactory:
_registered_exchanges = {
'edgex': EdgeXClient,
'your_exchange': YourExchangeClient, # Add this line
}Add your exchange to exchanges/__init__.py:
from .your_exchange import YourExchangeClient
__all__ = ['BaseExchangeClient', 'EdgeXClient', 'YourExchangeClient', 'ExchangeFactory']Test your exchange client:
from exchanges import ExchangeFactory
# Test exchange creation
client = ExchangeFactory.create_exchange('your_exchange', {'api_key': 'test'})
print(f"Created {client.get_exchange_name()} client")All exchange clients must implement these methods from BaseExchangeClient:
_validate_config()- Validate exchange-specific configurationconnect()- Establish connection to exchangedisconnect()- Clean up connectionsget_exchange_name()- Return exchange name
place_open_order(contract_id, quantity, direction)- Place opening ordersplace_close_order(contract_id, quantity, price, side)- Place closing orderscancel_order(order_id)- Cancel ordersget_order_info(order_id)- Get order detailsget_active_orders(contract_id)- Get all active orders
get_account_positions()- Get account positionssetup_order_update_handler(handler)- Set up real-time order updates
@dataclass
class OrderResult:
success: bool
order_id: Optional[str] = None
side: Optional[str] = None
size: Optional[float] = None
price: Optional[float] = None
status: Optional[str] = None
error_message: Optional[str] = None@dataclass
class OrderInfo:
order_id: str
side: str
size: float
price: float
status: str
filled_size: float = 0.0
remaining_size: float = 0.0Once implemented, users can select your exchange:
python runbot.py --exchange your_exchange --contract-id YOUR_CONTRACT_ID- Error Handling: Always return appropriate
OrderResultobjects with error messages - Async/Await: All methods should be async for non-blocking operations
- Configuration: Use environment variables for API keys and endpoints
- Logging: Use the provided logger for consistent logging
- Testing: Test thoroughly with paper trading before live trading
- Documentation: Document any exchange-specific requirements
Here's a simplified example of how you might implement Binance Futures:
class BinanceFuturesClient(BaseExchangeClient):
def __init__(self, config: Dict[str, Any]):
super().__init__(config)
self.api_key = os.getenv('BINANCE_API_KEY')
self.secret_key = os.getenv('BINANCE_SECRET_KEY')
self.client = Client(self.api_key, self.secret_key)
def _validate_config(self) -> None:
if not self.api_key or not self.secret_key:
raise ValueError("BINANCE_API_KEY and BINANCE_SECRET_KEY required")
async def place_open_order(self, contract_id: str, quantity: float, direction: str) -> OrderResult:
try:
order = await self.client.futures_create_order(
symbol=contract_id,
side=direction.upper(),
type='LIMIT',
quantity=quantity,
timeInForce='GTC'
)
return OrderResult(success=True, order_id=order['orderId'])
except Exception as e:
return OrderResult(success=False, error_message=str(e))This modular approach makes it easy to add new exchanges while maintaining a consistent interface for the trading bot.