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

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску 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]:
        """Повертає балансу за всіма біржами з еквівалентом у доларах США"""
        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])

Єдина стрічка ордерів

Усі ордери з усіх бірж — в одній стрічці:

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

Особливості та обмеження

Кожна біржа має свою систему мінімальних розмірів ордерів, точності для ціни та кількості, обмежень за типами ордерів. Єдиний інтерфейс повинен це враховувати: при виставленні ордера на конкретну біржу — застосовуємо її правила до параметрів ордера.

CCXT — відмінна бібліотека для швидкого прототипування. Для виробництва варто писати користувацькі адаптери: CCXT не завжди ідеально підтримує граничні випадки конкретних бірж і має помітні накладні витрати.