Разработка стакана ордеров (order book) для криптобирж

Отметим: когда клиент говорит «у нас latency на matching 200 мс» — мы сразу знаем: проблема в архитектуре order book. В нашей практике был случай: биржа теряла до 10% ордеров из-за блокировок на уровне БД. Решение — in-memory order book с минимальной синхронизацией. Мы разрабатываем высокопроизводит

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

Часто задаваемые вопросы

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

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

Отметим: когда клиент говорит «у нас latency на matching 200 мс» — мы сразу знаем: проблема в архитектуре order book. В нашей практике был случай: биржа теряла до 10% ордеров из-за блокировок на уровне БД. Решение — in-memory order book с минимальной синхронизацией. Мы разрабатываем высокопроизводительные order book под ключ для crypto-бирж. Наш опыт — 15+ проектов.

Order book — центральный компонент любой биржи. Это упорядоченный список заявок на покупку и продажу актива. Производительность order book напрямую определяет возможности всей торговой системы: от latency исполнения до максимального throughput. Поддерживаются лимитные и рыночные ордера. Средняя экономия на инфраструктурных затратах после внедрения in-memory решения достигает 40% при нагрузке 50 000+ ордеров в секунду.

Как устроен in-memory order book?

Order book живёт в оперативной памяти. Доступ к диску при каждом matching — неприемлемо по latency. Классическая структура: два отсортированных контейнера — bid side (покупки, по убыванию цены) и ask side (продажи, по возрастанию цены). На каждом ценовом уровне — очередь ордеров (FIFO для price-time priority).

type Order struct { ID string UserID int64 Side Side // Buy | Sell Type OrderType // Limit | Market Price decimal.Decimal Quantity decimal.Decimal FilledQty decimal.Decimal CreatedAt int64 // nanosecond timestamp } type PriceLevel struct { Price decimal.Decimal Orders []*Order // FIFO queue } type OrderBook struct { Bids *redblacktree.Tree // Price -> *PriceLevel, descending Asks *redblacktree.Tree // Price -> *PriceLevel, ascending Orders map[string]*Order // OrderID -> Order (для быстрой отмены) mu sync.RWMutex } 

Выбор tree-структуры:

  • Red-black tree: O(log n) для всех операций. Библиотека emirpasic/gods — хорошая Go реализация.
  • Skip list: конкурентный, но сложнее. Lock-free skip list даёт лучшую масштабируемость для многоядерных систем.
  • Sorted slice + binary search: O(n) insert, O(log n) search. Работает для небольших books (< 1000 уровней).

Почему отмена ордера должна быть O(1)?

Если отмена ордера требует поиска по всем уровням, latency растёт линейно. Мы используем hashmap Orders map[string]*Order — прямая индексация по ID. Это критично для high-frequency trading, где каждая микросекунда на счету.

Matching алгоритм: FIFO vs Pro-Rata

Price-Time Priority (FIFO) — стандарт для большинства бирж. FIFO до 2 раз быстрее Pro-Rata при высокой нагрузке, но Pro-Rata стимулирует крупные заявки. Мы выбираем алгоритм под ваши задачи.

func (ob *OrderBook) matchOrder(taker *Order) []Trade { var trades []Trade counterSide := ob.getCounterBook(taker.Side) for taker.RemainingQty().IsPositive() { bestLevel := ob.getBestLevel(counterSide) if bestLevel == nil { break } if !ob.priceCrosses(taker, bestLevel.Price) { break } for len(bestLevel.Orders) > 0 && taker.RemainingQty().IsPositive() { maker := bestLevel.Orders[0] fillQty := decimal.Min(taker.RemainingQty(), maker.RemainingQty()) trades = append(trades, Trade{ Price: bestLevel.Price, Quantity: fillQty, TakerOrderID: taker.ID, MakerOrderID: maker.ID, TakerSide: taker.Side, Timestamp: time.Now().UnixNano(), }) taker.FilledQty = taker.FilledQty.Add(fillQty) maker.FilledQty = maker.FilledQty.Add(fillQty) if maker.RemainingQty().IsZero() { bestLevel.Orders = bestLevel.Orders[1:] delete(ob.Orders, maker.ID) } } if len(bestLevel.Orders) == 0 { ob.removeLevel(counterSide, bestLevel.Price) } } return trades } 

Снэпшот и инкрементальные обновления

Клиент не получает весь order book при подключении — это может быть мегабайты. Архитектура:

  1. Клиент запрашивает снэпшот (top N уровней, например 50) через REST.
  2. Подписывается на WebSocket channel diff updates.
  3. Применяет diff к локальной копии.
Сценарий Действие
Новое подключение GET /api/v1/orderbook/snapshot?symbol=BTCUSDT&depth=50
Пропуск diff (sequence gap) Запросить новый снэпшот
Нормальный поток Применять diff с sequence+1
type OrderBookDiff = { sequence: number; bids: [string, string][]; asks: [string, string][]; }; class OrderBookClient { private bids = new Map<string, string>(); private asks = new Map<string, string>(); private lastSeq = 0; applyDiff(diff: OrderBookDiff) { if (diff.sequence <= this.lastSeq) return; if (diff.sequence !== this.lastSeq + 1) { this.requestSnapshot(); return; } diff.bids.forEach(([p, s]) => s === '0' ? this.bids.delete(p) : this.bids.set(p, s)); diff.asks.forEach(([p, s]) => s === '0' ? this.asks.delete(p) : this.asks.set(p, s)); this.lastSeq = diff.sequence; } } 

Визуализация: группировка по тикам и depth chart

Реальный order book может иметь тысячи уровней. Для отображения — группировка по «тику» (минимальный шаг цены). Пользователь переключает тик (0.01, 0.1, 1 для BTC/USDT), и мы агрегируем объёмы. Depth chart показывает относительную глубину каждого уровня — зелёный для bids, красный для asks.

Типичные проблемы и их решение - **Race conditions при отмене и исполнении**: используем RWMutex, но для высокой конкурентности — lock-free структуры. - **Пропуск diff обновлений**: клиент хранит sequence, при разрыве запрашивает полный снэпшот. - **Слишком много уровней в ответе**: ограничиваем depth (top 50) и даём группировку.

Что входит в разработку order book

  • Архитектура и проектирование: выбор алгоритма matching, схемы репликации.
  • Реализация in-memory engine на Go с latency < 100 μs.
  • REST API и WebSocket feed со снэпшотами и diff updates.
  • Frontend-компоненты на React с grouping и depth chart.
  • Интеграция с PostgreSQL для персистентности ордеров.
  • Нагрузочное тестирование (100k+ ордеров/сек).
  • Документация: OpenAPI, описание протокола, инструкция по развёртыванию.
  • Обучение команды заказчика.
  • Гарантия и поддержка: 3 месяца после деплоя.

Как мы разрабатываем order book под ключ

  1. Анализ требований и архитектура.
  2. Реализация in-memory matching engine.
  3. REST API + WebSocket feed.
  4. Frontend-визуализация.
  5. Интеграция с внешними системами.
  6. Нагрузочное тестирование и оптимизация.
  7. Документация и передача.

Производительность

Для биржи с 10–20 парами и умеренным объёмом: один Go-процесс обрабатывает > 50 000 ордеров/сек. При необходимости — шардинг по парам и горизонтальное масштабирование API. Снижение затрат на инфраструктуру за счёт in-memory подхода составляет до 30-40% при высокой нагрузке.

Метрика Значение Условия
Matching latency < 100 μs In-memory, single core
Add order throughput 100k+ ops/sec Go, Red-Black tree
Cancel order O(1) Hash map lookup
Snapshot generation < 1 ms Top 50 levels
WS diff broadcast < 1 ms After each trade

Свяжитесь с нами для оценки вашего проекта. Закажите разработку order book под ключ — получите консультацию инженера с опытом 10+ лет в blockchain. Экономия средств на инфраструктуре и повышение производительности торговой площадки — реальные результаты наших проектов.