Реализация трекинга портфеля криптоактивов в мобильном приложении
Пользователь держит 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 keys с ограничением на 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 бесплатный plan ограничен 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 change, pie chart по активам
- Хранение API-ключей в Keychain / Keystore
Сроки
Интеграция двух бирж + on-chain ETH + дашборд: 5–8 рабочих дней. Каждая дополнительная биржа — плюс 1–2 дня. Стоимость рассчитывается индивидуально после анализа требований.







