Парсинг даних Funding Rate з бірж
Funding rate — це механізм балансування perpetual futures. Кожні 8 годин (на більшості централізованих бірж) або безперервно (на деяких) трейдери з довгими позиціями платять трейдерам з короткими або навпаки, залежно від того, торгується ли контракт з премією або дисконтом до спот-ціни. Для quant-стратегій, арбітражерів й risk-менеджерів historical й real-time funding rate дані критичні — це один з основних сигналів про настрої ринку.
Джерела даних: біржі й їх API
Централізовані біржі
Binance — найбільший обсяг perpetuals:
GET https://fapi.binance.com/fapi/v1/fundingRate
?symbol=BTCUSDT&limit=1000&startTime={ms}&endTime={ms}
Повертає історію по 1000 записів за запит. Rate limit: 2400 weight/хвилина, цей ендпоінт коштує 1 weight. Повна історія доступна з моменту листингу.
Bybit:
GET https://api.bybit.com/v5/market/funding/history
?category=linear&symbol=BTCUSDT&limit=200
Пагінація через cursor у ответі, не за timestamp.
OKX:
GET https://www.okx.com/api/v5/public/funding-rate-history
?instId=BTC-USDT-SWAP&limit=100&before={ts}&after={ts}
Hyperliquid (децентралізований perpetuals):
POST https://api.hyperliquid.xyz/info
Content-Type: application/json
{"type": "fundingHistory", "coin": "BTC", "startTime": 1700000000000}
WebSocket для real-time
Real-time funding rate (поточний, до наступного settlement):
Binance WebSocket:
const ws = new WebSocket("wss://fstream.binance.com/ws/btcusdt@markPrice@1s");
ws.onmessage = (e) => {
const data = JSON.parse(e.data);
// data.r — поточний funding rate
// data.T — час наступного funding (ms)
};
Bybit WebSocket:
ws.send(JSON.stringify({
op: "subscribe",
args: ["tickers.BTCUSDT"]
}));
// У ответі: fundingRate й nextFundingTime
Реалізація колектора
Базовий колектор з retry й rate limiting
import pLimit from "p-limit";
import axiosRetry from "axios-retry";
class FundingRateCollector {
private readonly limit = pLimit(5); // макс 5 одночасних запитів
constructor(private readonly config: ExchangeConfig) {
axiosRetry(this.http, {
retries: 3,
retryDelay: axiosRetry.exponentialDelay,
retryCondition: (err) =>
axiosRetry.isNetworkError(err) ||
err.response?.status === 429 ||
err.response?.status >= 500,
});
}
async fetchHistorical(
symbol: string,
from: Date,
to: Date
): Promise<FundingRateRecord[]> {
const results: FundingRateRecord[] = [];
let cursor = from.getTime();
while (cursor < to.getTime()) {
const batch = await this.limit(() =>
this.fetchBatch(symbol, cursor, to.getTime())
);
if (batch.length === 0) break;
results.push(...batch);
cursor = batch[batch.length - 1].timestamp + 1;
// Дотримуємось rate limits
await delay(this.config.requestDelayMs);
}
return results;
}
}
Нормалізація даних
Кожна біржа повертає різний формат. Нормалізована структура:
interface FundingRateRecord {
exchange: string; // "binance", "bybit", "okx", "hyperliquid"
symbol: string; // нормалізований: "BTC-USDT"
originalSymbol: string; // як на бірже: "BTCUSDT", "BTC-USDT-SWAP"
timestamp: number; // unix ms — час settlement
fundingRate: number; // decimal, наприклад 0.0001 = 0.01%
annualizedRate: number; // fundingRate * 3 * 365 (3 розрахунки на день)
markPrice?: number; // ціна в момент розрахунку
}
Annualized rate важливий для арбітражної аналітики: якщо annualized funding > 30%, cash-and-carry арбітраж (лонг спот + шорт perp) потенційно вигідний.
Обробка символів
Один й той же актив на різних біржах називається по-різному:
- Binance:
BTCUSDT(futures),BTCUSD_PERP(coin-margined) - Bybit:
BTCUSDT(linear),BTCUSD(inverse) - OKX:
BTC-USDT-SWAP,BTC-USD-SWAP
Потрібна таблиця маппінгу символів:
CREATE TABLE symbol_mapping (
normalized_symbol VARCHAR(20) NOT NULL, -- "BTC-USDT"
exchange VARCHAR(20) NOT NULL,
exchange_symbol VARCHAR(30) NOT NULL,
contract_type VARCHAR(10) NOT NULL, -- "linear", "inverse"
PRIMARY KEY (exchange, exchange_symbol)
);
Зберігання та доступ до даних
Схема БД
CREATE TABLE funding_rates (
id BIGSERIAL,
exchange VARCHAR(20) NOT NULL,
symbol VARCHAR(20) NOT NULL,
settled_at TIMESTAMPTZ NOT NULL,
funding_rate DECIMAL(18, 10) NOT NULL,
mark_price DECIMAL(24, 8),
PRIMARY KEY (id),
UNIQUE (exchange, symbol, settled_at)
) PARTITION BY RANGE (settled_at);
-- Індекс для типових запитів
CREATE INDEX idx_funding_symbol_time
ON funding_rates (symbol, settled_at DESC);
TimescaleDB hypertable для автоматичного партиціонування за часом й компресії старих даних.
Аномалії й валідація
Funding rate рідко виходить за межи ±0.3% за 8 годин при нормальних умовах. Екстремальні значення (FTX в останні дні, LUNA collapse) — до кількох відсотків. Валідація при вставці:
function validateFundingRate(rate: number, exchange: string, symbol: string): boolean {
if (Math.abs(rate) > 0.03) { // > 3% це аномалія
logger.warn(`Extreme funding rate detected`, { exchange, symbol, rate });
// Не відбрасуємо — може бути реальною екстремальною подією
// Помічаємо флагом для ручної перевірки
return true; // але зберігаємо
}
return Math.abs(rate) <= 1.0; // > 100% — явна помилка даних
}
Расписання збирання й моніторинг
Історичні дані: initial backfill при запуску системи (може тривати кілька годин для повної історії по всіх символам). Після — incremental update кожні 8 годин (після settlement) плюс real-time через WebSocket.
Моніторинг:
- Freshness: якщо остання запис для символу старіша за 9 годин — alert (пропустили settlement)
- Gap detection: перевіряємо continuity послідовності timestamp (крок повинен бути рівно 8h або кратен)
- Collection lag: час між settlement на бірже й появою в нашій БД
Реалістичний срок розробки колектора для 5–6 бірж з історичним бэкфіллом і API: 4–6 тижнів.







