Реалізація трекингу портфеля крипто-активів у мобільному приложенні
Користувач тримає BTC на Binance, ETH у MetaMask та кілька альткоїнів на Bybit. Хоче видити загальну вартість портфеля, зміну за 24 години та розподіл активів — в одному екрані, без ручного вводу. Це і є трекинг портфеля: агрегація даних з різних джерел з актуальними цінами.
Джерела даних
Три джерела, кожне зі своїми нюансами:
Біржові API. Binance /api/v3/account повертає баланси спот-кошельку, але вимагає HMAC-SHA256 підпис з timestamp та recvWindow. Bybit V5 /v5/account/wallet-balance — аналогічно. Ключі зберігаються зашифровані на пристрої (iOS Keychain, Android Keystore), приватні ключі ніколи не передаються — тільки read-only API ключі з обмеженням по IP, якщо біржа підтримує.
On-chain кошельки. Для Ethereum-кошельків — Alchemy або Infura /eth_getBalance плюс alchemy_getTokenBalances для ERC-20. Для Solana — getTokenAccountsByOwner через Helius або QuickNode. Адреса публічна, ключі не потрібні.
Ручний ввід. Частину активів користувачі додають вручну (стейкинг, p2p, апаратні гаманці). Проста форма: тікер + кількість.
Актуальні ціни — через CoinGecko API /simple/price (до 30 тікерів за запит) або CoinMarketCap Pro API. CoinGecko безплатний план обмежений 30 запитами/хвилину — для приложення з фоновим оновленням достатньо, якщо кешувати ціни з TTL 60 секунд.
// iOS, Swift — агрегація портфеля
actor PortfolioAggregator {
private let exchangeService: ExchangeService
private let priceService: PriceService
private let walletService: WalletService
func aggregate() async throws -> Portfolio {
async let exchangeBalances = exchangeService.fetchAll()
async let onchainBalances = walletService.fetchAll()
let (exchange, onchain) = try await (exchangeBalances, onchainBalances)
let allTickers = (exchange + onchain).map(\.ticker)
let prices = try await priceService.getPrices(tickers: allTickers)
let positions = (exchange + onchain).map { balance in
PortfolioPosition(
ticker: balance.ticker,
amount: balance.amount,
priceUsd: prices[balance.ticker] ?? 0,
source: balance.source
)
}
return Portfolio(positions: positions, updatedAt: .now)
}
}
async let дозволяє запитувати біржі та on-chain балансі паралельно — агрегація вміщується в 1–2 секунди замість послідовних 4–5.
Зберігання та оновлення
Балансі кешуються локально — SQLite через drift (Flutter) або CoreData/SwiftData (iOS). Важливо для offline-режиму: користувач відкриває приложение без мережі та видить останні актуальні дані з мет.часу.
Фоновое оновлення на iOS — через BGAppRefreshTask. Планується при переходу в фон, система викликає задачу раз на 15–30 хвилин (точний інтервал визначає iOS на основі usage patterns). На Android — WorkManager з PeriodicWorkRequest(15, TimeUnit.MINUTES).
Оновлення цін у реальному часі — WebSocket. Binance надає wss://stream.binance.com:9443/stream?streams=btcusdt@ticker/ethusdt@ticker. При відкритті приложення підключаємось до стріму, при згортанні — відключаємось та покладаємось на кеш.
Типічні грабли
Clock skew на біржевих запитах. Binance вимагає, щоб timestamp у запиті відрізнявся від серверного часу не більше ніж на recvWindow (за замовчуванням 5000 мс). На Android-пристроях часи іноді уходять. Рішення: синхронізувати час через /api/v3/time перед першим запитом та застосувати offset.
Rate limits при множині бирж. Якщо користувач додав 5 бирж, одночасні запити можуть вичерпати ліміти. Потрібна чергу з контролем частоти: одна exchange — один слот у черзі, затримка 200 мс між запитами до одного endpoint.
Різні формати тікерів. Binance повертає BTC, Bybit — BTC, CoinGecko приймає bitcoin (id), не символ. Потрібна таблиця маппінгу тікер → CoinGecko id, яку періодично синхронізуємо через /coins/list.
Що входить у роботу
- Інтеграція Binance / Bybit / OKX API з HMAC-підпругою
- Завантаження on-chain балансів (EVM через Alchemy, Solana опціонально)
- Кешування в локальній БД з offline-підтримкою
- Фоновое оновлення (BGAppRefreshTask / WorkManager)
- Дашборд: загальна вартість, 24h зміна, pie chart за активами
- Зберігання API-ключів у Keychain / Keystore
Строки
Інтеграція двох бирж + on-chain ETH + дашборд: 5–8 робочих днів. Кожна додаткова біржа — плюс 1–2 дні. Вартість розраховується індивідуально після аналізу вимог.







