Ми розробляємо модуль історії торгів для біржових додатків, який обробляє до 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-проектів. Отримайте консультацію з архітектури через форму зв'язку.
Аналітика мобільних застосунків: Firebase, Amplitude, AppsFlyer та атрибуція
Наша команда регулярно стикається з проектами, де аналітика вже «налаштована», але реальних інсайтів немає. Типовий приклад — стартап з 50k DAU: трекінг десятків подій без жодної відповіді на питання «чому користувачі не доходять до оплати». За два тижні ми побудували базову воронку і з'ясували, що 70% аудиторії відвалюється на екрані верифікації номера телефону. Після локалізації бага retention зріс на 12%. Висновок: аналітика повинна починатися з конкретних питань, а не з трекінгу всього підряд.
Чому таксономія подій — основа аналітики мобільних застосунків?
Firebase Analytics, Amplitude, Mixpanel — технічно схожі. Різниця в тому, що ви в них кладете. Типова помилка: події screen_view, button_tap_1, button_tap_2 без контексту. Через місяць ніхто не пам'ятає, що таке button_tap_2.
Правильна таксономія: об'єкт + дія + контекст. product_viewed, checkout_started, payment_completed з параметрами product_id, category, price, source. Це дозволяє будувати воронки, когортний аналіз та retention без додаткового трекінгу.
Ми фіксуємо naming convention у tracking plan — документі (Google Sheet або Amplitude Data Catalog), де описано кожну подію, її параметри та умови спрацьовування. Tracking plan синхронізується з командою аналітиків до початку розробки, а не після. Такий підхід гарантує, що через місяць дані залишаться інтерпретованими, а не перетворяться на звалище. Досвід впровадження на 50+ проектах підтверджує: при відсутності tracking plan вартість підтримки аналітики зростає у 2-3 рази за рахунок переробок.
Що обрати для аналітики мобільних застосунків: Firebase, Amplitude чи Mixpanel?
Таблиця нижче показує ключові відмінності трьох популярних платформ. Вибір залежить від бюджету, трафіку та завдань.
| Критерій |
Firebase Analytics |
Amplitude |
Mixpanel |
| Безкоштовний ліміт |
Безліміт (в рамках Spark-плану) |
До 10 млн events/міс |
До 1 тис. MTU/міс (Special) |
| Затримка даних |
До 24 годин (стандарт) |
Хвилини (real-time) |
Хвилини (real-time) |
| Воронки та когорти |
Базові воронки, обмежена кількість |
Глибокі воронки, Journeys, когорти |
Funnels, Retention, Insights |
| BigQuery-експорт |
Так (безкоштовно, сирі дані) |
Так (підписка) |
Так (Enterprise) |
| Session Replay |
Ні |
Є (iOS/Android SDK) |
Ні |
| Інтеграція з рекламою |
Google Ads (нативна) |
Через Universal Links |
Через партнерів |
Firebase Analytics — безкоштовно, глибока інтеграція з Google Ads, BigQuery-експорт для сирих даних. Обмеження: затримка даних до 24 годин, обмежені воронки. Для стартапів з Google Ads трафіком — перший вибір.
Amplitude — продуктова аналітика з акцентом на когорти та шляхи користувача. Journeys (колишній Pathfinder) показує реальні шляхи між подіями — не передбачувані воронки, а фактичні маршрути. Session Replay — запис сесій для UX-аналізу. Безкоштовний тир до 10 млн events/місяць достатній для більшості продуктів на старті.
Mixpanel — ближче до Amplitude, сильніший у сегментації в реальному часі. Insights, Funnels, Retention — базові інструменти, які закривають 90% аналітичних завдань продакта.
Більш формальні визначення цих платформ можна знайти у Wikipedia (Firebase) та Wikipedia (Amplitude).
Як вирішити проблему мультиканальної атрибуції з AppsFlyer?
Знати звідки прийшов користувач — окреме завдання. Firebase Attribution працює лише всередині Google-екосистеми. Для мультиканальної атрибуції (Facebook Ads, TikTok, Apple Search Ads, programmatic) потрібен MMP — Mobile Measurement Partner.
AppsFlyer — лідер ринку. OneLink — universal deep link, який працює на iOS та Android і коректно атрибутує встановлення з будь-якого каналу. Protect360 — вбудований захист від fraud (фейкові встановлення, click injection на Android). Adjust та Branch — конкуренти з подібним функціоналом. Branch сильний у deep linking; Adjust популярний у gaming.
Згідно з Apple, з iOS 14.5 застосунки повинні отримувати дозвіл користувача через ATT перед збором IDFA для відстеження. AppsFlyer використовує probabilistic matching (IP + user agent + timing) для цих користувачів — точність нижча, але краще ніж нічого. SKAdNetwork та Privacy Preserving Attribution надають агреговані дані від Apple із затримкою 24-72 години.
Як налаштувати crash-аналітику, щоб не пропускати баги?
Firebase Crashlytics — стандарт для crash reporting. Автоматично групує креші за стектрейсом, показує affected users %, velocity alerts при зростанні crash rate більш ніж на 10% за годину.
Важливо: символікація. На iOS .dSYM файли повинні автоматично завантажуватися при кожній збірці — через Fastlane upload_symbols_to_crashlytics або Xcode Cloud built-in. Без символів креш у Crashlytics виглядає як набір адрес пам'яті. Це трапляється частіше, ніж здається при переході на новий CI — в одному проекті з аудиторією 500k користувачів ми виявили, що 40% крешів залишалися несимволізованими через пропущений етап у CI/CD. Після автоматизації час реакції на баги скоротився з 3 годин до 15 хвилин.
Для React Native та Flutter — @sentry/react-native та sentry_flutter дають додатковий контекст: breadcrumbs, мережеві запити перед крешем, стан Redux/Provider.
Нижче — порівняння популярних інструментів crash-аналітики для вибору під свої завдання.
| Критерій |
Firebase Crashlytics |
Sentry |
Instabug |
| Безкоштовний ліміт |
Безліміт (в рамках Spark) |
5k events/міс |
250 MAU |
| Групування |
За стектрейсом + параметри |
За fingerprint |
За стектрейсом + метадані |
| Символікація |
Автоматична (через файл) |
Автоматична (через CLI) |
Автоматична |
| Velocity alerts |
Так (за % зміни) |
Так (за кількістю) |
Так (за порогом) |
| Дод. контекст |
Logs, Keys, Custom Keys |
Breadcrumbs, User, Tags |
User steps, мережеві запити |
| Ціна |
Безкоштовно (у Firebase) |
Від $26/міс (Team) |
Від $99/міс |
Налаштування оточення
Три оточення з окремими Firebase проектами: dev, staging, production. Змішувати аналітику з тестових сесій і production — поширена помилка, яка спотворює всі метрики. На iOS через GoogleService-Info.plist для кожної схеми, на Android через google-services.json у папці кожного flavor.
Терміни: базова аналітика з Firebase + Crashlytics — 3-5 днів. Повноцінний tracking plan + Amplitude/Mixpanel з воронками та когортами — 2-3 тижні. Атрибуція через AppsFlyer з deep linking та fraud protection — 1-2 тижні. Вартість розраховується індивідуально залежно від складності інтеграцій.
Що входить у нашу роботу
В рамках впровадження аналітики ми надаємо:
- Розробку та узгодження tracking plan з командами продукту та маркетингу.
- Інтеграцію SDK (Firebase, Amplitude, Mixpanel, AppsFlyer) з урахуванням вашого стеку (Swift/Kotlin/Flutter/React Native).
- Налаштування воронок, когорт, дашбордів та алертів.
- Автоматизацію символікації та завантаження .dSYM через Fastlane.
- Документацію щодо подій та параметрів.
- Навчання команди роботі з аналітичною платформою.
- Два тижні пост-релізної підтримки та коригування трекінгу.
Наш досвід — 7 років впровадження аналітики та понад 80 успішних проектів у сфері мобільної розробки. Ми гарантуємо коректність даних і прозорість кожного етапу.
Зв'яжіться з нами, щоб отримати консультацію з налаштування аналітики вашого застосунку. Замовте аудит поточної аналітики — і ми покажемо, які метрики ви втрачаєте.