Multi-exchange trading from single interface system

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Multi-exchange trading from single interface system
Complex
from 2 weeks to 3 months
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1217
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1046
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Development of Multi-Exchange Trading Interface

A multi-exchange trading interface allows a trader to manage positions on multiple exchanges from a single window: see aggregated balance, place orders on the right exchange, see a summary position per asset. This greatly simplifies work for traders who use multiple exchanges for arbitrage or diversification.

Architecture: Exchange Abstraction Layer

Key pattern — a unified interface that abstracts exchange-specific API:

from abc import ABC, abstractmethod
from decimal import Decimal

class ExchangeAdapter(ABC):
    @abstractmethod
    async def get_balance(self) -> dict[str, Decimal]:
        """Returns {asset: amount}"""

    @abstractmethod
    async def place_order(self, symbol: str, side: str, order_type: str,
                           quantity: Decimal, price: Decimal = None) -> Order:
        pass

    @abstractmethod
    async def cancel_order(self, order_id: str, symbol: str) -> bool:
        pass

    @abstractmethod
    async def get_open_orders(self, symbol: str = None) -> list[Order]:
        pass

    @abstractmethod
    async def subscribe_order_updates(self, callback) -> None:
        pass


class BinanceAdapter(ExchangeAdapter):
    def __init__(self, api_key: str, secret: str):
        self.client = BinanceClient(api_key, secret)

    async def place_order(self, symbol: str, side: str, order_type: str,
                           quantity: Decimal, price: Decimal = None) -> Order:
        binance_symbol = symbol.replace('/', '')  # BTC/USDT → BTCUSDT
        raw = await self.client.create_order(
            symbol=binance_symbol,
            side=side,
            type=order_type,
            quantity=str(quantity),
            price=str(price) if price else None,
        )
        return Order.from_binance(raw)


class BybitAdapter(ExchangeAdapter):
    async def place_order(self, symbol: str, ...):
        # Bybit-specific implementation
        ...

Balance Aggregation

class MultiExchangePortfolio:
    def __init__(self, adapters: dict[str, ExchangeAdapter]):
        self.adapters = adapters

    async def get_aggregated_balance(self) -> dict[str, dict]:
        """Returns balances across all exchanges with USD equivalent value"""
        tasks = {
            exchange: asyncio.create_task(adapter.get_balance())
            for exchange, adapter in self.adapters.items()
        }

        results = await asyncio.gather(*tasks.values(), return_exceptions=True)
        balances_by_exchange = dict(zip(tasks.keys(), results))

        # Aggregate by asset
        aggregated: dict[str, dict] = {}
        for exchange, balances in balances_by_exchange.items():
            if isinstance(balances, Exception):
                continue  # exchange unavailable, skip
            for asset, amount in balances.items():
                if asset not in aggregated:
                    aggregated[asset] = {"total": Decimal(0), "by_exchange": {}}
                aggregated[asset]["total"] += amount
                aggregated[asset]["by_exchange"][exchange] = amount

        return aggregated

Smart Order Routing

When placing an order, the system can automatically select the exchange with the best conditions:

class SmartOrderRouter:
    async def find_best_execution(
        self,
        symbol: str,
        side: str,
        quantity: Decimal,
    ) -> tuple[str, Decimal]:
        """Returns (exchange_name, best_price)"""
        prices = {}

        for exchange_name, adapter in self.adapters.items():
            try:
                book = await adapter.get_order_book(symbol, depth=5)
                if side == 'BUY':
                    # Best buy price = lowest ask
                    prices[exchange_name] = book.best_ask
                else:
                    # Best sell price = highest bid
                    prices[exchange_name] = book.best_bid
            except Exception:
                continue

        if not prices:
            raise ValueError("No exchanges available")

        if side == 'BUY':
            return min(prices.items(), key=lambda x: x[1])
        else:
            return max(prices.items(), key=lambda x: x[1])

Unified Order Feed

All orders from all exchanges in one stream:

class UnifiedOrderFeed:
    def __init__(self, adapters: dict[str, ExchangeAdapter]):
        self.order_queue = asyncio.Queue()

    async def start(self):
        tasks = [
            self.subscribe_exchange(exchange, adapter)
            for exchange, adapter in self.adapters.items()
        ]
        await asyncio.gather(*tasks)

    async def subscribe_exchange(self, exchange: str, adapter: ExchangeAdapter):
        async def callback(order: Order):
            order.exchange = exchange
            await self.order_queue.put(order)

        await adapter.subscribe_order_updates(callback)

UI: Unified Interface

In frontend show exchange symbol next to each order/position:

const UnifiedOrdersPanel = () => {
  const { orders } = useUnifiedOrders();

  return (
    <table>
      <thead>
        <tr>
          <th>Exchange</th>
          <th>Symbol</th>
          <th>Side</th>
          <th>Price</th>
          <th>Qty</th>
          <th>Status</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        {orders.map(order => (
          <tr key={`${order.exchange}:${order.id}`}>
            <td>
              <ExchangeBadge exchange={order.exchange} />
            </td>
            <td>{order.symbol}</td>
            <td className={order.side === 'BUY' ? 'text-green' : 'text-red'}>
              {order.side}
            </td>
            <td>{formatPrice(order.price)}</td>
            <td>{order.quantity}</td>
            <td>{order.status}</td>
            <td>
              <button onClick={() => cancelOrder(order.exchange, order.id)}>
                Cancel
              </button>
            </td>
          </tr>
        ))}
      </tbody>
    </table>
  );
};

Features and Limitations

Each exchange has its own system of minimum order sizes, precision for price and quantity, order type limitations. The unified interface must account for this: when placing an order on a specific exchange — apply its rules to order parameters.

CCXT is a great library for quick prototyping. For production, it's worth writing custom adapters: CCXT doesn't always perfectly support edge cases of specific exchanges and has notable overhead.