Интеграция API OKX в мобильное криптоприложение
OKX — одна из немногих бирж, где REST и WebSocket живут в разных URL-пространствах и с разной логикой аутентификации. REST идёт на https://www.okx.com/api/v5/, WebSocket — на wss://ws.okx.com:8443/ws/v5/public и /private. Если команда раньше работала с Binance и переносит архитектуру «как есть» — будут сюрпризы.
Подпись: три поля в заголовках, не в параметрах
OKX аутентифицирует запросы через HTTP-заголовки, а не через query string или body:
-
OK-ACCESS-KEY— API key -
OK-ACCESS-SIGN— Base64(HMAC-SHA256(timestamp + method + requestPath + body)) -
OK-ACCESS-TIMESTAMP— ISO 8601 (например2024-01-15T10:30:00.123Z) -
OK-ACCESS-PASSPHRASE— третий секрет, задаётся при создании ключа
requestPath включает query string: для GET /api/v5/account/balance?ccy=BTC подписываем /api/v5/account/balance?ccy=BTC. Тело для GET-запросов — пустая строка "". Ошибка {"code":"50113","msg":"Invalid Sign"} почти всегда означает проблему с requestPath — либо забыли query string, либо добавили лишний слэш.
Временна́я метка в формате ISO 8601 с миллисекундами — редкость для бирж. На Android Instant.now().toString() даёт нужный формат начиная с API 26. Для более старых версий — SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US) с UTC timezone.
WebSocket Private: аутентификация сессии
{
"op": "login",
"args": [{
"apiKey": "...",
"passphrase": "...",
"timestamp": "1705312200",
"sign": "..."
}]
}
Signature для WebSocket отличается от REST: HMAC-SHA256(timestamp + "GET" + "/users/self/verify"), где timestamp — Unix seconds (не миллисекунды, не ISO). Эта разница — частый источник ошибок при рефакторинге общего auth-модуля.
OKX отключает WebSocket-сессию через 30 секунд без activity. Ping/pong — нестандартный: отправляем строку "ping", получаем строку "pong". Не JSON-объект, именно raw string. Библиотеки, которые работают только с text-frame JSON, ломаются на этом месте.
Нюансы продуктовой логики
OKX поддерживает instType (instrument type): SPOT, MARGIN, SWAP, FUTURES, OPTION. Один и тот же тикер, например BTC-USDT, существует в нескольких instType с разными правилами торговли. При реализации ордерной формы нужно явно передавать instType — иначе биржа вернёт {"code":"51001","msg":"Instrument ID does not exist"} для инструментов, которые существуют в другом типе.
Ещё одна особенность — tdMode (trade mode): cash для Spot, cross или isolated для маржи. Мобильные UI часто скрывают этот выбор «для простоты», что приводит к случайному открытию маржинальных позиций. Рекомендуем явный UI-выбор с предупреждением.
Работа с историческими данными
OKX лимитирует кандлы: GET /api/v5/market/candles возвращает максимум 300 записей. Для подгрузки истории при скролле графика назад нужен пагинационный запрос с параметром before (ID свечи). Стандартная ошибка — использовать after вместо before и получать данные в обратном порядке, потом инвертировать массив в UI с визуальным артефактом.
Стек и подход
Для React Native: axios с request interceptor для подписи + reconnecting-websocket с кастомным pingInterval. Состояние рынка — в Redux Toolkit с RTK Query для REST и кастомным middleware для WebSocket событий.
Для Flutter: dio + web_socket_channel, BLoC для управления состоянием торговых экранов. Разделяем PublicStreamBloc и PrivateStreamBloc — разные жизненные циклы (публичные стримы живут всё время, приватные — только при авторизованной сессии).
Тестирование: OKX Demo Trading (www.okx.com/demo-trading) — полноценная среда с реальными стаканами и возможностью выставлять ордера без реальных средств. Существенно лучше, чем у некоторых конкурентов.
Срок интеграции: базовая (маркет-данные + spot trading) — 2–4 недели. Деривативы + margin — добавьте ещё 3–4 недели на бизнес-логику и тестирование edge cases.







