Блог им. 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. При этом важно учитывать комиссии, проскальзывание и требования маржи.

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

793 | ★1

Читайте на SMART-LAB:
Фото
Актуальный состав портфеля и взгляд на рынок 2026: по-прежнему 0% позитива.
Добрый вечер! С момента предыдущего поста, касающегося моего портфеля, прошел квартал.  Пришло время актуализировать его состав. Также поделюсь...
Фото
Биткоин попробует разыграть «треугольную карту»?
«Цифровое золото» прорвало верхнюю границу восходящего треугольника на уровне 94 500 и сейчас тестирует пробитую горизонталь, формируя серию...
Фото
Индикатор Fractal: торговые сигналы и робот для OsEngine. Видео
В этом видео разбираем индикатор Fractal Билла Вильямса — один из самых известных инструментов в трейдинге. Покажем, как формируются фракталы,...
Фото
Стратегия 2026 по рынку акций от Mozgovik Research: трудный год, но, возможно, последний год низких цен
Сегодня у меня первый день официального отпуска. За окном темная звездная ночь, яркая белая луна, +24С и шум волн Андаманского моря. Неудачный...

теги блога Roman crypto_maniac

....все тэги



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