Моніторинг торгового бота в режимі реального часу в мобільному додатку
Бот відкрив позицію, ринок рухнув проти — користувач хоче бачити це негайно, а не через п'ять хвилин опитування. Моніторинг торгового бота в режимі реального часу — це завдання про передачу даних: WebSocket, правильна обробка розривів та розумне оновлення UI без перевантаження main thread.
WebSocket як основний транспорт
REST-опитування кожні 5 секунд створює затримку до 5 секунд та непотрібне навантаження. WebSocket — це постійне з'єднання, дані приходять за подією. Backend бота розповсюджує eventi: position_opened, position_closed, order_filled, pnl_updated.
На 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) // 3 секунди
connect(botId: botId, token: token)
}
}
}
Переподключення та стани з'єднання
WebSocket розривається. Мобільні мережі нестійкі. Використовуйте exponential backoff: перший retry через 1 секунду, потім 2, 4, 8, максимум 30. При успішному переподключенні — запит поточного стану через REST (GET /bots/{id}/state), тому що під час розриву eventi могли бути втрачені.
Індикатор стану з'єднання на UI: зелена точка (live), сіра (reconnecting), червона (offline). Користувачі повинні розуміти, чи актуальні дані.
На 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()); // при помилці — пересоздати provider
}
Що відображати
Поточні відкриті позиції. Пара, сторона (Long/Short), розмір, ціна входу, поточна ціна, unrealized PnL у % та USD. PnL оновлюється на кожній події pnl_updated — не перерисовувати весь список, лише змінену рядок. На Android використовуйте DiffUtil в RecyclerView, на Flutter використовуйте ListView.builder з ключами.
Потік подій. Останні N подій в хронологічному порядку: «Відкрита позиція BTC/USDT long 0.01 BTC @ 67,430», «Ордер виконаний», «Stop-loss спрацював». З часовими мітками.
Метрики сесії. Кількість угод, загальний реалізований PnL, win rate. Оновлюється на кожній події position_closed.
Push-сповіщення для критичних подій (stop-loss спрацював, помилка бота) — окремий шар через FCM/APNs. WebSocket для екрана реального часу, push — для фонових сповіщень.
Що входить до роботи
- WebSocket-клієнт з exponential backoff переподключенням
- Індикатор стану з'єднання
- Список відкритих позицій з live PnL (ефективне оновлення без повного перебудови)
- Потік подій з автоскролом
- REST-синхронізація стану при переподключенні
- Push через FCM/APNs для фонових алертів
Терміни
5–7 робочих днів. Якщо backend вже розповсюджує WebSocket-eventi — 4–5 днів на мобільну частину. Вартість розраховується індивідуально після аналізу вимог.







