Вступ
Уявіть: бот відкрив позицію, ринок різко розвертається, а ви дізнаєтесь про це через 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.
Довіра та досвід
Наші інженери мають сертифікати Apple (iOS) та Google (Android). За 5+ років ми реалізували більше 20 проектів для фінансової сфери, включаючи торгові термінали, моніторинг портфелів та ботів. Кожен додаток проходить код-рев'ю, навантажувальне тестування та перевірку на безпеку.
Що входить в роботу
- WebSocket-клієнт з exponential backoff перепідключенням
- Індикатор стану з'єднання (live/reconnecting/offline)
- Список відкритих позицій з live PnL (ефективне оновлення)
- Стрічка подій з автоскролом
- REST-синхронізація стану при перепідключенні
- Push через FCM/APNs для фонових алертів
- Документація та інструкція з інтеграції
Терміни та вартість
Термін розробки — 5–7 робочих днів. Якщо бекенд вже розсилає WebSocket-події, вистачить 4–5 днів на мобільну частину. Вартість розраховується індивідуально після аналізу вимог та архітектури.
Зв'яжіться з нами, щоб обговорити ваш проект. Наші спеціалісти безкоштовно оцінять логіку бота, запропонують оптимальну архітектуру та дадуть точний кошторис. Отримайте консультацію вже сьогодні.







