Исходный код
Для реализации высокоскоростного арбитража критически важно использовать асинхронный подход и 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.




