Реализация истории торгов в мобильном приложении биржи
История торгов на бирже — это не просто список ордеров. Это таблица с высоким темпом обновления в реальном времени, фильтрацией по торговым парам и типам ордеров, пагинацией на тысячах записей, корректным отображением статусов и расчётом P&L по каждой сделке.
Типы записей и структура данных
Биржевая история включает несколько сущностей, которые важно разделять на UI:
- Ордера (Orders) — то, что пользователь выставил: лимитный, рыночный, стоп. Статус: open, filled, partially_filled, cancelled
- Сделки (Trades/Fills) — фактические исполнения ордеров. Один ордер может иметь несколько fills
- P&L — расчёт прибыли по закрытым позициям
class TradeRecord {
final String tradeId;
final String orderId;
final String symbol; // "BTC/USDT"
final TradeSide side; // buy / sell
final double price; // цена исполнения
final double quantity;
final double fee;
final String feeAsset; // "USDT" или "BNB" (если fee discount)
final DateTime executedAt;
final OrderType orderType; // market, limit, stop_limit
}
P&L для spot торговли: (sell_price - avg_buy_price) * quantity - fees. Для бирж, которые не предоставляют P&L через API — вычисляем локально, сопоставляя buy и sell сделки по FIFO.
Загрузка данных: REST + WebSocket
Исторические данные — через REST API биржи. Большинство бирж (Binance, OKX, Bybit) имеют /api/v3/myTrades или аналог с cursor-based пагинацией по fromId или startTime:
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), // HMAC-SHA256
});
return (response.data as List).map(TradeRecord.fromJson).toList();
}
Real-time обновления — WebSocket executionReport (Binance) или orders channel. При получении события об исполнении ордера — добавляем сделку в начало списка и обновляем статус ордера.
UI: виртуализированный список
История торгов может содержать тысячи записей. ListView.builder с пагинацией — единственный правильный подход. Обычный ListView с children из 5000 виджетов вызовет jank при прокрутке и OOM на слабых устройствах.
NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification is ScrollEndNotification &&
notification.metrics.pixels >= notification.metrics.maxScrollExtent - 200) {
_loadNextPage(); // lazy load при приближении к концу списка
}
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]);
},
),
)
Фильтрация
Фильтры по торговой паре, по стороне (buy/sell), по типу ордера, по дате. Критически важно: фильтрация по дате через DateTimeRange picker с пресетами «сегодня / 7 дней / 30 дней».
Фильтры применяем на сервере при загрузке (параметры запроса), не на клиенте — иначе при большой истории придётся скачать всё и фильтровать локально.
Цветовая индикация и читаемость
Стандарт для биржевых приложений: buy — зелёный, sell — красный. Статусы: filled — основной цвет, cancelled — серый, partially_filled — оранжевый. Цена исполнения — чуть крупнее остальных полей.
Для отображения P&L: зелёный с + для прибыли, красный с - для убытка. Ноль — нейтральный цвет.
Экспорт
Кнопка экспорта в CSV — стандартное требование для биржевых историй (налоговая отчётность). Формируем CSV с полями: Date, Pair, Side, Price, Quantity, Fee, Fee Asset, Total. BOM для корректного открытия в Excel.
Что входит в работу
- REST API интеграция с поддержкой пагинации и подписи запросов (HMAC-SHA256)
- WebSocket для real-time обновлений новых сделок
- Виртуализированный список с ленивой загрузкой
- Фильтры по паре, стороне, дате
- Отображение P&L (если API предоставляет или расчёт по FIFO)
- Экспорт в CSV
Сроки
Базовая история с пагинацией и фильтрами: 3–5 дней. С real-time, P&L расчётом и экспортом: 1–2 недели. Стоимость рассчитывается индивидуально.







