Мы разрабатываем модуль истории торгов для биржевых приложений, который обрабатывает до 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-проектов. Получите консультацию по архитектуре через форму связи.







