# Adding New Exchange Adapters This guide explains how to add support for new cryptocurrency exchanges. ## Exchange Adapter Architecture All exchange adapters inherit from `BaseExchange` and implement a standardized interface. This allows the trading engine to work with any exchange through a common API. ## Implementation Steps ### 1. Create Exchange Module Create a new file in `src/exchanges/`: ```python # src/exchanges/your_exchange.py from src.exchanges.base import BaseExchange from src.exchanges.factory import ExchangeFactory import ccxt.pro as ccxt import logging logger = logging.getLogger(__name__) class YourExchangeAdapter(BaseExchange): """Adapter for Your Exchange.""" def __init__(self, name: str, api_key: str, secret_key: str, password: str = None): super().__init__(name, api_key, secret_key, password) self.exchange = ccxt.yourexchange({ 'apiKey': self.api_key, 'secret': self.secret_key, 'enableRateLimit': True, }) async def connect(self): """Establish connection to exchange.""" await self.exchange.load_markets() self.is_connected = True logger.info(f"Connected to {self.name}") # Implement all required methods from BaseExchange # ... ``` ### 2. Implement Required Methods Implement all abstract methods from `BaseExchange`: - `connect()` - Establish connection - `disconnect()` - Close connection - `fetch_balance()` - Get account balance - `place_order()` - Place order - `cancel_order()` - Cancel order - `fetch_order_status()` - Get order status - `fetch_ohlcv()` - Get historical data - `subscribe_ohlcv()` - Real-time OHLCV - `subscribe_trades()` - Real-time trades - `subscribe_order_book()` - Real-time order book - `fetch_open_orders()` - Get open orders - `fetch_positions()` - Get positions (futures) - `fetch_markets()` - Get available markets ### 3. Register Exchange Register the exchange in `src/exchanges/__init__.py`: ```python from .your_exchange import YourExchangeAdapter from .factory import ExchangeFactory ExchangeFactory.register_exchange("your_exchange", YourExchangeAdapter) ``` ### 4. Handle Exchange-Specific Features Some exchanges have unique features: - **Authentication**: Some exchanges use different auth methods - **Rate Limits**: Respect exchange rate limits - **WebSocket**: Implement exchange-specific WebSocket protocol - **Order Types**: Support exchange-specific order types ### 5. Write Tests Create tests in `tests/unit/exchanges/test_your_exchange.py`: ```python import pytest from unittest.mock import Mock, patch from src.exchanges.your_exchange import YourExchangeAdapter class TestYourExchangeAdapter: """Tests for Your Exchange adapter.""" @pytest.fixture def adapter(self): return YourExchangeAdapter( name="test", api_key="test_key", secret_key="test_secret" ) @pytest.mark.asyncio async def test_connect(self, adapter): """Test connection.""" with patch.object(adapter.exchange, 'load_markets'): await adapter.connect() assert adapter.is_connected # Add more tests... ``` ## Using CCXT Most exchanges can use the `ccxt` library: ```python import ccxt.pro as ccxt exchange = ccxt.pro.yourexchange({ 'apiKey': api_key, 'secret': secret_key, 'enableRateLimit': True, }) # Use ccxt methods balance = await exchange.fetch_balance() order = await exchange.create_order(...) ``` ## Exchange-Specific Considerations ### Authentication Some exchanges require additional authentication: ```python # Example: Exchange requiring passphrase self.exchange = ccxt.coinbase({ 'apiKey': api_key, 'secret': secret_key, 'password': passphrase, # Coinbase requires this }) ``` ### Rate Limits Always enable rate limiting: ```python self.exchange = ccxt.yourexchange({ 'enableRateLimit': True, # Important! }) ``` ### WebSocket Support For real-time data, implement WebSocket connections: ```python async def subscribe_ohlcv(self, symbol: str, timeframe: str, callback): """Subscribe to OHLCV updates.""" # Exchange-specific WebSocket implementation await self.exchange.watch_ohlcv(symbol, timeframe, callback) ``` ## Testing Your Adapter ### Unit Tests Test all methods with mocked exchange responses: ```python @pytest.mark.asyncio async def test_fetch_balance(self, adapter): """Test balance fetching.""" mock_balance = {'BTC': {'free': 1.0, 'used': 0.0, 'total': 1.0}} with patch.object(adapter.exchange, 'fetch_balance', return_value=mock_balance): balance = await adapter.fetch_balance() assert 'BTC' in balance ``` ### Integration Tests Test with real exchange (use testnet/sandbox if available): ```python @pytest.mark.integration async def test_real_connection(self): """Test real connection (requires API keys).""" adapter = YourExchangeAdapter(...) await adapter.connect() assert adapter.is_connected ``` ## Documentation Document your exchange adapter: 1. Add docstrings to all methods 2. Document exchange-specific features 3. Add usage examples 4. Update API documentation ## Best Practices 1. **Error Handling**: Handle exchange-specific errors 2. **Rate Limiting**: Always respect rate limits 3. **Retry Logic**: Implement retry for transient failures 4. **Logging**: Log important operations 5. **Testing**: Test thoroughly before submitting ## Example: Complete Exchange Adapter See `src/exchanges/coinbase.py` for a complete example implementation.