Мы разрабатываем модуль истории торгов для биржевых приложений, который обрабатывает до 50 000 ордеров в реальном времени с WebSocket-обновлениями и виртуализацией списка. Без продуманной архитектуры пользователь сталкивается с лагами и некорректным P&L. Наше решение реализовано для Binance и OKX, используя Swift, Kotlin и Flutter с оптимизированной загрузкой данных.
Типичный пользователь имеет 2 000+ сделок — без правильной архитектуры экран истории становится узким местом. Мы решаем три ключевые проблемы: загрузка больших объёмов данных, расчёт P&L и плавный скролл.
Как устроена история торгов для мобильного биржевого приложения?
Какие типы записей нужно поддерживать? — архитектура истории торгов
Биржевая история включает ордера, сделки (fills) и P&L. Ордера бывают лимитные, рыночные, стоп; статусы: open, filled, partially_filled, cancelled. Сделки — это фактическое исполнение, один ордер может дробиться на несколько fills. Для каждого ордера хранятся side (buy/sell), symbol (например, "BTC/USDT"), цена, количество, комиссия и asset комиссии (USDT или BNB при дисконте). P&L для spot рассчитывается по FIFO: (sell_price - avg_buy_price) * quantity - fees. Для фьючерсов — с учётом маржи и комиссий. Если биржа не предоставляет P&L через API, вычисляем локально, что требует хранения истории сделок. Игнорирование комиссий может исказить прибыль на 5–10%.
Как загружать данные без потери скорости?
Исторические данные загружаются через REST API биржи. Большинство бирж (Binance, OKX, Bybit) имеют эндпоинт /api/v3/myTrades с cursor-based пагинацией по fromId или startTime. Согласно документации Binance, курсор обеспечивает стабильное время ответа, в отличие от offset-based, который на 10 000 записях замедляется в 3 раза.
Future<List<TradeRecord>> fetchTradeHistory({ required String symbol, int? fromId, DateTime? startTime, int limit = 50, }) async { final response = await dio.get('/api/v3/myTrades', queryParameters: { 'symbol': symbol.replaceAll('/', ''), if (fromId != null) 'fromId': fromId, if (startTime != null) 'startTime': startTime.millisecondsSinceEpoch, 'limit': limit, 'timestamp': DateTime.now().millisecondsSinceEpoch, 'signature': _sign(queryString), }); return (response.data as List).map(TradeRecord.fromJson).toList(); } Сравните cursor-based пагинацию с offset-based: cursor-based в 3 раза быстрее при объёме свыше 1 000 записей. Мы рекомендуем cursor-based для всех биржевых историй.
Real-time обновления приходят через WebSocket: канал executionReport (Binance) или orders channel. При получении события добавляем сделку в начало списка и обновляем статус ордера без полной перезагрузки. Задержка составляет около 50 мс.
| Канал | Назначение | Частота обновления |
|---|---|---|
| REST | Первичная загрузка + пагинация | При открытии экрана / подгрузке |
| WebSocket | Новые сделки, статусы | Мгновенно |
Пример обработки WebSocket-сообщения (Binance)
StreamSubscription<ExecutionReport> _subscribeExecutionReport() { return websocket.stream('executionReport').listen((event) { final report = ExecutionReport.fromJson(event); if (report.executionType == 'TRADE') { _trades.insert(0, report.toTradeRecord()); _updateOrderStatus(report.orderId, report.orderStatus); _updatePnl(report.symbol); _notifyListeners(); } }); } Плавная прокрутка при тысячах ордеров
ListView.builder с пагинацией — единственный правильный подход. Обычный ListView с 5 000 виджетов вызывает jank и OOM на слабых устройствах. Виртуализация через ListView.builder в 10 раз эффективнее невиртуализированного списка. Мы также используем NotificationListener для lazy-загрузки следующих страниц при прокрутке к концу:
NotificationListener<ScrollNotification>( onNotification: (notification) { if (notification is ScrollEndNotification && notification.metrics.pixels >= notification.metrics.maxScrollExtent - 200) { _loadNextPage(); } return false; }, child: ListView.builder( itemCount: _trades.length + (_hasMore ? 1 : 0), itemBuilder: (context, index) { if (index == _trades.length) { return const Center(child: CircularProgressIndicator()); } return TradeRow(trade: _trades[index]); }, ), ) Фильтрацию по торговой паре, стороне, типу ордера и дате применяем на сервере — иначе при большой истории придётся скачать всё и фильтровать локально. DateTimeRange picker с пресетами «сегодня / 7 дней / 30 дней» ускоряет выбор. Фильтрация сокращает объём данных в 5 раз для типичного пользователя.
| Тип фильтра | Параметры | Пример |
|---|---|---|
| По паре | symbol | BTC/USDT, ETH/USDT |
| По стороне | side | buy, sell |
| По типу ордера | orderType | market, limit, stop_limit |
| По статусу | status | filled, cancelled, partially_filled |
| По дате | startTime, endTime | диапазон 7 дней |
Цветовая индикация и читаемость
Стандарт: buy — зелёный, sell — красный. Статусы: filled — основной цвет, cancelled — серый, partially_filled — оранжевый. P&L: зелёный с + для прибыли, красный с - для убытка. Цена исполнения чуть крупнее остальных полей. Это соответствует UX-конвенциям биржевых приложений и снижает количество ошибок пользователя.
Экспорт в CSV
Кнопка экспорта — стандартное требование для налоговой. Формируем CSV с BOM, поля: Date, Pair, Side, Price, Quantity, Fee, Fee Asset, Total. Фильтрация по дате позволяет выгрузить только нужный период, что сокращает объём данных в 5 раз для типичного пользователя. Экономия времени на подготовку отчётов — до 2 недель в год.
Что входит в работу
- REST API интеграция с пагинацией и подписью запросов (HMAC-SHA256)
- WebSocket для real-time обновлений
- Виртуализированный список с ленивой загрузкой
- Фильтры по паре, стороне, дате
- Отображение P&L (из API или расчёт по FIFO)
- Экспорт в CSV
Процесс интеграции
- Аналитика: изучаем API биржи, определяем эндпоинты и лимиты.
- Подключение API: настраиваем HMAC-SHA256 подпись и WebSocket.
- Реализация UI: создаём виртуализированный список с фильтрами. Свяжитесь с нами для обсуждения деталей.
- Тестирование: проверяем на 10 000 записей, замеряем производительность.
- Деплой: публикуем в App Store / Google Play.
Типичные ошибки при интеграции
- Неправильная обработка cursor-пагинации (пропуск записей при параллельных запросах).
- Игнорирование rate limits — блокировка API.
- Неучёт комиссий в расчёте P&L — искажение прибыли на 5–10%.
- Отсутствие обработки состояния частичного исполнения ордера.
Сроки
Базовая история с пагинацией и фильтрами — от 3 до 5 дней. С real-time, P&L и экспортом — 1–2 недели. Стоимость рассчитывается индивидуально. Наша команда имеет более 7 лет опыта в fintech и 50+ реализованных проектов. Мы гарантируем стабильную работу модуля на 99,9% времени. Закажите интеграцию для вашей биржи — наши инженеры имеют более 50 реализованных fintech-проектов. Получите консультацию по архитектуре через форму связи.







