Интеграция API Binance в мобильное криптоприложение
REST + WebSocket — не взаимозаменяемы. Binance предоставляет оба транспорта, и большинство ошибок при интеграции возникают именно из-за того, что команда пытается подписаться на рыночные данные через REST вместо WebSocket Streams, или наоборот — пытается выставить ордер через wss://stream.binance.com:9443.
Разберём оба сценария по-честному.
REST API: лимиты, подпись и типичные краши на мобиле
Binance REST API версии 3 (/api/v3/) использует HMAC-SHA256 для подписи приватных эндпоинтов. Подпись формируется из строки queryString + body, к которой добавляется timestamp и необязательный recvWindow. Типичная ошибка — {"code":-1021,"msg":"Timestamp for this request is outside of the recvWindow."} — возникает не из-за кривой подписи, а потому что системные часы на Android-устройстве уехали от серверного времени на 2–3 секунды. На iOS это редкость, на Android бюджетных устройствах — норма.
Правильное решение: не хардкодить recvWindow=5000, а синхронизировать локальное время с /api/v3/time при каждом холодном старте приложения и хранить serverTimeOffset в памяти.
Лимиты весовые, не запросные. Каждый эндпоинт имеет weight — /api/v3/depth?limit=1000 стоит 50 единиц, тогда как /api/v3/ticker/price — 1. Минутный лимит — 6000 единиц. Мобильное приложение с агрессивным поллингом стаканов на 5 пар улетает в бан (HTTP 429) за 30 секунд. Нужен WeightBudget-менеджер: очередь запросов с приоритетами, дебаунс на ручное обновление и мгновенный переход на WebSocket при превышении 80% квоты.
WebSocket Streams: жизненный цикл соединения на мобиле
wss://stream.binance.com:9443/ws/<streamName> — отдельный хост, без авторизации для публичных потоков. Для приватных (ордера, баланс) нужен listenKey, который получают через POST /api/v3/userDataStream и продлевают каждые 30 минут через PUT /api/v3/userDataStream.
Проблема мобиля: фоновый режим. На iOS приложение уходит в background, сокет закрывается с кодом 1001 (going away). При возврате в foreground нужно:
- Проверить, истёк ли
listenKey(TTL — 60 минут с момента последнегоPUT). - Если истёк — получить новый, переподписаться.
- Восстановить все публичные стримы заново.
На Android ситуация другая: агрессивный Doze Mode обрывает TCP-сокет раньше, чем WebSocket успевает прислать ping. Библиотека OkHttp с pingInterval(20, TimeUnit.SECONDS) справляется, но только если WakeLock держится на уровне WorkManager.
Для Flutter используем web_socket_channel с кастомным ReconnectingWebSocketChannel — wrapper с exponential backoff (старт 1 с, максимум 30 с) и журналом пропущенных событий для reconciliation при переподключении.
Подпись ордеров: что не так с большинством реализаций
Критичная деталь: параметры в query string и в body считаются вместе. Если POST /api/v3/order отправляется с телом symbol=BTCUSDT&side=BUY&...×tamp=..., то подпись формируется из всей этой строки целиком — без знака ?. Типичная ошибка — подписывать только body или только query, получать {"code":-1022,"msg":"Signature for this request is not valid."} и искать баг в алгоритме хэширования.
Ещё нюанс: порядок параметров важен только для подписи, но не для исполнения — Binance принимает их в любом порядке, но HMAC чувствителен к порядку конкатенации.
Как строим интеграцию
Архитектура: Clean Architecture с отдельным BinanceDataSource (network layer), TradeRepository (бизнес-логика) и ViewModel-слоем для UI.
Для REST: Retrofit 2 + OkHttpClient с интерцептором подписи и интерцептором синхронизации времени. Перехватываем 429 и 418 (IP-бан) — при 418 показываем пользователю таймер до разбана (заголовок Retry-After).
Для WebSocket: отдельный BinanceStreamManager — Singleton в DI-контейнере (Hilt), управляет пулом стримов, дедуплицирует подписки (если два экрана хотят btcusdt@trade — один сокет, два observer'а через SharedFlow).
Тестирование: Binance Testnet (testnet.binance.vision) с отдельным ключом. MockWebServer в unit-тестах для проверки подписи без сети.
Оценка и сроки
Стоимость интеграции зависит от объёма функциональности: только маркет-данные (без торговли) — одна история, полноценный трейдинг с управлением ордерами и портфелем — совсем другая. Перед оценкой анализируем требования: какие эндпоинты нужны, нужна ли поддержка Spot + Futures + Margin, есть ли существующий бэкенд-прокси или всё идёт напрямую с мобильного устройства.
Базовая интеграция (маркет-данные + один тип торговли) — от 2 до 4 недель. Полный торговый терминал с несколькими типами ордеров, стаканом, историей и аналитикой — от 6 до 12 недель в зависимости от платформы (нативная iOS/Android vs Flutter).







