Зауважимо: коли криптобіржа вирішує вийти на інституційний ринок, перше питання клієнтів — наявність FIX API. Без нього prime brokers та HFT-фірми не підключаться: їхні роботи не вміють працювати з REST. FIX протокол — стандарт для низьколатентної торгівлі, що використовується на традиційних біржах з кінця XX століття. Ми розробляємо FIX API під ключ, забезпечуючи сумісність з QuickFIX, високу пропускну здатність (до 10 000 повідомлень/сек) та надійну сесійну модель з автоматичним відновленням. Наш досвід включає реалізацію FIX серверів для бірж з добовою торгівлею понад $100 млн. Для такої біржі перехід на FIX API може заощадити до $200 000 на рік на транзакційних витратах. У цій статті розберемо архітектуру FIX сервера, типові проблеми інтеграції та етапи робіт. Замовте розробку FIX API — зв'яжіться з нами для консультації.
FIX API: чому розробка критична для криптобіржі
FIX — текстовий протокол поверх TCP. Повідомлення — набір полів тег=значення, розділених SOH (0x01): 8=FIX.4.4 | 9=178 | 35=D | 49=CLIENT1 | 56=EXCHANGE | 34=123 | 52=20241201-14:30:00.000 | 11=ORDER-001 | 55=BTC/USD | 54=1 | 38=0.1 | 40=2 | 44=42000 | 59=1 | 10=087. Ключові теги: 35=D (New Order Single), 55 — інструмент, 54 — сторона, 38 — кількість, 40 — тип ордера, 44 — ціна, 59 — Time in Force.
FIX переважніший за REST для інституціоналів з кількох причин. Стандартний протокол — їхні системи вже вміють з ним працювати. Низька latency: мікросекундні затримки проти мілісекундних у REST — FIX швидше в 10–50 разів. Надійна сесійна модель з автоматичним відновленням після розривів та sequencing повідомлень.
Які проблеми вирішує FIX API при інтеграції?
Підтримка множини одночасних сесій
Кожен клієнт підключається через окрему FIX-сесію з унікальними CompID. Сервер повинен коректно обробляти тисячі сесій, не втрачаючи порядок повідомлень. Sequencing (MsgSeqNum) гарантує цілісність: при розриві клієнт запитує ResendRequest, і сервер повторює пропущені повідомлення. Наші тести показують стабільну роботу при 2000+ одночасних сесій з навантаженням 5000 ордерів/сек.
Відновлення після розриву з'єднання
FIX-сесія підтримує автоматичне перепідключення з відновленням послідовності. HeartBtInt (heartbeat) та ReconnectInterval налаштовуються у конфігу. Якщо сесія втрачена, сервер надішле SequenceReset для синхронізації. Ми тестуємо сценарії розриву на рівні 1000 одночасних сесій, гарантуючи нульову втрату даних.
Аутентифікація без вбудованих засобів
FIX 4.4 не має вбудованої аутентифікації. Ми використовуємо комбінацію: IP whitelist + TLS + кастомне поле 96 (RawData) для API-ключа з підписом. Приклад валідації у FromAdmin.
Як ми реалізуємо FIX сервер?
QuickFIX/Go — основна реалізація
QuickFIX — reference implementation FIX engine з портами для Go, Java, C++, Python. Go-версія (quickfixgo) — чудова база для production-біржі.
import (
"github.com/quickfixgo/quickfix"
"github.com/quickfixgo/quickfix/field"
"github.com/quickfixgo/quickfix/fix44"
"github.com/quickfixgo/quickfix/fix44/newordersingle"
)
type FIXApplication struct {
orderEngine *OrderEngine
sessionManager *SessionManager
}
func (app *FIXApplication) OnCreate(sessionID quickfix.SessionID) {
log.Info("FIX session created", "sessionID", sessionID)
}
func (app *FIXApplication) OnLogon(sessionID quickfix.SessionID) {
log.Info("FIX client logged on", "sessionID", sessionID)
app.sessionManager.SetOnline(sessionID)
}
func (app *FIXApplication) OnLogout(sessionID quickfix.SessionID) {
log.Info("FIX client logged out", "sessionID", sessionID)
app.sessionManager.SetOffline(sessionID)
}
func (app *FIXApplication) FromApp(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
msgType, err := msg.Header.GetString(field.NewMsgType())
if err != nil {
return err
}
switch msgType {
case "D": // New Order Single
return app.handleNewOrder(msg, sessionID)
case "F": // Order Cancel Request
return app.handleCancelOrder(msg, sessionID)
case "G": // Order Cancel/Replace Request (amend)
return app.handleAmendOrder(msg, sessionID)
case "H": // Order Status Request
return app.handleStatusRequest(msg, sessionID)
}
return quickfix.NewMessageRejectError("Unknown message type", 35, nil)
}
Обробка New Order Single
func (app *FIXApplication) handleNewOrder(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
nos := newordersingle.New(
field.NewClOrdID(""),
field.NewSide(0),
field.NewTransactTime(time.Now()),
field.NewOrdType(0),
)
if err := quickfix.Unmarshal(msg, &nos); err != nil {
return err
}
clOrdID, _ := nos.GetClOrdID()
symbol, _ := nos.GetSymbol()
sideInt, _ := nos.GetSide()
ordType, _ := nos.GetOrdType()
qty, _ := nos.GetOrderQty()
price, _ := nos.GetPrice()
tif, _ := nos.GetTimeInForce()
order := Order{
ClientOrderID: string(clOrdID),
Pair: normalizePair(string(symbol)),
Side: fixSideToInternal(sideInt),
Type: fixOrdTypeToInternal(ordType),
Quantity: decimal.NewFromFloat(float64(qty)),
Price: decimal.NewFromFloat(float64(price)),
TimeInForce: fixTIFToInternal(tif),
}
app.sendExecReport(sessionID, order, ExecTypeNew, OrdStatusPendingNew)
trades, err := app.orderEngine.PlaceOrder(order)
if err != nil {
app.sendExecReport(sessionID, order, ExecTypeRejected, OrdStatusRejected)
return nil
}
for _, trade := range trades {
app.sendFillReport(sessionID, order, trade)
}
if order.RemainingQty().IsPositive() {
status := OrdStatusNew
if len(trades) > 0 {
status = OrdStatusPartiallyFilled
}
app.sendExecReport(sessionID, order, ExecTypeNew, status)
}
return nil
}
Відправка Execution Report
func (app *FIXApplication) sendExecReport(sessionID quickfix.SessionID, order Order, execType ExecType, ordStatus OrdStatus) {
report := fix44executionreport.New(
field.NewOrderID(order.ID),
field.NewExecID(generateExecID()),
field.NewExecType(fix44.ExecType(execType)),
field.NewOrdStatus(fix44.OrdStatus(ordStatus)),
field.NewSymbol(denormalizePair(order.Pair)),
field.NewSide(fix44.Side(internalSideToFIX(order.Side))),
field.NewLeavesQty(order.RemainingQty().InexactFloat64(), 8),
field.NewCumQty(order.FilledQty.InexactFloat64(), 8),
field.NewAvgPx(order.AvgPrice().InexactFloat64(), 8),
)
report.SetClOrdID(order.ClientOrderID)
report.SetOrderQty(order.Quantity.InexactFloat64(), 8)
report.SetTransactTime(time.Now())
quickfix.SendToTarget(report.ToMessage(), sessionID)
}
Сесійна модель та безпека
FIX-сесія підтримує sequencing: кожне повідомлення має MsgSeqNum (34). При розриві з'єднання клієнт відновлює сесію з останнім відомим SeqNum. Сервер може надіслати ResendRequest (2) або SequenceReset (4).
Приклад конфігурації FIX-сесії
func createFIXSettings() *quickfix.Settings {
settings := quickfix.NewSettings()
globalSection := quickfix.NewSessionSettings()
globalSection.Set("FileStorePath", "./fix-sessions")
globalSection.Set("FileLogPath", "./fix-logs")
settings.GlobalSettings().SetGlobalSection(globalSection)
sessionSection := quickfix.NewSessionSettings()
sessionSection.Set(quickfix.BeginString, "FIX.4.4")
sessionSection.Set(quickfix.SenderCompID, "EXCHANGE")
sessionSection.Set(quickfix.TargetCompID, "CLIENT1")
sessionSection.Set("HeartBtInt", "30")
sessionSection.Set("ReconnectInterval", "5")
sessionSection.Set("StartTime", "00:00:00")
sessionSection.Set("EndTime", "00:00:00")
return settings
}
FIX 4.4 не має вбудованої аутентифікації. Стандартні підходи:
- IP whitelist: тільки дозволені IP підключаються до FIX-порту.
- TLS: шифрування з'єднання (FIX over SSL).
- Logon з password: поле 96 (RawData) або кастомний тег для API-ключа з підписом.
func (app *FIXApplication) FromAdmin(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
msgType, _ := msg.Header.GetString(field.NewMsgType())
if msgType == "A" { // Logon
apiKey, _ := msg.Body.GetString(9001)
signature, _ := msg.Body.GetString(9002)
timestamp, _ := msg.Body.GetString(9003)
if !app.auth.Verify(apiKey, signature, timestamp) {
return quickfix.NewMessageRejectError("Authentication failed", 58, nil)
}
app.sessionManager.SetAPIKey(sessionID, apiKey)
}
return nil
}
Безпека FIX з'єднання: три рівні захисту
Ми гарантуємо захист на трьох рівнях: транспортному (TLS), мережевому (IP whitelist) та прикладному (аутентифікація з підписом). Додатково реалізуємо аудит сесій та Drop Copy для compliance. Це стандарт для бірж, що працюють з інституційними клієнтами.
Обсяг робіт при розробці FIX API
- Розробка сервера FIX 4.4 на Go (QuickFIX)
- Реалізація типових повідомлень: New Order, Cancel, Amend, Execution Reports
- Market Data feed (підписка на стакан та угоди)
- Безпека: TLS, IP whitelist, аутентифікація за ключами
- Drop Copy для compliance
- Документація та тестування (навантажувальне, регресійне)
- Навчання команди та підтримка на етапі впровадження
Процес роботи та терміни
- Аналітика: вивчаємо ваші вимоги та існуючу архітектуру.
- Проектування: розробляємо схему сесій, черговість повідомлень та політики безпеки.
- Реалізація: пишемо код — від парсингу повідомлень до взаємодії з matching engine.
- Тестування: навантажувальне (1000+ ордерів/сек) та регресійне.
- Деплой: розгортання, моніторинг та навчання вашої команди.
Орієнтовні терміни: від 4 тижнів для базової інтеграції до 2–3 місяців для повноцінного production-ready рішення.
| Характеристика | FIX | REST |
|---|---|---|
| Затримка | Мікросекунди (<100 мкс) | Мілісекунди |
| Надійність | Вбудоване відновлення | Складніше |
| Аутентифікація | Зовнішня (TLS + ключі) | API-ключі |
| Стандартизація | Єдиний протокол | Різні реалізації |
| Етап | Тривалість |
|---|---|
| Аналітика та проектування | 1–2 тижні |
| Розробка базового сервера | 3–4 тижні |
| Market Data та Drop Copy | 2–3 тижні |
| Тестування (навантажувальне, регресійне) | 2 тижні |
| Деплой та навчання | 1 тиждень |
Типові помилки при розробці FIX API
Некоректний sequencing: якщо MsgSeqNum збивається, сесія переходить у broken state. Використовуйте файлове або БД-сховище для SeqNum, а не in-memory. Ігнорування HeartBtInt: клієнти відключаються при відсутності heartbeats. Налаштуйте HeartBtInt на 30 секунд та обробляйте MissedHeartBeat. Відсутність ResendRequest: при розриві клієнт повинен запросити повтор. Переконайтеся, що сервер зберігає всі повідомлення для повторної відправки.
Отримайте консультацію з FIX API для вашої біржі — зв'яжіться з нами для оцінки обсягу робіт. Запитуйте тестову інтеграцію: ми надамо доступ до інстансу FIX-сервера для ваших розробників.
Специфікація FIX протоколу: FIX protocol







