Треугольный арбитраж на OKX: Python скрипт для Triangular Arbitrage

Треугольный арбитраж на OKX: Python скрипт для Triangular Arbitrage Python & API
Пошаговое руководство по созданию скрипта для внутрибиржевого треугольного арбитража на спотовом рынке OKX с использованием Python и CCXT Pro.
Суть: В данной статье мы разберем архитектуру и напишем готовый асинхронный Python-скрипт для поиска и реализации возможностей треугольного арбитража (Triangular Arbitrage) на спотовом рынке биржи OKX с использованием библиотеки CCXT Pro. Мы настроим подписку на WebSocket-вещание стаканов, рассчитаем цепочки с учетом торговых комиссий и подготовим базу для исполнения ордеров.

Исходный код

Для реализации высокоскоростного арбитража критически важно использовать асинхронный подход и WebSocket-соединения. Обычные REST-запросы слишком медленны для захвата мимолетных неэффективностей рынка. В нашем скрипте мы задействуем библиотеку ccxt.pro для параллельного получения обновлений стаканов (Order Book L2) по трем торговым парам, образующим замкнутый треугольник (например, ETH/USDT, BTC/USDT и ETH/BTC).

Для минимизации задержек при обработке стаканов в распределенных системах часто применяется Интеграция Redis для кэширования стакана ордеров L2 на Python. Также, если вы планируете расширять стек поддерживаемых бирж и методов, рекомендуем ознакомиться со статьей про Создание кастомного адаптера CCXT.Pro для парсинга ликвидаций Bitget.

import asyncio
import ccxt.pro as ccxtpro

# Инициализация биржи OKX
exchange = ccxtpro.okx({
    'enableRateLimit': True,
    'options': {
        'defaultType': 'spot',
    }
})

# Комиссия спота OKX по умолчанию для Taker-ордеров (0.1% = 0.001)
TAKER_FEE = 0.001
orderbooks = {}

async def watch_symbol(symbol):
    while True:
        try:
            orderbook = await exchange.watch_order_book(symbol)
            orderbooks[symbol] = orderbook
        except Exception as e:
            print(f'Ошибка при получении стакана {symbol}: {e}')
            await asyncio.sleep(1)

async def arbitrage_loop():
    symbols = ['BTC/USDT', 'ETH/USDT', 'ETH/BTC']
    while len(orderbooks) < len(symbols):
        print('Ожидание получения стаканов...')
        await asyncio.sleep(2)

    print('Все стаканы получены. Запуск мониторинга...')
    while True:
        try:
            # Извлекаем лучшие цены (bids/asks)
            ask_btc_usdt = orderbooks['BTC/USDT']['asks'][0][0]
            ask_eth_btc = orderbooks['ETH/BTC']['asks'][0][0]
            bid_eth_usdt = orderbooks['ETH/USDT']['bids'][0][0]

            initial_usdt = 100.0

            # Прямой путь: USDT -> BTC -> ETH -> USDT
            # Шаг 1: Покупаем BTC за USDT
            btc_amount = (initial_usdt / ask_btc_usdt) * (1 - TAKER_FEE)
            # Шаг 2: Покупаем ETH за BTC
            eth_amount = (btc_amount / ask_eth_btc) * (1 - TAKER_FEE)
            # Шаг 3: Продаем ETH за USDT
            final_usdt = (eth_amount * bid_eth_usdt) * (1 - TAKER_FEE)

            profit_pct = ((final_usdt - initial_usdt) / initial_usdt) * 100

            if profit_pct > 0:
                print(f'[ПРОФИТ] Путь: USDT -> BTC -> ETH -> USDT | Доходность: {profit_pct:.4f}%')
                print(f'Детали: Ask BTC/USDT: {ask_btc_usdt}, Ask ETH/BTC: {ask_eth_btc}, Bid ETH/USDT: {bid_eth_usdt}')
            else:
                # Обратный путь: USDT -> ETH -> BTC -> USDT
                ask_eth_usdt = orderbooks['ETH/USDT']['asks'][0][0]
                # Шаг 1: Покупаем ETH за USDT
                eth_amount_rev = (initial_usdt / ask_eth_usdt) * (1 - TAKER_FEE)
                # Шаг 2: Продаем ETH за BTC
                bid_eth_btc = orderbooks['ETH/BTC']['bids'][0][0]
                btc_amount_rev = (eth_amount_rev * bid_eth_btc) * (1 - TAKER_FEE)
                # Шаг 3: Продаем BTC за USDT
                bid_btc_usdt = orderbooks['BTC/USDT']['bids'][0][0]
                final_usdt_rev = (btc_amount_rev * bid_btc_usdt) * (1 - TAKER_FEE)

                profit_pct_rev = ((final_usdt_rev - initial_usdt) / initial_usdt) * 100
                if profit_pct_rev > 0:
                    print(f'[ПРОФИТ] Обратный путь: USDT -> ETH -> BTC -> USDT | Доходность: {profit_pct_rev:.4f}%')
                    print(f'Детали: Ask ETH/USDT: {ask_eth_usdt}, Bid ETH/BTC: {bid_eth_btc}, Bid BTC/USDT: {bid_btc_usdt}')

            await asyncio.sleep(0.1)
        except Exception as e:
            print(f'Ошибка в цикле арбитража: {e}')
            await asyncio.sleep(1)

async def main():
    symbols = ['BTC/USDT', 'ETH/USDT', 'ETH/BTC']
    tasks = [watch_symbol(symbol) for symbol in symbols]
    tasks.append(arbitrage_loop())
    await asyncio.gather(*tasks)

if __name__ == '__main__':
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print('Скрипт остановлен пользователем.')
    finally:
        asyncio.run(exchange.close())

Разбор параметров

  • TAKER_FEE: Размер торговой комиссии биржи для Taker-ордеров. На спотовом рынке OKX стандартная комиссия составляет 0.1% (или 0.001 в долях). Учет комиссий критически важен, так как они могут полностью поглотить математическое преимущество арбитражной цепочки.
  • orderbooks: Глобальный словарь для хранения актуальных срезов стаканов по выбранным торговым парам. Обновляется асинхронно через WebSocket-соединение.
  • watch_symbol: Асинхронная функция, которая подписывается на поток обновлений стакана конкретного инструмента с помощью метода watch_order_book библиотеки CCXT Pro.
  • arbitrage_loop: Основной рабочий цикл, выполняющий расчет кросс-курсов для прямого и обратного направлений треугольника, а также вычисляющий чистую доходность с учетом комиссий.
  • exchange: Экземпляр класса ccxtpro.okx, инициализирующий асинхронное подключение к API биржи OKX.

Как запустить

Для запуска скрипта вам понадобится установленный интерпретатор Python версии 3.8 или выше, а также библиотека CCXT Pro. Обратите внимание, что для работы с WebSocket-соединениями в CCXT требуется коммерческая лицензия CCXT Pro, либо вы можете адаптировать код под стандартную бесплатную версию CCXT, используя частые REST-запросы (что снизит скорость работы).

Установите необходимые зависимости в вашем виртуальном окружении:

pip install ccxt asyncio

Сохраните код скрипта в файл с именем triangular_arbitrage.py и запустите его из терминала:

python triangular_arbitrage.py

Для полноценной автоматизации торговли и своевременного информирования о результатах работы алгоритма, рекомендуем настроить уведомления. В этом вам поможет подробная инструкция: Интеграция Python скрипта с Telegram Bot API для отправки PnL отчета CCXT.

Оцените статью
FinFluct