Блог им. RomellaAkumov

Создаём скринер для арбитража ставок финансирования для получения почти безрисковой доходности.

Введение: что такое арбитраж по ставке финансирования

На крипто рынке у бессрочных фьючерсов существует специальный механизм: ставка финансирования (funding rate) — периодический платёж между держателями длинных (long) и коротких (short) позиций, который служит для выравнивания цены фьючерса с ценой спота.

Арбитраж по ставке финансирования — стратегия, цель которой не столько угадать движение цены, сколько извлечь выгоду из разницы в ставках финансирования на разных площадках или между контрактом и спотом.
Например: если фьючерс на актив торгуется с положительной ставкой +0.03 % за период, то держатели short получают оплату от long. Арбитражер может занять длинную позицию на споте и короткую на фьючерсе, тем самым оставаясь почти нейтральным к движению цены, и получать платёж по ставке. Или — если ставка отрицательная (short платят long) — можно действовать наоборот: short спот и long фьючерс.

Зачем это нужно и когда работает

  • Это стратегия с относительно низкой ориентированной на движение цены риском

  • Возможности возникают, когда ставка финансирования отклоняется от нуля или есть разница между площадками.

  • Нужно учитывать: сборы, проскальзывание, ликвидационный риск, требования маржи, переключения механизмов ставок.

  • Для начинающих важно понимать: это не «гарантированная» прибыль, а механизм, требующий мониторинга, автоматизации и расчёта.

Для автоматизации нахождения таких «расхождений» ставок финансирования я решил написать скрипт, который будет это делать за меня. Взял биржи: binance, bybit, mexc, okx. Торговля будет ручная, так как тут тоже важна насмотренность и анализ чарта — допустим, если монета улетела на сотни процентов, то лучше стоит ее просто пропустить.

Подробное описание скриптов и логики их работы

В этой части мы разберём внутреннюю архитектуру проекта — как устроены скрипты, какие API используются, как рассчитывается потенциальная прибыль и как всё это работает вместе. Проект состоит из менеджера скринеров и четырёх отдельных скринеров для бирж. Каждый скринер автономен, но следует единой логике.

1. main.py — Менеджер скринеров

Для начала создаем сердце проекта — main.py будет отвечать за координацию скриптов и логирование. Сразу импортируем будущие скрипты — MexcScreener.py и т.п. для удобства, чтобы не возвращаться сюда позже.

<code>import logging 
from screeners.mexc_screener import MexcScreener
from screeners.bybit_screener import BybitScreener
from screeners.okx_screener import OkxScreener
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class ScreenerManager:
    def __init__(self):
        self.screeners = [MexcScreener(), BybitScreener(), OkxScreener(), BinanceScreener()]

    def run_screeners(self):
        all_results = []
        for screener in self.screeners:
            data = screener.run()
            data = data[:20]  # Берём только топ-20

            result = {
               'ex_name': screener.name,
               'coins': data
            }
            all_results.append(result)
        
        # Запись в файл
        with open('results.txt', 'w') as f:
            for exchange in all_results:
               f.write(f"============ Top {len(exchange['coins'])} coins in {exchange['ex_name']} ============\n")
               for coin in exchange['coins']:
                  f.write(f"{coin['ticker']}. Funding rate: {coin['funding_rate']} - Potential Profit: {coin['potential_profit']:.6%}\n")
        
        return all_results</code>

 

Что делает:

  1. Инициализирует все скринеры.

  2. Запускает .run() у каждого.

  3. Обрезает результат до топ-20 по potential_profit.

  4. Формирует человекочитаемый отчёт в results.txt.

  5. Логирует процесс через logging.

2. Базовая логика всех скринеров (общее ядро)

Каждый скринер следует одинаковому алгоритму:

Шаг

Описание

1

Получить список всех перпетульных контрактов

2

Для каждого — получить текущую ставку финансирования

3

Рассчитать потенциальную прибыль = funding_rate − комиссии

4

Отсортировать по убыванию прибыли

5

Вернуть топ-N (в нашем случае — 20)

3. bybit_screener.py — Bybit

Ключевые эндпоинты для запросов к api:

Эндпоинт

Что делает

GET /v5/market/instruments-info?category=linear

Все линейные перпетульные контракты (USDT-маржа)

GET /v5/market/funding/history?symbol=BTCUSDT&limit=1

Последняя ставка финансирования

Базовый url для формирования запросов — "https://api.bybit.com"

Важно: Bybit не отдаёт все funding rates одним запросов, нужно запрашивать по символу.

Блок 1: Импорты и настройка логирования

<code>import requests, time, decimal, logging
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from typing import Dict, Any, List
import re</code>

Что делает: Подключает библиотеки для работы с API (requests), параллельного выполнения (ThreadPoolExecutor), точных вычислений с денежными величинами (decimal), работы с датами и логирования.

Блок 2: Класс BybitScreener и инициализация

<code>class BybitScreener:
    BASE_URL = "https://api.bybit.com"
    FUNDING_RATE_ENDPOINT = "/v5/market/funding/history"
    INSTRUMENTS_INFO_ENDPOINT = "/v5/market/instruments-info"

    def __init__(self):
        self.name = 'Bybit'
        self.contracts = self.get_all_contracts()
        logger.info(f"Initialized with Bybit Screener{len(self.contracts)} contracts")</code>

Что делает:

  • Определяет скринер для Bybit с базовым URL и необходимыми endpoint.

  • При создании объекта автоматически загружает список всех контрактов

  • Логирует количество доступных контрактов.

Блок 3: Получение списка контрактов

<code>def get_all_contracts(self) -> List[Dict[str, Any]]:
        url = f"{self.BASE_URL}{self.EXCHANGE_INFO_ENDPOINT}"
        response = requests.get(url)
        response.raise_for_status()
        contracts = []
        for symbol in response.json()['symbols']:
            if symbol['contractType'] == 'PERPETUAL':
                contracts.append({
                    'symbol': symbol['symbol'],
                    'takerFeeRate': decimal.Decimal(symbol.get('takerFee', '0')),
                    'makerFeeRate': decimal.Decimal(symbol.get('makerFee', '0'))
                })
        return contracts</code>

Что делает:

  • Отправляет запрос к API Bybit для получения всех линейных контрактов.

  • Исключает фьючерсы с датой экспирации (не подходят для арбитража).

  • Для каждого контракта сохраняет символ и комиссии (makerFeeRate и takerFeeRate).

  • Возвращает список контрактов для дальнейшего анализа.

Блок 4: Проверка экспирации контрактов

<code>def is_future_dated_contract(self, symbol: str, current_date: datetime) -> bool:
      match = re.search(r'-(\d{2})([A-Z]{3})(\d{2})$', symbol)
      if match:
         day, month, year = match.groups()
         contract_date = datetime.strptime(f"20{year}-{month}-{day}", "%Y-%b-%d")
         return contract_date > current_date
      return False</code>

Что делает:

  • Проверяет тикер контракта на наличие даты экспирации.

  • Использует регулярные выражения, чтобы понять, является ли контракт будущим фьючерсом.

  • Возвращает True, если контракт истечёт позже текущей даты.

Блок 5: Получение текущей funding rate

<code>    def get_current_funding_rate(self, symbol: str) -> decimal.Decimal:
        url = f"{self.BASE_URL}{self.FUNDING_RATE_ENDPOINT}"
        params = {"symbol": symbol, "category": "linear", "limit": 1}
        try:
            response = requests.get(url, params=params)
            response.raise_for_status()
            funding_rate_data = response.json()['result']['list'][0]
            return self.format_funding_rate(funding_rate_data)
        except (requests.exceptions.HTTPError, IndexError, KeyError) as e:
            logger.warning(f"Error fetching funding rate for {symbol}: {e}")
            return decimal.Decimal('0')</code>

Что делает:

  • Отправляет запрос к API Bybit, чтобы получить последнюю ставку финансирования.

  • Обрабатывает ошибки запроса и пустые данные.

Блок 6: Форматирование funding rate и расчёт прибыли

<code>    def format_funding_rate(self, funding_rate_data):
        funding_rate = funding_rate_data.get('fundingRate', '0')
        return decimal.Decimal(funding_rate).quantize(decimal.Decimal('1E-6'))

    def calculate_potential_profit(self, funding_rate: decimal.Decimal, contract: Dict[str, Any]) -> decimal.Decimal:
        total_fee = contract['makerFeeRate'] * 2
        return funding_rate - total_fee</code>

Что делает:

  • Преобразует строковое значение funding rate в Decimal.

  • Округляет до 6 знаков после запятой для удобства отображения и расчётов.

  • Учитывает комиссии биржи (двойную maker fee) при расчёте потенциальной прибыли.

  • Возвращает реальный доход, который можно получить после оплаты комиссий.

Блок 7: Анализ funding rates

<code>    def analyze_funding_rates(self):
        funding_rates = []
        with ThreadPoolExecutor(max_workers=5) as executor:
            futures = {executor.submit(self.get_current_funding_rate, contract['symbol']): contract for contract in self.contracts}
            for future in as_completed(futures):
                contract = futures[future]
                try:
                    rate = future.result()
                    potential_profit = self.calculate_potential_profit(rate, contract)
                    funding_rates.append({
                        'ticker': contract['symbol'],
                        'funding_rate': rate,
                        'potential_profit': potential_profit
                    })
                except Exception as e:
                    logger.error(f"Error analyzing {contract['symbol']}: {e}")
        
        sorted_rates = sorted(funding_rates, key=lambda x: x['potential_profit'], reverse=True)
        return sorted_rates</code>

Что делает:

  • Параллельно запрашивает funding rate для всех контрактов через ThreadPoolExecutor.

  • Вычисляет потенциальную прибыль для каждого контракта.

  • Сортирует контракты по potential_profit по убыванию.

  • Возвращает список самых прибыльных контрактов.

Блок 9: Запуск скринера

<code>def run(self):
    logger.info("Starting BybitScreener")
    try:
        best_contracts = self.analyze_funding_rates()
        logger.info(f"BybitScreener completed. Found {len(best_contracts)} contracts.")
        return best_contracts
    except Exception as e:
        logger.error(f"An error occurred during BybitScreener execution: {e}")
        return []</code>

Что делает:

  • Объединяет все функции: загружает контракты, анализирует их funding rate, сортирует по доходности.

  • Логирует успешное завершение или ошибки выполнения.

  • Возвращает готовый список контрактов с потенциальной прибылью.

Остальные скринеры

Все остальные скрипты следуют аналогичной логике — разве что отличаются эндпоинты и подобные ньюансы. Для того, чтобы не томить читателей кодом, все остальные скринеры загружены на github - https://github.com/kir1l/Funding-Arbitrage-Screener

Вывод

По итогу, запустив скрипт мы получим вывод с лучшими монетками на биржах, и уже там можно будет собирать фандинг.

Ключ к успешному арбитражу — хеджирование: открытие противоположной позиции минимизирует ценовой риск, а прибыль формируется только за счёт funding rate. При этом важно учитывать комиссии, проскальзывание и требования маржи.

Аарбитраж ставок финансирования позволяет извлекать доход с относительно низким риском, используя автоматизированные скринеры для мониторинга возможностей на разных биржах. Хотя и от вас будет зависить многое — важна скорость принятия решений и возможность находится у терминала, но всё же такой терминал сильно упростит работу по арбитражу ставок финансирования.

Данная публикация является личным мнением автора. Мнение владельца сайта может не совпадать с мнением автора.
1.1К | ★1

Читайте на SMART-LAB:
Золото пытается возобновить рост, другие драгметаллы дешевеют 
С начала торгов 17 июля золото растет в цене на 0,22%, до $4000,9 за тройскую унцию, серебро корректируется на 0,8%, до $55,74. При этом платина...
Фото
«Черный понедельник»: что будет в день дивотсечек «Сбера» и ВТБ?
Российский рынок падает 19-ю неделю подряд, в четверг «под занавес» вечерней сессии индекс МосБиржи оказался ниже 2000 пунктов впервые с...
Фото
Один из лучших ИИ на планете уже доступен алготрейдерам России. Kimi K3
Итак, вчера вышла новая китайская модель с открытыми весами. Kimi K3. Выше только Fable и GPT-5.6. И то не во всех тестах. Вся...
Фото
Портовый срез #7: НМТП отгружает рекордные объемы, но все боятся остановки судоходства в Черном море - смотрим на факты
Порты России вместо привычной сверхмаржи и дохода для инвесторов стали мишенью для БПЛА противника. Перестали ли из-за этого они быть...

теги блога Roman crypto_maniac

....все тэги



UPDONW
Новый дизайн