Розробка системи ордерів (limit, market, stop)
Система ордерів — сердце будь-якої біржи. Саме тут сконцентрована вся торгова логіка, й саме тут вартість помилки максимальна: баг у matching engine може за секунди обнулити ліквідність або створити несправедливі виконання. Розберемо архітектуру від моделі даних до matching алгоритму.
Типи ордерів і їхня семантика
Limit order
Користувач вказує ціну й обсяг. Ордер виконується лише якщо ринок досягне вказаної ціни або краще.
- Buy limit: виконується по ціні ≤ вказаної
- Sell limit: виконується по ціні ≥ вказаної
- Може бути частично виконаний
- Невиконана частина залишається в order book
Додаткові модифікатори: GTC (Good Till Cancelled), GTD (Good Till Date), IOC (Immediate Or Cancel), FOK (Fill Or Kill), Post-Only.
Market order
Виконується негайно по найкращій доступній ціні. Гарантує виконання, не ціну. На неліквідних ринках може дати значне slippage.
Безпечна реалізація: лімір slippage. Якщо виконання вимагає проходження через стакан більше ніж на X%, ордер відхиляється.
Stop order
Триггерний ордер. Активується коли ринкова ціна досягає stop price. Після активації стає market або limit ордером.
- Stop-Market: при досягненні stop price створюється market ордер
- Stop-Limit: при досягненні stop price створюється limit ордер з вказаною ціною
- Trailing Stop: stop price слідує за ринком на задану відстань
Архітектура matching engine
Структура даних order book
Класична реалізація — два sorted map (bid side і ask side) з ціною як ключем. На кожному ціновому рівні — черга ордерів (FIFO для price-time priority).
Вибір структури даних критичний для продуктивності:
-
Red-Black Tree (Go
btree, JavaTreeMap): O(log n) для insert/delete - Skip List: конкурентний без глобального локу
- Array + binary search: швидше для читання на малих books
Алгоритм matching
Price-time priority (FIFO matching) — стандарт для більшості бирж.
Модель даних
Критичний момент: matching engine працює в пам'яті, БД використовується лише для персистентності. При старті сервер завантажує всі open ордери в пам'ять.
Stop ордери й триггерний механізм
Stop ордери зберігаються в окремій структурі — sorted по stop price. При кожній сделці matching engine публікує останню ціну.
Trailing stop — особливий случай. При русі ціни на користь користувача stop price пересчитується.
Контроль балансу й atomicity
Перед розміщенням ордера потрібно зарезервувати кошти. При скасуванні — звільнення резерву. При fill — перемищення резерву в реальний баланс контрагента.
Atomicity через БД транзакції, але matching engine не може ходити в БД на кожен матч. Рішення: в-пам'яті баланс з асинхронною синхронізацією в БД.
Decimal точність й floating point
Ніколи не використовувати float64 для фінансових розрахунків. Для фінансів використовуйте:
- Go:
shopspring/decimal - Python:
decimal.Decimal - Java:
BigDecimal - JavaScript:
decimal.jsабоbignumber.js
Усі зберігаємі значення в БД — NUMERIC(36,18) або рядки.
Продуктивність й масштабування
Один matching engine на Go обробляє 50,000–100,000 ордерів/сек на сучасному залізі при latency <1мс. Для більшості CEX цього достатньо.
При необхідності масштабування — шардинг по trading pair.
| Компонент | Технологія | Latency |
|---|---|---|
| In-memory order book | Go btree | <100 мкс |
| Stop orders processor | Go goroutine | <1 мс |
| Balance check | In-memory map | <10 мкс |
| DB persistence | PostgreSQL async | 5–20 мс |
| WebSocket broadcast | Go channels | <1 мс |
Тестування
Matching engine покривається unit-тестами на граничні случаї. Property-based testing (fuzzing) — генеруються случайні послідовності ордерів.
Таймлайн розробки
- MVP (limit + market, без stop, без time-in-force): 3–4 тижні
- Повна система з stop ордерами, всіма TIF модифікаторами, trailing stop: 8–12 тижнів
- Production-ready з аудитом, нагрузовими тестами, мониторингом: +4–6 тижнів
Вартість залежить від вимог до throughput та наявності готових компонентів (баланс, комісії, WebSocket).







