Розробка мобільного додатку для крипто-торгового бота
Торговий бот працює на сервері: відкриває позиції, виконує ордери, управляє ризиками. Мобільний додаток — це не сам бот, а повнофункціональний інтерфейс керування ним: моніторинг позицій в режимі реального часу, налаштування стратегій, історія угод, push-сповіщення про критичні події. Розробка такого додатку об'єднує кілька складних завдань одночасно.
Архітектура системи
Мобільний додаток не торгує напряму з біржею. Схема завжди йде через backend:
Мобільний додаток
↕ REST API + WebSocket
Backend API (бот-сервер)
↕ Exchange API (Binance/Bybit)
Така архітектура обов'язкова: ключі API біржі зберігаються лише на сервері, мобільний додаток аутентифікується через JWT до свого власного backend. Прямі запити з телефону до біржі виключені — ключи в додатку будуть скомпрометовані статичним аналізом APK/IPA.
Аутентифікація та безпека
Користувач входить до додатку (email/пароль або OAuth), отримує JWT + refresh token. JWT зберігається в iOS Keychain / Android Keystore — не в SharedPreferences або UserDefaults, інакше він доступний з незашифрованих резервних копій.
Біометрична аутентифікація для відкриття додатку та підтвердження критичних операцій (наприклад, зупинення бота з закриттям позицій):
// iOS — біометрія через LocalAuthentication
import LocalAuthentication
func authenticateWithBiometrics() async throws {
let context = LAContext()
var error: NSError?
guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {
throw AuthError.biometricsNotAvailable
}
let success = try await context.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: "Підтвердіть зупинення бота"
)
guard success else { throw AuthError.biometricsFailed }
}
Дані в режимі реального часу
Два типи даних з різними вимогами до затримки:
Дані бота (позиції, статус, PnL) — через WebSocket до вашого backend. Backend агрегує дані з біржі та розповсюджує їх клієнтам. Затримка 1–3 секунди приймаль.
Ринкові дані (ціна активу, стакан ордерів) — можна отримати безпосередньо з потоків Binance WebSocket (btcusdt@ticker, btcusdt@depth5). Затримка < 100 мс. Однак пряме підключення до біржі з мобільного додатку призначено лише для відображення, а не для торгівлі.
На Flutter управління кількома з'єднаннями WebSocket:
@riverpod
class TradingHubNotifier extends _$TradingHubNotifier {
WebSocketChannel? _botChannel;
WebSocketChannel? _marketChannel;
@override
TradingHubState build() {
ref.onDispose(() {
_botChannel?.sink.close();
_marketChannel?.sink.close();
});
return const TradingHubState.initial();
}
void connect(String botId, String jwtToken, String symbol) {
_connectBot(botId, jwtToken);
_connectMarket(symbol);
}
void _connectBot(String botId, String token) {
_botChannel = WebSocketChannel.connect(
Uri.parse('wss://api.mybot.com/bots/$botId/ws?token=$token'),
);
_botChannel!.stream.listen(
(data) => _handleBotEvent(jsonDecode(data as String)),
onError: (_) => Future.delayed(const Duration(seconds: 3), () => _connectBot(botId, token)),
onDone: () => Future.delayed(const Duration(seconds: 3), () => _connectBot(botId, token)),
);
}
void _connectMarket(String symbol) {
_marketChannel = WebSocketChannel.connect(
Uri.parse('wss://stream.binance.com:9443/ws/${symbol.toLowerCase()}@ticker'),
);
_marketChannel!.stream.listen(
(data) => _handleMarketTick(jsonDecode(data as String)),
);
}
}
Перепідключення не факультативне. Мобільні мережі постійно розривається: перехід з WiFi на LTE, вхід у тунель. Використовуйте експоненціальну затримку з максимумом 30 секунд.
Основний екран: Dashboard
Три смислові блоки без зайвого:
Статус бота. Кольоровий індикатор + текстовий статус (Running / Stopped / Error). Кнопки Start/Stop. При помилці — коротке повідомлення («Недостатньо балансу для відкриття позиції»).
Відкриті позиції. Список карток: пара, сторона, розмір, ціна входу, поточна ціна, unrealized PnL в USDT та %. PnL оновлюється при кожному ринковому тику без перебудови списку — лише зміна даних у вже створених комірках. На iOS використовуйте UICollectionView з UICollectionViewDiffableDataSource та NSDiffableDataSourceSnapshot для точкових оновлень.
Метрики сесії. Загальний реалізований PnL на сьогодні, кількість угод, win rate. Перерахунок при кожній події position_closed.
Управління кількома ботами
Користувач може запускати кілька ботів на різних парах та стратегіях. BotsListScreen — список ботів з компактними картками (статус, поточний PnL, пара). Дотик — навігація до детального екрану конкретного бота.
Коли активні кілька ботів, утримуйте з'єднання WebSocket лише для відкритого бота. У фоновому режимі — перейдіть на push-сповіщення замість WebSocket (FCM high priority data message).
Push-сповіщення: типи та пріоритети
Три рівні важливості:
Критичні (доставити негайно, розбудити пристрій):
- Stop-loss спрацював
- Бот зупинився з помилкою
- Біржевий API повернув 401 (невалідний ключ)
Інформаційні (показати у зручний час):
- Take-profit досягнутий, позиція закрита з прибутком
- Щоденний звіт
Тихі оновлення (оновити дані у фоні лише, без сповіщення):
- Перерахунок статистики
На Android: критичні — FCM з priority: high, ttl: 60s, notification + data. Інформаційні — priority: normal. iOS: критичні — apns-priority: 10, apns-expiration: 60.
// Android — обробка push в FirebaseMessagingService
override fun onMessageReceived(message: RemoteMessage) {
val eventType = message.data["event_type"] ?: return
when (eventType) {
"stop_loss_triggered" -> {
showCriticalNotification(
title = "Stop-loss спрацював",
body = "${message.data["pair"]}: -${message.data["loss_usdt"]} USDT",
channelId = CRITICAL_CHANNEL_ID
)
}
"position_closed" -> {
showInfoNotification(
title = "Позиція закрита",
body = "${message.data["pair"]}: +${message.data["pnl_usdt"]} USDT",
channelId = INFO_CHANNEL_ID
)
}
"background_sync" -> {
// Оновити локальний кеш без показу сповіщення
syncBotState(message.data["bot_id"]!!)
}
}
}
Notification channels на Android — критичні в окремому каналі з IMPORTANCE_HIGH та вібрацією. Інформаційні — IMPORTANCE_DEFAULT. Користувачі можуть керувати каналами в системних налаштуваннях без відключення всіх сповіщень одночасно.
Історія угод та статистика
Окрема вкладка з повною історією: список з пагінацією (Jetpack Paging 3 / SwiftUI LazyVStack з .task тригером для наступної сторінки), фільтри за парою/періодом/результатом.
Summary-метрики за період: Total PnL, Win Rate, Profit Factor, Max Drawdown. Граф equity curve (кумулятивний PnL) на fl_chart LineChart. Граф оновлюється при перемиканні періоду, а не при кожній події.
Налаштування стратегій
Окремий екран для кожної стратегії бота. Форма з числовими полями та валідацією:
- Take Profit / Stop Loss (діапазон 0.1–50%)
- Розмір ордера (мінімум диктує біржа)
- Торгові пари (multiselect з пошуком, список з API біржі)
- Cooldown між угодами (у хвилинах)
Критичне правило: зміна параметрів під час роботи бота — з попередженням та підтвердженням. Поля, які неможливо змінювати на ходу (тип стратегії, біржа) — заблоковані при status == RUNNING.
Типові помилки при розробці
Зберігання JWT у відкритому вигляді. SharedPreferences/UserDefaults доступні в незашифрованих резервних копіях. Використовуйте лише Keychain/Keystore.
Перебудова всього списку при кожному ринковому тику. З 5+ відкритими позиціями та тиком кожну секунду — постійна перебудова всього списку. Оновлюйте лише змінені комірки: DiffableDataSource на iOS, параметр key в LazyColumn на Android.
Ігнорування розриву WebSocket. З'єднання розривається без події onError при переключенні мереж. Впровадьте ping/pong: надсилайте ping кожні 30 секунд, якщо нема pong протягом 10 секунд — вважайте з'єднання мертвим і переподключіться.
Немає офлайн-режиму. Без мережі додаток показує порожній екран. Мінімум — кешовані дані з часовою міткою («дані від 14:30») та ProgressView при підключенні.
Що входить до роботи
- Аутентифікація (JWT + біометрія)
- Dashboard з позиціями в режимі реального часу через WebSocket
- Управління кількома ботами
- Історія угод з пагінацією та фільтрами
- Граф equity curve
- Форма налаштування стратегії з валідацією
- Push-сповіщення на трьох рівнях пріоритету
- Офлайн-режим з кешуванням
Терміни
| Версія | Склад | Тривалість |
|---|---|---|
| MVP | 1 бот, моніторинг, start/stop, push | 10–14 днів |
| Повна | Кілька ботів, стратегії, статистика, налаштування | 20–30 днів |
| З нуля + дизайн | Те ж саме + UI/UX дизайн | +5–7 днів |
Вартість розраховується індивідуально після аналізу вимог.







