Парсинг данных 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/минуту, этот endpoint стоит 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); // max 5 concurrent requests
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;
// Respect 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% — явная ошибка данных
}
Расписание сбора и monitoring
Исторические данные: initial backfill при запуске системы (может занять несколько часов для полной истории по всем символам). После — incremental update каждые 8 часов (после settlement) плюс real-time через WebSocket.
Мониторинг:
- Freshness: если последняя запись для символа старше 9 часов — алерт (пропустили settlement)
- Gap detection: проверяем continuity последовательности timestamp (шаг должен быть ровно 8h или кратен)
- Collection lag: время между settlement на бирже и появлением в нашей БД
Реалистичный срок разработки коллектора для 5–6 бирж с историческим бэкфиллом и API: 4–6 недель.







