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

Одна из таких стратегий - арбитраж ставок финансирования (funding rate arbitrage).

Этот материал - не обещание лёгких денег. Это разбор реальной рабочей системы, которую я сначала писал для себя, а позже обернул в Telegram-бота. Ниже я разберу:

  • как именно зарабатываются деньги на арбитраже ставок финансирования

  • почему ручной арбитраж не работает

  • как устроена архитектура алгоритмической системы

  • как код собирает данные, считает спреды и фильтрует мусор;

  • какие риски остаются и как их контролировать.

Автоматизированная торговая система может кратко упростить поиск грамотных связок между биржами и присылать уведомления. Я обернул эту систему в телеграм бота @Fandyng_Bot, логику которого мы сегодня и разберём - от получения данных с нескольких бирж, до обработки этой информации и практической значимости.

Что такое funding rate и откуда берётся доход

Funding rate - это периодический платёж между участниками рынка бессрочных фьючерсов. Он нужен, чтобы цена perpetual-контракта не отклонялась слишком сильно от спота.

Механика простая:

  • если funding положительный - платят держатели long-позиций;

  • если funding отрицательный - платят держатели short-позиций.

Ключевой момент: ставка финансирования отличается от биржи к бирже. Причём иногда - значительно.

Например, в один и тот же момент времени:

  • MEXC: -0.25%

  • Bitget: +0.0035%

Разница между ними - это и есть арбитражный спред, на котором мы можем заработать.

Почему направление цены здесь не важно

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

В арбитраже фандинга используется хедж-позиция:

  • long на одной бирже;

  • short на другой;

  • одинаковый объём;

В результате движение цены компенсируется, PNL по цене будет приблительно 0, а итоговый PNL позиции будет сформирован только фандингом.

Как на этом зарабатывают на практике

Процесс выглядит так:

  1. Найти актив, где funding на разных биржах сильно отличается.

  2. Открыть long там, где funding отрицательный.

  3. Открыть short там, где funding положительный.

  4. Дождаться выплаты фандинга.

  5. Закрыть обе позиции.

Прибыль = (Funding_short − Funding_long) − комиссии

Вот пример одной из связок, которая была найдена с помощью моей системы:

mexc
mexc
kucoin
kucoin

Суммарная прибыль составила 400$ и комиссионные съели около 112$ (учтено в PNL). Это пример хорошей удачной связки, которая отработала менее чем за несколько часов.

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

На бумаге всё выглядит просто, но в реальности бирж много, на каждой из них по несколько сотен разных тикеров, значения могут меняться за минуты

Ручной поиск не масштабируется, требует full-time мониторинга и мы физически не можем контролировать всё сразу = получим упущенные возможности, фомо, трудности с эмоциями.

Именно здесь появляется необходимость в автоматизации.

Общая логика системы

Система решает одну задачу - быстро находить качественные арбитражные связки.

Логика следующая:

  1. Собрать funding rate со всех бирж.

  2. Привести данные к единому формату.

  3. Отфильтровать неактуальные и шумовые значения.

  4. Посчитать разницу между биржами.

  5. Отдать трейдеру только те связки, где есть экономический смысл.

Вся архитектура построена вокруг этой последовательности.

Архитектура системы

Архитектура намеренно простая - без баз данных, брокеров сообщений и лишней магии.

1. Скрипты бирж

Для каждой биржи существует отдельный скрипт, который обращается к API биржи, получает список активных контрактов (фьючерсы), запрашивает ставку финансирования, сохраняет результат в текстовый файл, чтобы потом работать с этими данными.

Примеры файлов:

Binance.txt
ByBit.txt
KuCoin.txt
Hyperliquid.txt
...

Разбор кода

Давайте разберём, как получать данные на некоторых биржах. Для примера возьмём kucoin и hyperliquid. Со второй ситуация довольно интересная, ведь это не классический CEX.

Получение активных контрактов Kucoin

async def get_active_symbols():
    symbols = []
    async with aiohttp.ClientSession() as session:
        async with session.get(active_contracts_url, timeout=10) as response:
            data = await response.json()
            for contract in data.get('data', []):
                symbol = contract.get('symbol')
                    if symbol and symbol.endswith('M'):
                        symbols.append(symbol[:-1])
                        return symbols

Что здесь происходит:

Используем асинхронные запросы - это важно, так как работаем с большим количеством инструментов. Также работаем только с USDT-M/USDC-M контрактами, т.е. с активами к стейблкоинам. Добавляем все символы в список и возвращаем их.

Получение funding rate

async def fetch_funding_rate(session, symbol):
  url = funding_rate_url.replace('{symbol}', symbol + 'M')
  async with session.get(url, timeout=10) as response:
    data = await response.json()
    funding_rate = float(data['data']['value']) * 100
    return funding_rate

Здесь мы можем получить фандинг. Для удобства переводим его в проценты. Получаем сам фандинг мы, извлекая его из массива данных с помощью ключей ['data']['value']. Делаем всё также асинхронно, обрабатываем таймауты и не забываем передать в функцию правильно сам символ токена.

Пример нестандартного API: Hyperliquid

Hyperliquid — это децентрализованная биржа perpetual-фьючерсов на собственной L1-цепочке. В отличие от классических CEX вроде Binance или KuCoin, здесь нет привычного REST-API для получения списка контрактов и funding rates. Вместо этого используется единый эндпоинт /info, куда отправляются POST-запросы с JSON-payload'ом, указывающим тип запроса.

В системе используется специальная функция для отправки запросов:

def _post_info(payload: dict, timeout: int = 10) -> Any:
    data = json.dumps(payload).encode("utf-8")
    req = Request(
        HL_INFO_API,
        data=data,
        method="POST",
        headers={
            "Content-Type": "application/json",
            "User-Agent": "curl/8",
        },
    )
    with urlopen(req, timeout=timeout) as resp:
        raw = resp.read().decode("utf-8")
        try:
            return json.loads(raw)
        except Exception:
            return raw

Далее идёт запрос мета-данных и контекста активов:

def fetch_meta_and_asset_ctxs() -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
    resp = _post_info({"type": "metaAndAssetCtxs"})
    if not (isinstance(resp, list) and len(resp) >= 2):
        raise RuntimeError("Неверный ответ metaAndAssetCtxs: ожидался список из 2 элементов")
    meta_part = resp[0]
    ctxs_part = resp[1]
    if not (isinstance(meta_part, dict) and isinstance(ctxs_part, list)):
        raise RuntimeError("Неверный формат metaAndAssetCtxs: meta=dict, ctxs=list")
    ctxs: List[Dict[str, Any]] = [c for c in ctxs_part if isinstance(c, dict)]
    return meta_part, ctxs

Ответ содержит два элемента: мета-информацию (список всех активов с их именами, szDecimals и т.д.) и массив asset contexts. Funding rate для каждого актива находится в поле funding внутри соответствующего asset context (это значение в decimal, обычно очень маленькое, поэтому его умножаем на 100 для перевода в проценты). Также там есть previousFundingTimestamp и интервал (обычно 1 час), по которым рассчитывается время до следующей выплаты.

Такой подход позволяет одним запросом получить данные по всем активам сразу - это эффективно и быстро.

Расчёт спредов: как код находит прибыльные связки

После того как все скрипты бирж отработали и заполнили свои текстовые файлы (Binance.txt, ByBit.txt, KuCoin.txt и т.д.), запускается центральный скрипт, который собирает всё воедино и считает спреды.

Ключевые шаги скрипта:

  1. Чтение файлов - функция read_funding_file парсит строки вида BTC: 0.01% | Time: 12:00:00 для каждой биржи.

  2. Объединение данных - все записи по одному символу (например, BTCUSDT, ETHUSDT) собираются в один словарь.

  3. Приведение символов к единому виду - функция get_base_symbol отрезает USDT/USDC, чтобы связать, например, BTCUSDT с BTCUSDC или с BTC/USDT на разных биржах (это важно, потому что один и тот же актив может называться по-разному).

  4. Фильтрация по времени - учитывается только актуальный funding, соответствующий ближайшему часу выплаты (целевой час в UTC+3). Это отсекает устаревшие или несовпадающие по времени данные.

  5. Поиск экстремальных значений - для каждого актива находим максимально положительный и максимально отрицательный funding (в пределах разумных границ, например ±0.002%).

  6. Расчёт всех значимых спредов - сортируем отрицательные и положительные rates, перебираем пары и сохраняем только те, где разница ≥ порога (по умолчанию 0.01%).

  7. Запись в Raznitsa.txt - итоговый отчёт с удобным форматированием: символ, long-биржа (отрицательный funding), short-биржа (положительный), спред и время до выплаты.

    Давайте разберём код - сердце скрипта, который отвечает именно за расчёты и поиск спредов, для начала зададим константы фильтров и основные имена файлов для хранения фандинга:

# Константы фильтров
EXT_MIN_NEG = -0.002      # Считаем «отрицательным» только ≤ -0.002% (отсекаем шум)
EXT_MAX_POS =  0.002      # Считаем «положительным» только ≥ +0.002%
SP_THRESHOLD = 0.01       # Минимальный спред для раздела «Все спреды» (можно менять)

FILENAMES = [
    "Binance.txt", "Bitget.txt", "ByBit.txt",
    "CoinEx.txt",  "KuCoin.txt", "Gate.txt",
    "Hyperliquid.txt", "BingX.txt", "MEXC.txt", "OKX.txt"
]

OUTPUT_FILE = "Raznitsa.txt"

Как скрипт понимает, где какой актив

Самая частая проблема - разные биржи называют один и тот же контракт по-разному:

  • BTCUSDT на Binance

  • BTCUSDT на ByBit

  • BTC:USDT на Hyperliquid

  • BTCUSD на некоторых DEX

Функция get_base_symbol отрезает всё после USDT/USDC/USD и приводит к единому виду:

def get_base_symbol(sym: str) -> str:
    sym = sym.strip().upper()
    suffixes = ("USDT", "USDC", "BUSD", "TUSD", "USD")
    for s in suffixes:
        if sym.endswith(s):
            return sym[:-len(s)]
    return sym

Благодаря этому BTCUSDT, BTCUSD и 100BTCUSDT попадают в одну группу.

Фильтрация по времени выплаты

Не все биржи платят фандинг в одно и то же время. Большинство — каждые 8 часов (00:00, 08:00, 16:00 UTC), но есть и ежечасные (Hyperliquid, ByBit Inverse и др.).

Скрипт определяет ближайший «целевой час» в UTC+3 (Москва) и оставляет только те ставки, у которых время выплаты совпадает с этим часом.

def get_target_hour_str() -> str:
    now_utc = datetime.now(timezone.utc)
    tz3 = timezone(timedelta(hours=3))
    now_tz3 = now_utc.astimezone(tz3)
    # Округляем до следующего целого часа
    if now_tz3.minute != 0 or now_tz3.second != 0:
        target_hour = (now_tz3.replace(minute=0, second=0, microsecond=0) + timedelta(hours=1)).hour
    else:
        target_hour = now_tz3.hour
    return f"{target_hour:02d}:00:00"

Это критически важно: если у вас на одной бирже фандинг через 5 минут, а на другой - через 7 часов, спред будет ложный.

Поиск экстремальных значений (самые жирные связки)

Для каждого актива скрипт сначала ищет просто максимальный положительный и минимальный отрицательный funding (в разумных пределах ±0.002%). Это самые очевидные и обычно самые прибыльные связки.

def filter_extremes(entries, min_neg, max_pos):
    max_ent = None   # самая положительная ставка
    min_ent = None   # самая отрицательная ставка
    for exch, rate, raw, t in entries:
        if rate >= max_pos and (max_ent is None or rate > max_ent[1]):
            max_ent = (exch, rate, raw, t)
        if rate <= min_neg and (min_ent is None or rate < min_ent[1]):
            min_ent = (exch, rate, raw, t)
    return max_ent, min_ent

Поиск всех спредов ≥ порога

Если экстремальных нет, но есть несколько бирж с отрицательным и несколько с положительным - скрипт перебирает все возможные пары и сохраняет те, где разница ≥ 0.01%.

def find_spreads_extended(entries, threshold):
    results = []
    negs = sorted([e for e in entries if e[2] < 0], key=lambda x: x[2])  # от самого отрицательного
    poss = sorted([e for e in entries if e[2] > 0], key=lambda x: x[2])  # от самого маленького положительного

    for group in (negs, poss):
        for i in range(len(group)):
            le = group[i]
            for j in range(i+1, len(group)):
                se = group[j]
                diff = se[2] - le[2]
                if diff >= threshold:
                    results.append({ ... })
    return results

Это даёт больше возможностей, особенно когда на рынке мало экстремальных расхождений.

Формирование красивого отчёта

Файл Raznitsa.txt выглядит так:

# Отчёт обновлён: 2026-01-06 12:34:56 (целевой час UTC+3: 15:00:00)

## Экстремальные funding (min/max)

| BTCUSDT |
? Long ? MEXC: -0.124500% | ?15:00:00
? Short ? ByBit: +0.003100% | ?15:00:00
 Spread: 0.127600%

## Все спреды (diff ≥ 0.010000%)

| ETHUSDT |
? Long ? BingX: -0.045612% | ?—
? Short ? OKX: +0.012345% | ?15:00:00
 Spread: 0.057957%

Бот читает именно этот файл - никаких баз данных не нужно.

Главный цикл

if __name__ == "__main__":
    save_combined()        # первый запуск сразу
    while True:
        time.sleep(60)    # каждуб минуту
        save_combined()

Скрипт никогда не падает: если у одной биржи файл пустой или битый — просто пропустит её, остальные продолжат работать.

Эту часть можно легко модифицировать под себя:

  • изменить SP_THRESHOLD на 0.03%, если хотите только жирные связки;

  • добавить свои биржи в FILENAMES;

  • поменять пороги EXT_MIN_NEG/EXT_MAX_POS, если торгуете альткоины с дикими ставками.

Всё вместе даёт полностью автономную систему, которая 24/7 ищет деньги там, где 99% трейдеров даже не знают, что они есть.

Инструменты для работы с разными CEX-биржами

Чтобы архитектура бота не была жёстко привязана к одной площадке, на практике важно понимать, какие инструменты доступны для работы с другими централизованными биржами. Ниже — краткий обзор наиболее популярных CEX и их API-стека, с которыми можно реализовать аналогичную логику мониторинга фандинга и открытия хеджированных позиций.

Binance Futures

  • Тип API: REST + WebSocket

  • Фандинг: доступен через отдельные эндпоинты, включая историю и будущие ставки

  • Инструменты: python-binance, ccxt

  • Особенности: высокая ликвидность, быстрые WebSocket-потоки, но строгие лимиты и агрессивный rate-limit

Bybit

  • Тип API: REST + WebSocket

  • Фандинг: удобный доступ к текущему и ожидаемому funding rate

  • Инструменты: pybit, ccxt

  • Особенности: хорошая документация, стабильная работа с деривативами, популярна для funding-стратегий

OKX

  • Тип API: REST + WebSocket

  • Фандинг: отдельные методы для perpetual-свопов

  • Инструменты: официальный SDK, ccxt

  • Особенности: сложнее модель аккаунта, но широкий выбор инструментов и пар

BingX

  • Тип API: REST

  • Фандинг: доступен, но с меньшей детализацией

  • Инструменты: неофициальные Python-клиенты, прямые REST-запросы

  • Особенности: проще инфраструктура, подходит для мониторинга и вспомогательных стратегий

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

Telegram-бот: как трейдер получает уведомления

Финальный этап — Telegram-бот (@Fandyng_Bot). Он читает Raznitsa.txt, хранит настройки пользователей (порог спреда, автоматические уведомления) в отдельном файле.

Возможности:

  • Установка личного порога (например, уведомлять только о спредах ≥ 0.05%).

  • Ручной запрос текущих связок.

  • Автоматические push-уведомления, как только появляется подходящая возможность.

  • Мониторинг подписки (чтобы бот работал только для платных пользователей).

Это решает главную проблему ручного арбитража — скорость. Вы получаете алерт за минуты до выплаты, открываете хедж-позиции и фиксируете прибыль.

Риски и как их минимизировать

Даже в хеджированной позиции риски остаются:

  • Изменение funding → до выплаты ставка может резко поменяться. Решение: входить за 5–10 минут до funding time.

  • Ликвидация → сильное движение цены может ликвидировать одну из сторон при высоком плече. Решение: использовать низкое плечо (1x–3x) или cross-маржу.

  • Комиссии и проскальзывание → съедают спред, особенно на низколиквидных активах. Решение: считать net profit с учётом taker/maker fees и открывать позиции частями.

  • Разные времена выплат → не все биржи платят в 00:00/08:00/16:00 UTC. Код фильтрует по совпадению времени.

В целом, при дисциплине и достаточном капитале (от $10k+) это одна из самых стабильных стратегий на крипто-рынке без directional риска.

Если вы хотите попробовать - начните с бота @Fandyng_Bot, протестируйте на небольших объёмах и убедитесь, что понимаете все нюансы. В боте хотя и есть подписка, но она символичная, чтобы не перегружать системы и не падать от ботов. Для абсолютно всех есть тестовый период, так что этот проект даже тяжело назвать коммерческим. Удачных связок!

Комментарии (1)


  1. anyagixx
    06.01.2026 09:49

    Криптаны, что бы вы не высирали, итог будет один, вы сольете свой депозит и все якобы заработанное. Заработанные деньги это те которые ты вытащил и освоил, а все эти пнл, балансы, кошелки это деньги которые в рынке, они не твои