Внутренний арбитраж - часть 2. Охота на сусликов

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

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

Изменения с точки зрения программирования

В процессе подготовки прошлой статьи стало ясно, что это одна из тех задач, с которой питону справиться сложновато – тут нужна большая скорость просчета и получения данных, и более-менее шустрая многопоточность. Это нормальный цикл производства, с моей точки зрения –сначала ты пишешь быстро, просто и весело на Питоне, проседаешь в скорости и производительности, но проверяешь работу алгоритма и ценность идеи вообще, добавляешь вские фишки и ходишь по всевозможным граблям, о которых раньше и подумать не мог, а потом, когда и если ты упираешься в производительность языка (обычно до этого не доходит, т.к. большинство идей сами по себе отстойные), переводишь свои наработки на что-то, похожее на C++. В данном случае чем-то похожим на C++ стал Golang.

Мне давно хотелось опробовать этот язык в бою, т.к. у него есть некоторые киллер-фичи:

  1. Скорость разработки на нем довольно высока
  2. Умеет хорошо параллелиться
  3. Компилируемый
  4. Встроенные средства для работы с вебом, разбора JSON, шифрования и т.п.
  5.  На нем круто делать всякие микросервисы
  6. Он модный
  7. Он кроссплатформенный (можно писать код на винде а компилировать под линуксом и наоборот)
  8. Самый главный пункт – мне было любопытно

Забегая вперед – если вы хотите писать софт на заказ, то можете присмотреться к этому языку – на выходе вы будете отдавать клиенту единый *.exe файл, который не раскрывает деталей реализации кода, алгоритмов и не требует установки дополнительного ПО.

Итак, язык был выбран, пришло время изменять алгоритм работы внутреннего арбитража. Вот какие улучшения пришлось мне сделать:

  1. На старте для каждой пары выделяем память, в этой памяти держим структуру данных: Название пары, лучшую цену и объем ask, лучшую цену и объем bid, стакан ask, стакан bid и прочую служебную информацию (об этом ниже).
  2. Нет смысла на лету искать цепочки торговли. На старте программы нужно получать список всех пар, строить цепочки и работать в дальнейшем с ними. Тут может возникнуть довольно маловероятный риск, что какие-то пары будут запрещены во время работы бота, поэтому нужно этот список время от времени актуализировать. Каждый элемент цепочки ссылается на пару, для которой уже выделена память (и которая содержит актуальные курсы), а также содержит тип сделки – BUY или SELL.
  3. Для упрощения и ускорения программы я сделал так, что каждая сделка начинается с покупки (Например, имея BTC мы покупаем монету X) и заканчивается продажей (Мы продаем купленную посередине монету Y и выручаем обратно BTC).
  4. Все, абсолютно все сделки должны быть проведены по рынку. Нет смысла ждать у моря погоды, когда курс пойдет в нужную сторону. С этим связано сразу несколько моментов, которые нужно учесть:

Выставление ордеров на Binance осуществляется через запрос к rest api, и сделка может произойти:

      1. Моментально – Мы отправили запрос к rest api, сервер нам вернул ответ, что сделка уже прошла, и её результат. В этом случае нет необходимости запрашивать уточненную информацию по ордеру.
      2. Протяженно по времени – мы отправили запрос через rest api, сервер биржи создал ордер и вернул нам номер, а через несколько миллисекунд этот ордер исполнился. В этом случае можно было бы бесконечно опрашивать биржу на предмет состояния ордера, но можно поступить оптимальнее – подписаться через web-сокеты на события изменения ордеров. Теперь, каждый раз, когда ордер создастся, и/или как-либо изменится, биржа кинет нам клич, а программа его подхватит. Это быстрее, чем опрашивать через rest. Так же возможны ситуации, когда мы отправляем запрос на создание ордера, и, прежде чем получаем ответ от сервера, уже по сокету прилетает информация об исполнении.
  1. Необходимо держать актуальными все стаканы по всем парам. При этом наиболее интересной информацией будет лучшая цена и объем, который этой цене соответствует. Для этого нужно имплементировать стаканы для каждой пары в своей программе, и обновлять их через сокеты: как только на бирже происходит изменение стакана, информация прилетает в программу, и мы у себя производим корректировки. При этом информация может прилететь какая-угодно: например, кто-то отменил ордер в середине или в хвосте стакана, либо увеличился/уменьшился объем по какой-то позиции и т.п. Поэтому у меня сложился такой алгоритм: на старте программы получаем топ1000 записей по каждому стакану каждой пары (bid и ask) считаем отдельно и строим бинарное дерево по каждому стакану. Подписываемся на сокеты, и, как только прилетает информация, обновляем дерево – либо добавляем запись, если такой цены не было, либо обновляем лист, если изменился объем.  После изменения дерева пробегаемся по нему, и получаем лучшую цену (и соответствующий объем, берем только записи с объемом больше 0). Стаканы и прочее держим в памяти пары – цены и объемы для поиска оптимальной цепочки, стаканы – что бы всегда иметь возможность получить актуальную лучшую цену, а так же, что бы уйти если что в глубину  - см. след пункт.
  2. Для того, что бы провернуть сделку, должны совпасть несколько условий:
    1. нам должно хватить денег на покупку,
    2. каждое лучшее предложение в цепочке должно содержать объем равный или выше нужному (не должно получиться так, что по лучшей цене продают одну сатошу, грубо говоря). Возможно, нужный объем будет достигнут, если брать не самое лучшее предложение, а несколько предложений сверху стакана, и суммировать объемы. При этом цены будут всё более невыгодными и нам придется считать среднезвешенную. Вообще это не работает, т.к. слишком быстро всё меняется, верхних цен и объемов достаточно.
    3. Каждая сделка на каждом этапе должна удовлетворять правилам биржи, особенно касательно размера сделки – нужно избегать таких ситуаций, где мы покупаем монету X на мин. разрешенное кол-во, потом пытаемся продать X за монету Y, и эта сделка кажется бирже слишком маленькой.
    4. На каждой сделке мы теряем комиссию 0.075%, поэтому на выходе мы должны получать больше BTC чем потратили с учетом 0.075% * длину цепи. При этом зачастую после покупки/продажи будет оставаться т.н. «пыль» - остатки монет, которые были отрезаны в результате необходимого округления. Поэтому на каждом этапе мы можем терять чуть больше. Пыль конечно останется, но может быть обесценена со временем.
  3. Важный момент – для покупки/продажи по рынку нужно указывать кол-во монет. Но обстоятельства меняются довольно быстро, и тот расчет, который был перед первой покупкой может быть уже неактуальным перед второй покупкой в цепи. Для примера, мы рассчитали цепь, в которой на 1 BTC закупаем ETH по курсу 1:10 (получим 1 ETH), потом на 10ETH покупаем 100X по курсу 1:10, потом 100X продаем за BTC.  Мы выставляем ордер на покупку 10ETH по рынку, получаем пускай эти 10 ETH, и… теперь нам нужно купить 100X по нашему расчету, но курс X:ETH изменился, и на 10 ETH можно купить только 99 X. А при покупке по рынку, как сказано выше, нужно указывать кол-во монет, так что после сделок нужно пересчитывать новое кол-во монет с учетом актуального курса.
  4. Еще есть фишка для ETH (и, вероятно BNB), что деньги на балансе оказываются не сразу – вы можете купить ETH, и не сможете купить на него ничего в течении секунды или двух. Видимо, там работает какой-то процесс по расписанию. Что бы обойти этот вопрос, нужно на балансе держать ETH – вы покупаете ETH, тратите свой ETH на дальнейшее движение по цепи, а потом купленный ETH падает вам на баланс, восполняя траты. Уот так уот.

В общем, все эти моменты я реализовал в коде, и этот осьминог в куче потоков получает все стаканы по всем парам, ищет цепочки, создает заказы, отслеживает заказы и т.п. Щас заживем.


Реклама


Результаты

Вообще, иногда такие возможности попадаются, и даже можно заработать несколько сатош, но, во-первых, эти ситуации довольно редкие – от 1 до 4 сделок в сутки по BTC паре.

Как только появляется такая возможность, она сразу же пропадает – я так понимаю, работают чужие роботы по тому же алгоритму. Поэтому очень важно успеть первым – приятно осознавать, что я часто успеваю :) Но, т.к. сделки идут по рынку, то если не успел, продаешь в минус.

Иногда бывает так, что цена в стакане и объем какие надо, бот покупает, но цена неадекватно растет шагами, вот так:

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

Golang меня порадовал, он реально работает очень быстро и потребляет мало памяти. Не то, что бы я решил на него переходить, но в некоторых ситуациях пользоваться буду. Я еще использовал его в других проектах – например, я делал веб-сервис, отлаживал его на винде, добавлял всякие штуки, проверял, потом этот же код без каких-либо изменений закинул на сервер с убунтой, там скомпилировал и запустил, вот он работает уже хз сколько. Не могу сказать, что он лучше C++ - его я тоже использую, но своя ниша у него есть – просто и быстро писать код, ориентированный на веб с хорошей производительностью.

Насчет арбитража – я думаю, история еще не закончена, и код пока что выкладывать не буду. У меня есть подозрения, что зря я выбрал Binance – она конечно самая популярная сегодня, но именно поэтому оккупирована ботами всех возможных мастей и направлений. Если взять биржу попроще, то и без всех этих оптимизаций алгоритмов, работ с сокетами и т.п. могло бы выгореть… возможно.

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

Может быть, у вас получится? :)


Это статья из цикла "Популярно о бирже"
Все статьи цикла:

Последнее изменение:

Не забудьте рассказать друзьям об этой статье.
Чтобы поддержать ресурс Bablofil достаточно просто поделиться с друзьями этой статьей в социальных сетях. Каждый репост - это самая высокая оценка качества материала. Спасибо, что читаете этот блог.



Комментарии
16.01.2019 04:40:02
Здравствуй Андрей! Мне понравилась твоя задумка про арбитраж на бинансе. Мог ли ты выложить сам скрипт написанный на golang? Хотелось бы поэкспериментировать на других более мелких биржах, а так задумка очень интересная! Заранее спасибо!
Проголосовать Проголосовать
0 0
21.01.2019 08:52:39
Я планирую сделать это чуть позже, т.к. нужно пройти еще несколько шагов:
1. Всё же погонять еще хотя бы месяц и снять статистику
2. Оформить комментариями, расписать в них логику
3. Сделать какой-то вывод текущей информации, что бы непосвященный человек мог мониторить работу.
4. Написать сопроводиловку, как запускать, как компилировать, и т.п.

Сейчас это выглядит как, как некий загадочный процесс, который работает, потребляет немного ресурсов компа, при этом ничего не происходит внешне, потом крекс-пекс-фекс, и на бирже цепочка ордеров сформировалась и в логах появилась куча загадочного.
Кроме того, если я сейчас выложу этот код, и его запустят многие, то они возможно будут мешать друг другу и вообще ничего происходить не будет.
А может быть наоборот, одни люди будут создавать волну для других, а это чем-то тоже интересно.
В общем, мне кажется будет правильным на основе этого проекта сделать что-то более доступное и массовое и выложить, а там делайте что хотите )
Но это будет позже )
Проголосовать Проголосовать
1 0
19.01.2019 07:24:40
почему только внутренний, почему не пространственный?
Проголосовать Проголосовать
0 0
21.01.2019 06:39:45
Всему свое время :)
Проголосовать Проголосовать
0 0
21.01.2019 21:04:14
здравствуйте Го-ланг действительно приятно удивил , как к нему GUI прикрутить ?
вот это подойдет ? https://habr.com/ru/post/420035/
 
п.с.  https://evilinside.ru/pishem-torgovogo-robota-dlya-birzhi-exmo/# Ваша статья? или "одолжили" ))
Проголосовать Проголосовать
0 0
22.01.2019 11:42:55
Хах, плагиатор детектед )
Вообще true way - это в отдельном потоке поднять веб-сервер в пару строк и управлять через страницу - просто, быстро и кроссплатформенно, можно управлять ботом на удаленном сервере. И кстати веб-сервер тоже может приятно удивить, он заточен на то, что бы обойтись без nginx, работать с хорошей скоростью на слабых серверах и т.п.
Но если уж нужен монолитный интерфейс, то я бы наверное сразу ушел в сторону C++ с QT например, ну или там WPF какой-нибудь.
Проголосовать Проголосовать
0 0
Пожалуйста, авторизуйтесь, что бы оставить свой комментарий
Крипто-кошельки для помощи и благодарности проекту:

Bitcoin адрес проекта: [[address]]

Перевод на сумму [[value]] BTC получен. Спасибо!.
[[error]]

Ethereum адрес проекта: [[address]]