Вступление
Представьте: бот открыл позицию, рынок резко разворачивается, а вы узнаёте об этом через 5 секунд — когда цена уже ушла на отметку стоп-лосса. Задержка в мобильном мониторинге напрямую конвертируется в потери. Мы разрабатываем мобильные приложения, которые подключаются к вашему торговому боту по WebSocket — задержка менее 200 мс, то есть в 25 раз быстрее, чем REST-полинг каждые 5 секунд. Наш опыт показывает, что правильно реализованный транспорт с exponential backoff и синхронизацией состояния гарантирует актуальность данных даже при нестабильной сети. Команда сертифицированных iOS, Android и Flutter-разработчиков реализует проект под ключ за 5–7 рабочих дней. Более 5 лет мы создаём high-performance решения для финансового сектора, и этот кейс — один из типовых.
Как работает WebSocket-транспорт?
REST-полинг каждые 5 секунд создаёт задержку до 5 секунд и бесполезную нагрузку. WebSocket — постоянное соединение, данные приходят по событию. Бэкенд бота рассылает события: position_opened, position_closed, order_filled, pnl_updated. В официальной документации Apple URLSessionWebSocketTask поддерживается с iOS 13.
Сравним подходы:
| Параметр | WebSocket | REST Polling |
|---|---|---|
| Задержка | 200 мс | 5+ секунд |
| Нагрузка на сеть | Минимальная | Высокая (запросы каждые 5с) |
| Работа в фоне | Требуется push | Только при активном приложении |
| Сложность реализации | Средняя | Низкая |
На iOS реализация через URLSessionWebSocketTask:
actor BotMonitorConnection { private var webSocketTask: URLSessionWebSocketTask? private let session = URLSession.shared var onEvent: ((BotEvent) -> Void)? func connect(botId: String, token: String) { let url = URL(string: "wss://api.example.com/bots/\(botId)/stream?token=\(token)")! webSocketTask = session.webSocketTask(with: url) webSocketTask?.resume() startListening() } private func startListening() { webSocketTask?.receive { [weak self] result in switch result { case .success(let message): if case .string(let text) = message, let data = text.data(using: .utf8), let event = try? JSONDecoder().decode(BotEvent.self, from: data) { self?.onEvent?(event) } self?.startListening() case .failure(let error): self?.scheduleReconnect() } } } private func scheduleReconnect() { Task { try? await Task.sleep(nanoseconds: 3_000_000_000) connect(botId: botId, token: token) } } } Почему exponential backoff критичен для мобильного трейдинга?
Мобильная сеть нестабильна: метро, лифт, переключение вышек. Если просто пытаться переподключаться каждую секунду, вы рискуете разрядить батарею и заблокировать сокет. Exponential backoff — это когда интервал переподключения растёт: 1с, 2с, 4с, 8с... до 30с. После успешного подключения интервал сбрасывается. Дополнительно, после восстановления соединения клиент запрашивает текущее состояние через REST (GET /bots/{id}/state), чтобы восполнить пропущенные события.
На Flutter с Riverpod удобно вынести соединение в StreamProvider:
@riverpod Stream<BotEvent> botEventStream(BotEventStreamRef ref, String botId) { final channel = WebSocketChannel.connect( Uri.parse('wss://api.example.com/bots/$botId/stream'), ); ref.onDispose(channel.sink.close); return channel.stream .map((data) => BotEvent.fromJson(jsonDecode(data as String))) .handleError((e) => ref.invalidateSelf()); } Что делать при обрыве соединения?
Пользователь должен видеть индикатор состояния: зелёная точка (live), серая (reconnecting), красная (offline). Это ключевой элемент доверия. Мы реализуем пошаговый алгоритм:
- При разрыве: ожидание 1 секунду, затем попытка подключения.
- При неудаче: удвоение таймаута до максимума 30 секунд.
- При успешном подключении: запрос текущего состояния через REST.
- Обновление UI с индикатором.
Какие данные отображаются на экране?
Приложение разделено на три основные зоны:
Открытые позиции. Пара, сторона (Long/Short), размер, цена входа, текущая цена, unrealized PnL в % и USD. PnL обновляется по каждому pnl_updated событию — мы не перерисовываем весь список, только изменившуюся строку. На Android — DiffUtil в RecyclerView, на Flutter — ListView.builder с ключами.
Лента событий. Последние N событий: «Открыта позиция BTC/USDT long 0.01 BTC @ 67,430», «Ордер исполнен», «Стоп-лосс сработал». Все с временными метками.
Метрики сессии. Количество сделок, суммарный реализованный PnL, win rate. Обновляется при каждом position_closed.
Типы событий подробно:
| Событие | Описание | Частота |
|---|---|---|
| position_opened | Открыта новая позиция | По событию |
| position_closed | Закрыта позиция | По событию |
| pnl_updated | Обновление PnL | Каждые 500 мс |
| order_filled | Исполнение ордера | По событию |
Push-уведомления для критичных событий
WebSocket — основной канал для активного экрана. Но когда приложение свёрнуто, события доставляются через FCM/APNs: стоп-лосс сработал, ошибка бота, значительное изменение PnL. Push-уведомления не заменяют real-time, а дополняют его. Мы настраиваем фильтрацию, чтобы не спамить: только события, помеченные бэкендом как critical.
Trust и опыт
Наши инженеры имеют сертификаты Apple (iOS) и Google (Android). За 5+ лет мы реализовали более 20 проектов для финансовой сферы, включая торговые терминалы, мониторинг портфелей и ботов. Каждое приложение проходит код-ревью, нагрузочное тестирование и проверку на безопасность.
Что входит в работу
- WebSocket-клиент с exponential backoff переподключением
- Индикатор состояния соединения (live/reconnecting/offline)
- Список открытых позиций с live PnL (эффективное обновление)
- Лента событий с автоскроллом
- REST-синхронизация состояния при переподключении
- Push через FCM/APNs для фоновых алертов
- Документация и инструкция по интеграции
Сроки и стоимость
Срок разработки — 5–7 рабочих дней. Если бэкенд уже рассылает WebSocket-события, хватит 4–5 дней на мобильную часть. Стоимость рассчитывается индивидуально после анализа требований и архитектуры.
Свяжитесь с нами, чтобы обсудить ваш проект. Наши специалисты бесплатно оценят логику бота, предложат оптимальную архитектуру и дадут точную смету. Получите консультацию уже сегодня.







