Маржинальный торговый робот на криптовалютной бирже BitMEX +9


Всем доброго времени суток!


Меня зовут Илья и сегодня я хочу вам немного рассказать о своем хобби — криптовалютном алго-трейдинге. Скоро будет год, как меня настигла мысль написать торгового робота, который бы минимизировал человеческий фактор торговли (торгующие люди наверняка знают, что такое каждые пять минут обновлять баланс и зачастую делать какие-то поспешные, и потому неверные, торговые решения). Потому было решено переложить все на робота, удалить приложения по просмотру курсов с телефона и начать спать спокойно. Потратив много времени на написание чего-то более или менее работающего, хочу дать читателю маленькое overview, с чего стоит начинать на этом веселом (и нервном) поприще, как алготрейдинг. Этот гайд не является призывом начинать торговлю, не содержит советов по инвестированию, преследуются исключительно образовательные цели.


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


Стой стой, что такое маржа?

Для тех, кто не понял о чем я говорю. Маржинальная торговля это торговля с кредитным плечом. [1] Что такое кредитное плечо?


Кредитное плечо — это отношение Вашего депозита к лоту, с которым Вы работаете. Т.е. имея на депозите 100$, Вы можете совершить сделку с лотом в 10 000, и тогда оно будет равно 1 к 100. Если же Вы выставите лот в 5 000, то кредитное плечо будет 1 к 50 и т.д. [2]


Итак, я надеюсь, что у читающего это есть базовые знания о торговле на бирже, к примеру, что такое OHLCV свечи (a.k.a. японские свечки), что бывают разные временные промежутки их представления и т.д.


Ну что, приступим к нашему маленькому приключения в страну алгоритмической маржинальной торговли?


Я любитель top-down коммуникации и поэтому я для начала расскажу, что я собираюсь сделать, а потом мы приступим к реализации. Глобально есть две важные вещи, которые надо сделать для запуска робота: разработать стратегию принятия решения (при каких условиях покупать) и разработать логику поверх принятого решения (сколько и как покупать).


Стратегия принятия решение (мозг) в нашем случае будет состоять из индикатора MACD (англ. Moving Average Convergence/Divergence — схождение/расхождение скользящих средних). Индикатор используют для проверки силы и направления тренда, а также определения разворотных точек. Строится на основе скользящих средних. Существует две модификации индикатора MACD: линейный MACD и MACD-гистограмма. [3] Мы воспользуемся реализацией MACD-гистограммы из библиотеки TA-lib и на основе этого индикатора будем принимать решение о покупке или продаже.


Пример MACD из Википедии

Логика поверх решения нашего индикатора будет простой: если индикатор сказал покупать, то мы купим, если продавать, то мы продадим. Торговать будем фиксированным количеством денег с фиксированным плечом.


Первое с чего мы начнем, это установка нужных библиотек. Для начала нам нужен клиент биржи, его берем тут. Мозг нашего робота будет основываться на техническом анализе, поэтому надо поставить библиотеку TA-lib. Ну и стандартный набор — numpy, pandas.


После установки всех нужных библиотек предлагаю читателю зарегистрироваться на https://testnet.bitmex.com — это копия биржи BitMEX, но там вы торгуете не реальным деньгами, а виртуальными. Очень удобно использовать для отладки роботов перед запуском на реальной бирже. После регистрации создаем себе ключи и создаем клиент биржи:


client = bitmex.bitmex(
    test=True,
    api_key="YOUR_KEY",
    api_secret="YOUR_SECRET"
)

Обратите внимание на параметр test. Он выставлен в true, что означает, что мы будем торговать на тестовой бирже. Этот пост не будет про использование API биржи, все возникающие вопросы по нему вы можете перенаправить в API explorer, благо он у них очень удобный.


Следующим шагом нам надо получить данных для использования их на MACD индикаторе. Мы получим 100 свечей с разрешением в 1 час.


ohlcv_candles = pd.DataFrame(client.Trade.Trade_getBucketed(
            binSize=self.timeframe,
            symbol='XBTUSD',
            count=100,
            reverse=True
        ).result()[0])

Теперь у нас есть датафрейм со свечками, давайте применим индикатор.


macd, signal, hist = talib.MACD(ohlcv_candles.close.values, 
                                              fastperiod = 8, 
                                              slowperiod = 28, 
                                              signalperiod = 9)

Почему параметры такие?

Я выбрал такие параметры немного поигравшись со стратегией и ее бэктестом на Trading View. Вот примеры картинок с точками входа/выхода стратегии на графике и сколько денег она заработала. Но учтите, это стратегия тестировалась без плеча.




Итак, получив индикатор, давайте поймем, как на его основе принимать решение. Ну тут все просто. Когда гистограмма пересекает нулевое значение снизу вверх, то это является сигналом к покупке, и наоборот.


#sell
if hist[-2] > 0 and hist[-1] < 0:
    return -1
#buy
if hist[-2] < 0 and hist[-1] > 0:
    return 1
#do nothing
else:
    return 0

Все очень просто и понятно. Давайте оформим это в один класс, который назовем стратегией.


class Strategy():
    def __init__(self, client, timeframe='5m'):
        self.client = client
        self.timeframe = timeframe

    def predict(self):
        ohlcv_candles = pd.DataFrame(self.client.Trade.Trade_getBucketed(
            binSize=self.timeframe,
            symbol='XBTUSD',
            count=100,
            reverse=True
        ).result()[0])

        macd, signal, hist = talib.MACD(ohlcv_candles.close.values, 
                                                      fastperiod = 8, 
                                                      slowperiod = 28, 
                                                      signalperiod = 9)

        #sell
        if hist[-2] > 0 and hist[-1] < 0:
            return -1
        #buy
        if hist[-2] < 0 and hist[-1] > 0:
            return 1
        #do nothing
        else:
            return 0

Теперь давайте напишем исполнителя наших решений. Логика простая — стратегия сказала нам покупать, значит мы покупаем. Приведу код торговца сразу, в нем ничего сложного нет:


class Trader():
    def __init__(self, client, strategy, money_to_trade=100, leverage=5):
        self.client = client
        self.strategy = strategy

        self.money_to_trade = money_to_trade
        self.leverage = leverage

    def execute_trade(self):
        prediction = self.strategy.predict()
        print(f"Last prediction: {prediction}")

        try:
            if prediction == -1:
                response = self.client.Order.Order_new(
                    symbol="XBTUSD",
                    side="Sell",
                    orderQty=self.money_to_trade * self.leverage,
                ).result()
            if prediction == 1:
                response = self.client.Order.Order_new(
                    symbol="XBTUSD",
                    side="Buy",
                    orderQty=self.money_to_trade * self.leverage,
                ).result()
        except Exception as e:
            print("Something goes wrong!")
            print(str(e))

        return

Маленький нюанс — для упрощения себе жизни, ордера здесь исполняются не по выставленной заранее цене, а по рыночной. В случае с BitMEX это хорошо по двум причинам:


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

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


time_to_wait_new_trade = 60*60 #sec

strategy = Strategy(client, timeframe='1h')
trader = Trader(client, strategy)

while True:
    if round(time.time()) % time_to_wait_new_trade == 0:
        trader.execute_trade()
        time.sleep(10)

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


Jupyter тетрадку с кодом я выложил в свой репозиторий, если кому-то интересно просмотреть — you are welcome!


  1. https://ru.wikipedia.org/wiki/Маржинальная_торговля
  2. https://www.fxclub.org/faq/chto-takoe-kreditnoe-plecho/"
  3. https://ru.wikipedia.org/wiki/Индикатор_MACD




К сожалению, не доступен сервер mySQL