Ручний експорт 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-ключів, налаштування прав.
Отримайте консультацію з інтеграції — обговоримо ваші біржі, обсяг даних та необхідний функціонал. Зв'яжіться з нами для оцінки вашого проекту.







