Исходный код
В количественном анализе и арбитраже ставки финансирования (Funding Rate) играют ключевую роль. Они определяют стоимость удержания позиций на рынке бессрочных фьючерсов и позволяют находить неэффективности между площадками. Однако последовательный опрос API нескольких бирж занимает слишком много времени, что недопустимо для высокочастотных стратегий.
Для решения этой задачи мы будем использовать асинхронный подход на базе библиотеки ccxt.async_support. Это позволит отправлять запросы к Binance, Bybit и OKX одновременно, сокращая общее время выполнения до скорости ответа самого медленного API.
Перед тем как разворачивать подобные скрипты в боевой среде, крайне важно протестировать их взаимодействие с биржами. Подробнее об этом вы можете прочитать в нашей статье Работа с Testnet API криптобирж в Python CCXT: Настройка.
Если вас интересует не только линейный деривативный рынок, но и опционы, рекомендуем ознакомиться с руководством Как извлечь исторические данные по опционам Deribit (Implied Volatility) с Python requests.
Кроме того, мониторинг рыночных аномалий и резких изменений ставок финансирования концептуально схож с отслеживанием критических событий в DeFi-сегменте. О методах такого мониторинга читайте в материале Мониторинг Flash Loan атак в Ethereum на Web3.py и Alchemy API.
Ниже представлен полный код асинхронного коллектора:
import asyncio
import ccxt.async_support as ccxt
import time
from typing import Dict, List, Any
SYMBOLS = ['BTC/USDT:USDT', 'ETH/USDT:USDT', 'SOL/USDT:USDT']
async def fetch_funding_for_exchange(exchange_id: str, symbols: List[str]) -> List[Dict[str, Any]]:
exchange_class = getattr(ccxt, exchange_id)
exchange = exchange_class({
'enableRateLimit': True,
'options': {
'defaultType': 'swap',
}
})
results = []
try:
await exchange.load_markets()
valid_symbols = [sym for sym in symbols if sym in exchange.markets]
if not valid_symbols:
return results
try:
rates = await exchange.fetch_funding_rates(valid_symbols)
for sym, rate_data in rates.items():
results.append({
'exchange': exchange_id,
'symbol': sym,
'funding_rate': rate_data.get('fundingRate'),
'timestamp': rate_data.get('timestamp'),
'datetime': rate_data.get('datetime')
})
except Exception:
tasks = []
for sym in valid_symbols:
tasks.append(exchange.fetch_funding_rate(sym))
rates_responses = await asyncio.gather(*tasks, return_exceptions=True)
for sym, resp in zip(valid_symbols, rates_responses):
if isinstance(resp, Exception):
continue
results.append({
'exchange': exchange_id,
'symbol': sym,
'funding_rate': resp.get('fundingRate'),
'timestamp': resp.get('timestamp'),
'datetime': resp.get('datetime')
})
except Exception as e:
print(f'Ошибка при работе с {exchange_id}: {e}')
finally:
await exchange.close()
return results
async def main():
exchanges = ['binance', 'bybit', 'okx']
start_time = time.time()
tasks = [fetch_funding_for_exchange(ex, SYMBOLS) for ex in exchanges]
all_results = await asyncio.gather(*tasks)
print(f'\nСбор завершен за {time.time() - start_time:.2f} сек.\n')
print('Биржа | Символ | Ставка % | Время обновления')
print('-' * 75)
for exchange_res in all_results:
for item in exchange_res:
rate = item['funding_rate']
rate_pct = f'{rate * 100:.4f}%' if rate is not None else 'N/A'
dt = item['datetime'] or 'N/A'
exchange_name = item['exchange'].upper()
symbol_name = item['symbol']
print(f'{exchange_name: