Разработка мобильного приложения для криптотрейдинг-бота
Торговый бот работает на сервере: открывает позиции, исполняет ордера, управляет рисками. Мобильное приложение — это не сам бот, а полноценный интерфейс управления им: мониторинг позиций в реальном времени, настройка стратегий, история сделок, push при критичных событиях. Разработка такого приложения объединяет несколько сложных задач одновременно.
Архитектура системы
Мобильное приложение не торгует напрямую с биржей. Схема всегда через бэкенд:
Мобильное приложение
↕ REST API + WebSocket
Backend API (бот-сервер)
↕ Exchange API (Binance/Bybit)
Такая архитектура обязательна: биржевые API-ключи хранятся только на сервере, мобильное приложение аутентифицируется через JWT в собственный бэкенд. Прямые запросы с телефона к бирже исключены — ключи в приложении скомпрометируют при статическом анализе 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 }
}
Real-time данные
Два типа данных с разными требованиями к latency:
Данные бота (позиции, статус, PnL) — через WebSocket к собственному бэкенду. Бэкенд агрегирует данные от биржи и рассылает клиентам. Задержка 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)),
);
}
}
Reconnect — не optional. Мобильная сеть рвётся постоянно: смена WiFi на LTE, переход в тоннель. Exponential backoff с максимумом 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-уведомления: типы и приоритеты
Три уровня важности:
Критичные (доставить немедленно, разбудить устройство):
- Стоп-лосс сработал
- Бот остановился с ошибкой
- Биржевой API вернул 401 (невалидный ключ)
Информационные (показать в удобное время):
- Тейк-профит достигнут, позиция закрыта с прибылью
- Ежедневный отчёт
Тихие обновления (только обновить данные в фоне, без алерта):
- Пересчёт статистики
На 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 = "Стоп-лосс сработал",
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 между сделками (в минутах)
Критичное правило: изменение параметров при запущенном боте — с предупреждением и confirmation. Поля, которые нельзя менять на лету (тип стратегии, биржа) — заблокированы при status == RUNNING.
Типичные ошибки при разработке
Хранение JWT в открытом виде. SharedPreferences/UserDefaults доступны в бэкапах без шифрования. Только Keychain/Keystore.
Обновление всего списка при каждом рыночном тике. При 5+ открытых позициях и тике каждую секунду — постоянный rebuild всего списка. Нужно обновлять только изменившиеся ячейки: DiffableDataSource на iOS, key-параметр в LazyColumn на Android.
Игнорирование разрыва WebSocket. Соединение рвётся без события onError при смене сети. Нужен ping/pong: каждые 30 секунд отправляем ping, если за 10 секунд нет pong — считаем соединение мёртвым и переподключаемся.
Нет offline-режима. При отсутствии сети приложение показывает пустой экран. Минимум — кэшированные данные с меткой «данные от 14:30» и ProgressView при подключении.
Что входит в работу
- Аутентификация (JWT + биометрия)
- Dashboard с real-time позициями через WebSocket
- Управление несколькими ботами
- История сделок с пагинацией и фильтрами
- Граф equity curve
- Форма настроек стратегии с валидацией
- Push-уведомления по трём уровням приоритета
- Offline-режим с кэшированием
Сроки
| Версия | Состав | Срок |
|---|---|---|
| MVP | 1 бот, мониторинг, start/stop, push | 10–14 дней |
| Полная | Несколько ботов, стратегии, статистика, настройки | 20–30 дней |
| С нуля + дизайн | То же + UI/UX дизайн | +5–7 дней |
Стоимость рассчитывается индивидуально после анализа требований.







