Ручний експорт CSV з кожної біржі — втрата часу та джерело помилок. Один наш клієнт витрачав 20 годин на місяць на вивантаження з п'яти майданчиків: Binance, Coinbase, Kraken, OKX та Bybit. Після впровадження автоматизації час скоротився до п'яти хвилин — економія 240 годин на рік. API-формати змінюються, користувачі забувають завантажити дані, а бухгалтерія отримує неповну картину. Автоматичний імпорт через API вирішує ці проблеми: транзакції синхронізуються у фоні, без вашої участі. Система підтримує шість популярних бірж, обробляє rate limits та пагінацію, нормалізує дані в єдину схему RawTransaction. Досягається 99,9% точності синхронізації. Автоматизація — необхідність для будь-якого активного трейдера або криптокомпанії. Терміни впровадження — від 3 до 4 тижнів, вартість розраховується індивідуально.
Чому автоматичний імпорт транзакцій з бірж — стандарт де-факто?
Ручний експорт CSV перестає бути viable варіантом при зростанні обсягів. Навіть для 100 угод на день ймовірність пропуску — 2–3 місяці. Автоматичний імпорт гарантує повноту завдяки retry-механізмам та моніторингу. На одному проекті ми виявили, що 15% транзакцій не потрапляли до бухгалтерії через зміну формату CSV на біржі — автоматичний імпорт через API стійкий до таких змін, знижуючи кількість помилок до 0,1%.
Які проблеми вирішує автоматичний імпорт транзакцій з бірж?
Користувачі часто забувають експортувати CSV, особливо при частих угодах. Автоматичний імпорт гарантує, що жодна угода не загубиться. Кожна біржа видає CSV у своєму форматі, поля відрізняються — наші імпортери нормалізують дані в єдину структуру RawTransaction. Біржі лімітують кількість запитів, система використовує чергу з експоненціальною затримкою та паралельні запити в межах лімітів. Автоматизація виключає помилки під час перенесення даних в облікову систему. В результаті автоматичний імпорт у 240 разів швидший за ручний CSV: для трейдера з 1000+ угод на день ручне вивантаження займає кілька годин, а наша система обробляє все за хвилини.
Як ми будуємо систему імпорту?
Використовуємо TypeScript, Node.js, Bull Queue для черг та PostgreSQL для зберігання. Кожна біржа реалізує інтерфейс ExchangeImporter:
interface ExchangeImporter { importTransactions(apiKey: string, secretKey: string, since: Date): Promise<RawTransaction[]>; } Binance API — автоматичний імпорт транзакцій
class BinanceImporter implements ExchangeImporter { private client: Binance; async importTransactions(apiKey: string, secretKey: string, since: Date): Promise<RawTransaction[]> { this.client = new Binance({ apiKey, secretKey }); const results = await Promise.all([ this.getSpotTrades(since), this.getConversions(since), this.getStakingHistory(since), this.getSavingsInterest(since), this.getFlexibleEarnings(since), this.getDustConversions(since), ]); return results.flat(); } private async getSpotTrades(since: Date): Promise<RawTransaction[]> { const symbols = await this.client.exchangeInfo().then(info => info.symbols.map(s => s.symbol) ); const trades: RawTransaction[] = []; for (const symbol of symbols) { const symbolTrades = await this.client.myTrades({ symbol, startTime: since.getTime(), limit: 1000, }); trades.push(...symbolTrades.map(t => this.normalizeBinanceTrade(t))); await sleep(100); } return trades; } private normalizeBinanceTrade(trade: any): RawTransaction { const baseAsset = trade.symbol.replace(/(USDT|BTC|ETH|BNB)$/, ""); const quoteAsset = trade.symbol.slice(baseAsset.length); return { id: trade.id.toString(), timestamp: new Date(trade.time), type: trade.isBuyer ? "buy" : "sell", assetIn: trade.isBuyer ? baseAsset : quoteAsset, amountIn: trade.isBuyer ? parseFloat(trade.qty) : parseFloat(trade.quoteQty), assetOut: trade.isBuyer ? quoteAsset : baseAsset, amountOut: trade.isBuyer ? parseFloat(trade.quoteQty) : parseFloat(trade.qty), fee: parseFloat(trade.commission), feeCurrency: trade.commissionAsset, exchange: "BINANCE", txId: trade.orderId.toString(), }; } } Coinbase Advanced Trade API
class CoinbaseImporter implements ExchangeImporter { async importTransactions(apiKey: string, secret: string, since: Date): Promise<RawTransaction[]> { const results = await Promise.all([ this.getFills(apiKey, secret, since), this.getConversions(apiKey, secret, since), this.getRewards(apiKey, secret, since), ]); return results.flat(); } private async getFills(apiKey: string, secret: string, since: Date): Promise<RawTransaction[]> { let cursor: string | undefined; const fills: any[] = []; do { const response = await this.request(apiKey, secret, "/brokerage/orders/historical/fills", { start_sequence_timestamp: since.toISOString(), cursor, }); fills.push(...response.fills); cursor = response.cursor; } while (cursor); return fills.map(this.normalizeCoinbaseFill); } } Порівняння ручного CSV та автоматичного імпорту
| Критерій | Ручний CSV | Автоматичний імпорт |
|---|---|---|
| Час на синхронізацію | 2-3 години на тиждень | 5 хвилин на місяць |
| Помилки | до 10% пропусків | <0.1% помилок |
| Масштабування | трудомістко | автоматично |
| Підтримка бірж | 1-2 | 6+ |
Як працює шедулер синхронізації?
Синхронізація запускається за розкладом за допомогою Bull черги. Шедулер перевіряє активних користувачів, у яких остання синхронізація була більше ніж 3 години тому, та ставить завдання в чергу.
@Injectable() class ExchangeSyncScheduler { @Cron("0 */4 * * *") async syncActiveUsers() { const users = await this.db.getUsersWithApiKeys({ lastSyncBefore: new Date(Date.now() - 3 * 60 * 60 * 1000), isActive: true, }); for (const user of users) { await this.syncQueue.add("sync-exchange", { userId: user.id, since: user.lastSyncAt, }, { attempts: 3, backoff: { type: "exponential", delay: 5000 }, }); } } } class ExchangeSyncWorker { async processJob(job: Job<SyncJobData>) { const { userId, since } = job.data; const exchangeConnections = await this.db.getUserExchanges(userId); for (const connection of exchangeConnections) { try { const importer = this.importerFactory.create(connection.exchange); const transactions = await importer.importTransactions( connection.apiKey, connection.secretKey, since ); const normalized = transactions.map(tx => this.normalizer.normalize(tx)); const classified = await this.classifier.classifyBatch(normalized, userId); await this.db.upsertTransactions(userId, classified); await this.db.updateLastSync(userId, connection.exchange); } catch (err) { if (err instanceof ApiKeyExpiredError) { await this.notifyUserApiKeyExpired(userId, connection.exchange); } throw err; } } } } Типові помилки при інтеграції з біржовими API
- Закінчення API-ключа без повідомлення — система надсилає алерт.
- Неправильна обробка пагінації: деякі біржі повертають курсор, інші — offset. Наш імпортер уніфікує цей процес.
- Rate limits: перевищення ліміту призводить до блокування ключа. Ми використовуємо експоненціальну затримку та паралельні запити в межах лімітів.
- Невраховані типи транзакцій: наприклад, конвертації та стейкінг. Наші імпортери збирають всі типи операцій.
Підтримувані біржі
| Біржа | Метод | Обмеження |
|---|---|---|
| Binance | REST API (HMAC) | Rate limits, потрібен запит по кожній парі |
| Coinbase | OAuth 2.0 або API Key | Ліміти на history |
| Kraken | REST API | History обмежений |
| OKX | REST API | Хороше API |
| Bybit | REST API | Потрібні права на history |
| KuCoin | REST API | Пагінація по-своєму |
Як налаштувати автоматичний імпорт: покрокова інструкція
- Отримати API-ключі на кожній біржі, задавши мінімальні права (читання історії угод).
- Підключити ключі в нашій системі через захищений інтерфейс. Ключі шифруються та зберігаються в vault.
- Вибрати часовий діапазон для синхронізації (наприклад, з першого дня реєстрації на біржі).
- Налаштувати розклад синхронізації: за замовчуванням кожні 4 години, але можна задати будь-який інтервал.
- Перевірити дані через дашборд: відображаються останні імпортовані транзакції, помилки та статус підключень.
Що входить в роботу?
- Документація API — опис всіх ендпоінтів, форматів даних та процедури отримання ключів.
- Вихідний код імпортерів — кожна біржа як окремий модуль з тестами.
- Система моніторингу — повідомлення про помилки, збої API, закінчення ключів.
- Консультація з безпеки — рекомендації щодо зберігання API-ключів, налаштування прав.
Отримайте консультацію з інтеграції — обговоримо ваші біржі, обсяг даних та необхідний функціонал. Зв'яжіться з нами для оцінки вашого проекту.







