Разработка системы мультибиржевой торговли из одного интерфейса

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1Все 1306 услуг
Разработка системы мультибиржевой торговли из одного интерфейса
Сложный
от 2 недель до 3 месяцев
Часто задаваемые вопросы

Направления блокчейн-разработки

Этапы блокчейн-разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1288
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    902
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1122
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    859

Разработка системы мультибиржевой торговли из одного интерфейса

Мультибиржевой торговый интерфейс позволяет трейдеру управлять позициями на нескольких биржах из единого окна: видеть агрегированный баланс, выставлять ордера на нужную биржу, видеть сводную позицию по активу. Это значительно упрощает работу трейдеров, которые используют несколько бирж для арбитража или диверсификации.

Архитектура: Exchange Abstraction Layer

Ключевой паттерн — единый интерфейс, абстрагирующий биржеспецифичный API:

from abc import ABC, abstractmethod
from decimal import Decimal

class ExchangeAdapter(ABC):
    @abstractmethod
    async def get_balance(self) -> dict[str, Decimal]:
        """Возвращает {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-специфичная реализация
        ...

Агрегация балансов

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

    async def get_aggregated_balance(self) -> dict[str, dict]:
        """Возвращает балансы по всем биржам с суммарным значением в USD"""
        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))

        # Агрегируем по активу
        aggregated: dict[str, dict] = {}
        for exchange, balances in balances_by_exchange.items():
            if isinstance(balances, Exception):
                continue  # биржа недоступна, пропускаем
            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

При выставлении ордера система может автоматически выбрать биржу с лучшими условиями:

class SmartOrderRouter:
    async def find_best_execution(
        self,
        symbol: str,
        side: str,
        quantity: Decimal,
    ) -> tuple[str, Decimal]:
        """Возвращает (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':
                    # Лучшая цена покупки = наименьший ask
                    prices[exchange_name] = book.best_ask
                else:
                    # Лучшая цена продажи = наибольший 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

Все ордера со всех бирж — в одном потоке:

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: унифицированный интерфейс

Во frontend показываем символ биржи рядом с каждым ордером/позицией:

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>
  );
};

Особенности и ограничения

Каждая биржа имеет свою систему минимальных размеров ордеров, precision для цены и количества, ограничения по типам ордеров. Унифицированный интерфейс должен это учитывать: при выставлении ордера на конкретную биржу — применять её правила к параметрам ордера.

CCXT — отличная библиотека для быстрого прототипа. Для production стоит писать кастомные адаптеры: CCXT не всегда идеально поддерживает edge cases конкретных бирж и имеет заметные накладные расходы.