Разработка криптотрейдингового бота с помощью Python
Всем привет, меня зовут Александр, я работаю интеграционным инженером в компании Luxoft. В этой статье хотел бы рассказать о своем опыте автоматизации торговли криптовалютами.
Данная статья будет содержать примеры кода на Python, а также некоторые выводы, которые я сделал, торгуя на бирже. Материал будет полезен людям, которые интересуются темой криптовалют и хотят автоматизировать некоторые рутинные процессы. А также тем, кто начинает изучать Python и хочет познакомиться с языком на полезном и практическом примере, а не на оторванных от реальности синтетических задачах.
В данный момент бот находится в стадии прототипа и альфа-тестирования. Он только собирает статистику с биржи, анализирует ее и дает рекомендации — в какой момент времени какой токен стоит покупать, какой — продавать. Сам процесс торговли пока еще находится в руках человека, но в будущем он также будет автоматизирован и бот станет полностью автономным.
Часть 1. Общие сведения про биржу и торговлю криптовалютами
Eсли вам интересен только код — смело листайте сразу до части.
Всё началось несколько месяцев назад, в январе 2021, когда практически из каждого утюга доносилось «Биткоин стремительно растёт! Те, кто вовремя вложились — стали миллионерами!». Также масла в огонь подливали новости о том, что геймерам не хватает видеокарт, потому что майнеры всё раскупили, даже несмотря на рост цен в
В итоге, после настолько навязчивой информационной атаки, я просто не мог оставаться в стороне и начал разбираться в вопросе.
Не вдаваясь в детали выбора криптобиржи скажу лишь, что он был скорее интуитивным, чем рационально обоснованным и в итоге пал на binance.com (не реклама).
У меня нет никаких аргументов за или против этой биржи, так как ничем другим не пользовался и сравнивать, соответственно, не с чем. Вы вполне можете выбрать любую другую биржу из популярных — принципы торговли будут одинаковы, отличаться будет лишь интерфейс, API и процедура верификации личности.
На последнем моменте стоит отдельно акцентировать внимание — на Бинанс у вас будут весьма ограниченные возможности, если вы не подтвердите свою личность. Процедура несложная, занимает буквально 15 минут и требует от вас всего лишь:
- документа, подтверждающего личность (например, паспорт, водительское удостоверение, etc);
- веб-камеры (или фронтальной камеры на смартфоне с установленным приложением от Бинанс);
- ввода некоторых данных о вас.
Крайне рекомендую сделать это, так как иначе на ваш аккаунт будет наложено, среди прочих, одно очень существенное ограничение — вы не сможете выводить деньги с биржи. То есть, завести деньги на биржу сможете без проблем, а потом, успешно поторговав — не сможете вернуть деньги обратно на свою банковскую карту.
После успешной регистрации и верификации аккаунта у вас будет несколько способов завести деньги на биржу. Рассмотрев альтернативы, был выбран такой способ — с помощью банковской карты покупаются токены USDT, которые относятся к так называемым стейблкоинам (от англ. stable coin — стабильная монета). Стабильной она называется потому, что ее цена колеблется в очень незначительных пределах (от 0.98$ до 1.02$ за 1 USDT) и большую часть времени составляет ровно 1 доллар США. Таким образом, купив за реальные деньги — виртуальные USDT, вы пока еще ничем не рискуете, так как цена практически гарантированно не изменится. Единственное, что вы теряете в данный момент — это 2% комиссии биржи за ввод средств или 20$ с каждой тысячи.
Также стоит учесть, что от всех торговых внутрибиржевых сделок Бинанс берет небольшую комиссию — 0.1% или 1$ с каждой 1000. Эта комиссия настолько незначительна, что её можно игнорировать.
И, наконец, последняя важная комиссия — 2.5% от суммы средств, которые вы выводите с биржи на свою банковскую карту. Процент хоть и небольшой, но ощутимый (25$ с каждой 1000), поэтому имеет смысл торговать на бирже так долго, как это возможно, и выводить лишь в самом крайнем случае.
Просуммировав все вышеописанное, можно сделать вывод № 1: ваши инвестиции должны вырасти в цене как минимум на 4.6%, чтобы вы вышли в ноль. Если взять условную 1000$ на вашей банковской карте, то после всех ваших манипуляций на бирже (ввод, торговля), ваша прибыль должна составить как минимум 46$, чтобы к вам на карточку вернулась та же самая тысяча.
Для людей, привыкших к обычным банковским вкладам, 4.6% могут показаться весьма существенным и сложнодостижимым результатом. Но в мире криптовалют всё намного более волатильно, поэтому часто сделки осуществляются со значительно большей прибылью и буквально каждый день. Для примера, можете взглянуть на этот «зеленый» период рынка:
«Зеленым» он называется потому, что когда цена криптовалют растет — их графики рисуют зеленым цветом, а когда падает — красным. Если наступил период массового роста, иногда говорят, что «рынок позеленел», а если наступил период спада — «покраснел», например, как здесь:
Иногда бывают и совсем необычные ситуации — весь рынок «красный», а какой-нибудь Dogecoin растет на +122% за сутки)
Раз мы посчитали, сколько нужно заработать и увидели, что это возможно, давайте перейдем к той части, где обсудим, как именно это сделать.
Есть несколько стратегий, но одна из самых простых и понятных для начинающего криптоторговца — купить подешевле, продать подороже.
На графике это можно изобразить следующим образом:
Где каждый левый кружок в паре — момент покупки («подешевле»), а каждый правый кружок — момент продажи («подороже»). Соответственно, разница между этими двумя сделками — и будет вашей прибылью (за исключением символического процента биржи в 0.1%)
Вы можете задать вопрос: «А почему во второй сделке не подождать дальнейшего роста и не продать с большей прибылью?» И этот вопрос совершенно оправдан, вот только ясность приходит уже по прошествии определенного времени, когда график колебания цен у вас перед глазами и поздно отправляться в прошлое, чтобы принять наилучшее решение.
Опытные инвесторы говорят, что два основных рычага, влияющих на принятие решений — это страх и жадность. Жадность — как стремление получить больше прибыли (на росте цены) и страх — как тревога за то, что цена в любой момент может пойти вниз и текущий момент времени — тот самый локальный пик, наилучший момент для продажи.
Я выбрал следующую стратегию поведения (которая чуть ниже будет показана в коде): сперва отслеживаю резкие падения цены, покупаю такую криптовалюту на 100$ и сразу же, в эту же минуту ставлю ордер на автопродажу на сумму 110$. Такой подход позволяет совершать сделки достаточно часто, при этом суммарно их выходит много в течении месяца и итоговая прибыль получается существенной (в процентном отношении к стартовым инвестициям).
Пара моментов, на которые стоит обратить внимание.
Во-первых, Бинанс позволяет ставить так называемые стоп-лимит уровни. Их можно использовать для выполнения автоматических сделок, например — для покупки криптомонет, когда их цена опускается ниже определенного уровня или для продажи, когда их цена растет выше определенного уровня.
Во-вторых, хорошей стратегией является диверсификация или распределение ваших инвестиций на несколько криптовалют. На момент начала торгов на биржу было заведено 600$, которые я распределил равномерно на 6 частей, закупившись 6 разными криптовалютами. Когда после многочисленных сделок общая стоимость инвестиций выросла до 700$ — я стал покупать уже 7 разных криптовалют, когда выросла до 800$ — 8, и так далее. На момент написания статьи, стартовые 600$ превратились в 812$ примерно за месяц торгов с использованием описанной стратегии.
И наконец, если с моментом для продажи все просто (ставим ордер на автопродажу за 110$ и ждем — иногда пару часов, иногда несколько дней), то как именно можно определить, что такое «резкое падение цены»?
Вероятно, у каждого свое представление о том, какие падение считать достаточно резким, но я для себя (математически) определил его как «5% падение цены в течении последнего часа». Именно это определение было заложено в логику бота.
Для примера приведу еще несколько графиков, где вы сами без труда сможете определить удачный момент для покупки, а также убедиться, что после стремительного падения цены — всегда следует рост, с которого можно получить прибыль:
Часть 2. Пишем бота
После прочтения первой части у вас мог возникнуть вопрос: «Если Бинанс такая замечательная биржа, что позволяет автоматически и покупать, и продавать — зачем вообще нужен бот?». Это уместное замечание и ответ на него такой — бот крайне полезен для сбора статистики, анализа и рекомендаций по удачным моментам для покупки и продажи.
В те несколько недель, пока всё делалось вручную, успел заметить, что очень много времени и внимания уходит на отслеживание падений цен. А ведь возможность заниматься мониторингом была лишь изредка, ненадолго отвлекаясь от работы в течении дня и вечером. В остальное время, когда я работал, ел, спал — все удачные моменты для покупки проходили мимо и это выливалось в упущенные возможности и недополученную прибыль.
Всё это смотивировало написать код, который ежеминутно проверял курсы валют для выбранных токенов, собирал статистику колебаний цен за последний час и как только для какой-то валюты обнаруживал резкую просадку цены — тут же писал в Телеграм сообщение следующего вида:
Как видно из этого скриншота, бот не только писал, какой токен следует купить, но и на сколько % упала цена за последний час. Для тех же криптовалют, для которых падение цены было меньше 5% — фраза была «nothing to do right now...»
В данный момент бот используется только как сборщик статистики, анализатор и советчик. Он не совершает сделки автоматически, этот функционал будет добавлен в будущем, когда придет уверенность, что бот дает корректные рекомендации и не наторгует в минус, пока я буду спать)
Давайте же наконец перейдем к коду и посмотрим, как все устроено внутри.
Проект состоит всего из 3 файлов:
- cryptobot.py (собственно, сам бот)
- calculations.py (вспомогательные функции для анализа и расчетов)
- my_cryptocoins.json (файл с данными о криптовалютах и их актуальных ценах)
Содержимое my_cryptocoins.json выглядит следующим образом:
{ "ALICE": { "amount": 3.5, "buy_price": 30, "desired_price_fall": 5, "desired_sell_price": 33, "last_prices": [ 12.71004841, 12.71728863, 12.71983559, ... 12.73806222, 12.74204871 ] }, "ARDR": { "amount": 314.895, "buy_price": 0.351, "desired_price_fall": 5, "desired_sell_price": 0.3861, "last_prices": [ 0.69192631, 0.69205345, 0.68947941, ... 0.68280223, 0.67819879 ] }, "BCH": { "amount": 0.22, "buy_price": 650, "desired_price_fall": 5, "desired_sell_price": 715, "last_prices": [ 628.07961283, 628.60812333, 629.01582194, ... 629.29318231, 629.12820048, 660.64513681 ] },
(и так далее, полный файл содержит в себе десятки токенов и данных об их ценах)
Где, «amount» — количество монет данной валюты, купленных ранее.
«buy_price» — цена, по которой они были куплены
«desired_price_fall» — процент, на который мы ожидаем, что цена упадет, чтобы покупка имела смысл
«desired_sell_price» — цена, по которой планируется продать купленные монеты (и на которую стоит ордер на автопродажу)
«last_prices» — список из последних 60 цен, обновляемый каждую минуту
И наконец «ALICE», «ARDR» и «BCH» — короткие названия токенов, которые будут использованы для обращения к API Бинанс.
В текущей реализации, все данные кроме списка цен приходится заносить самому вручную. В будущем это будет осуществляться автоматически на основании сделок, проведенных ботом.
Конечно, использовать json файл — не лучшее решение в данной ситуации, но оно было выбрано, чтобы как можно быстрее проверить торговые гипотезы. В планах — поднять рядом с ботом полноценное веб-приложение с API и БД, куда будут записываться все интересующие данные, которые позволят проводить более глубокий анализ.
Файл calculations.py содержит в себе следующие функции и данные:
API_URL = 'https://api3.binance.com/api/v3/avgPrice'</td>
API ендпоинт, при обращении на который мы узнаем цену интересующей нас криптовалюты.
Также могут использоваться альтернативы:
api.binance.com
api1.binance.com
api2.binance.com
Все они предоставляют одну и ту же информацию, так что можете выбрать любой из них.
Функция, которая обращается к бирже и узнает цену интересующей нас криптовалюты:
def get_price(coin: str) -> float: """ :param coin: token name, e.g. BTC for Bitcoin, LTC for Litecoin :return: coin's current price in stable USDT. 1USDT ~ 1$ USA """ data = {'symbol': f'{coin}USDT'} # e.g. BTCUSDT response = requests.get(API_URL, data) return float(response.json()['price'])
Как видите, ничего сложного здесь нет — обычный GET запрос с передачей дополнительных данных о том, какая торговая пара нас интересует. Чтобы функция корректно работала, не забудьте в начале файла импортировать библиотеку requests — import requests.
Следующая функция отвечает за расчет вашей потенциальной прибыли. Здесь тоже нет никакой высшей математики, все рассчитывается по простой формуле: (текущая цена минус цена покупки) умножить на количество ваших монет для данной криптовалюты. Чтобы в сообщениях бота не мешать самому себе избыточной информацией, было добавлено округление до 2 знаков после запятой. Вряд ли кому-то интересны доли центов.
def count_profit(coin: dict, current_price: float) -> float: """ :param coin: e.g.: {"amount": 1.4466, "buy_price": 200, "desired_sell_price": 219, "last_prices": [201.4, 205, 203, 211, 222.2], "desired_price_fall": 10} :param current_price: coin's current price in stable USDT. 1USDT ~ 1$ USA :return: profit in USDT """ # Example: (220 - 200) * 0.5 == 10 return round((current_price - coin['buy_price']) * coin['amount'], 2)
Следующая функция содержит в себе логику, которая была описана ранее, а именно — определение того, насколько упала цена за последний час. Алгоритм работает так: из json файла достаются все цены для конкретной валюты, среди них определяется максимальная цена и сравнивается с текущей ценой (которую, напоминаю, мы узнали обращением к API Бинанса)
def count_price_fall(coin: dict, current_price: float) -> float: """ :param coin: same as in count_profit() :param current_price: same as in count_profit() :return: max diff between last 5 prices and current price, in USDT """ # Example: max([201.4, 205, 203, 211, 222.2]) - 190 == 32.2 try: return max(coin['last_prices']) - current_price except: # may happens if coin['last_prices'] is empty return 0
И, наконец, финальная функция, которая и дает совет «Time to buy», если за последний час снижение цены оказалось равным или больше тому, что было указано в json файле в поле «desired_price_fall»:
def should_i_buy(price_fall: float, desired_fall: float, current_price: float) -> bool: """ :param price_fall: output of count_price_fall() :param desired_fall: desired price fall in PERCENTS! not in USDT. e.g. 10% :param current_price: coin's current price in stable USDT :return: True if you should buy, False otherwise """ # Example: 21 / 200 * 100 == 10.5% and 10.5 >= 10, so -> True if price_fall / current_price * 100 >= desired_fall: return True return False
Как видите, на данном этапе реализации бота, внутренних расчетов и анализа у него не так уж много. Но идей по улучшению и добавлению нового функционала — предостаточно.
Последний файл — cryptobot.py содержит в себе код телеграм бота, который как раз и шлет сообщения о том, что пора покупать, продавать, или пока можно расслабиться и ничего не делать.
Прежде всего, вам необходимо будет написать отцу всех ботов — @BotFather и создать у него своего бота. Не будем дополнительно останавливаться на этой части, так как в интернете море подобных инструкций и вы без проблем сможете зарегистрировать своего бота самостоятельно за пару минут.
Главное, что вам нужно будет получить — это токен, который вы будете использовать в коде.
А также, очевидно — никнейм вашего бота, с которым вы будете общаться в чате Телеграма.
После этого вы сможете вставить свой токен в код бота и он будет выглядеть так:
(импорт всех необходимых функций, модулей и библиотек)
import time import json from telegram.ext import Updater, CommandHandler from calculations import get_price, count_profit, count_price_fall, should_i_buy
(ваш токен)
TOKEN = '1111111111:sdfklsdjgkljfdglkDSFDGFDGFDkdjskfljdkf'
(главная и единственная функция вашего бота, она же будет командой, которую вы будете отправлять ему в чате Телеграма, чтобы запустить эту адскую машину:)
def make_money(update, context): # (получаете id чата, где бот будет общаться с вами) chat_id = update.effective_chat.id # (бесконечный цикл) while True: # (открываете файл my_cryptocoins.json и читаете из него данные) with open('my_cryptocoins.json', 'r') as my_coins_data: my_coins = json.loads(my_coins_data.read()) # (эта переменная будет содержать в себе тот сообщение, которое бот вам отправит в Телеграме) final_message = [] # (цикл, проходящий по всем токенам, перечисленным в my_cryptocoins.json) for coin_name in my_coins.keys(): coin = my_coins[coin_name] coin_price = get_price(coin_name) possible_profit = count_profit(coin, coin_price) price_fall = count_price_fall(coin, coin_price) last_prices = coin['last_prices'] # (часть кода, отвечающая за работу с ценами, обновляемыми каждую минуту) if len(last_prices) <= 60: last_prices.append(coin_price) if len(last_prices) <= 59: price_fall = 0 # not enough data to provide correct calculations else: last_prices = last_prices[1:] + [coin_price] my_coins[coin_name]['last_prices'] = last_prices message = ''
# (логика, которая формирует сообщение о том, что пора покупать/продавать/ничего не делать) if coin_price >= coin['desired_sell_price'] and coin['amount'] > 0: message += f'{coin_name} --> TIME TO SELL\n' message += f'possible profit = {possible_profit}$' else: if should_i_buy(price_fall, coin['desired_price_fall'], coin_price): message += f'{coin_name} --> TIME TO BUY\n' message += f'price fall = {round(price_fall / coin_price * 100, 1)}%' else: message += f'{coin_name} --> nothing to do right now...' # (обратите внимание на time.sleep(2) - если обращаться к API биржи слишком часто - она вас "забанит" на какое-то время. Так что лучше не спамить запросами) final_message.append(message) time.sleep(2) # (после всех операций - записываем обновленные данные в my_cryptocoins.json) with open('my_cryptocoins.json', 'w') as my_coins_data: my_coins_data.write(json.dumps(my_coins, sort_keys=True, indent=2)) # (и наконец, команда, которая отправляет финальное сообщение в чат Телеграма) context.bot.send_message(chat_id=chat_id, text='\n'.join(final_message)) # (бот засыпает на 1 минуту до следующей итерации бесконечного цикла) time.sleep(60) # run every minute # (здесь от вас уже практически ничего не зависит, эта часть кода нужна, чтобы корректно запускать нужную нам функцию при отправке боту соответствующей команды) def main(): updater = Updater(token=TOKEN, use_context=True) dp = updater.dispatcher dp.add_handler(CommandHandler('make_money', make_money)) updater.start_polling() updater.idle() if __name__ == '__main__': main()
После того, как все 3 файла будут готовы, вам нужно будет установить необходимые для работы бота библиотеки командами:
pip install requests
pip install python-telegram-bot
Затем запустить бота командой python cryptobot.py и наконец написать вашему боту в телеграме команду /make_money
С этого момента бот будет каждую минуту слать вам сообщения с рекомендациями.
Часть 3. Выводы и планы на будущее
В течении последнего месяца бот показал себя довольно неплохо — благодаря его рекомендациям стартовые 600$ инвестиций превратились в 812$, что значительно превышает альтернативные способы заработка (например — обычный банковский вклад или покупку ценных бумаг). Пока экспериментирую на относительно небольших суммах, так как для меня это новая сфера и есть предчувствие, что некоторые подводные камни еще впереди. Как только почувствую больше уверенности в себе и боте — увеличу сумму инвестиций в несколько раз.
Но важно понимать, что криптовалюты — это высокорисковые, хоть и высокоприбыльные инвестиции. Так что рано или поздно стремительный рост рынка закончится и главное — успеть вовремя выйти во что-то более надежное, например в доллар США. Опытные криптоаналитики считают, что следующего серьезного спада следует ждать в конце 2022 года, так что у нас есть около 1.5 лет для заработка.
В текущей реализации бот еще не является полностью автономным и только советует, когда какие действия предпринимать. В следующих версиях я планирую добавить боту возможность самостоятельно осуществлять сделки (API Бинанс это позволяет) и, начав с небольших сумм, посмотреть на его эффективность.
Также в планах поэкспериментировать над максимизацией прибыли, возможно проведя синтетические эксперименты на исторических данных. А именно — проверить, какой будет результат, если покупать, когда цена падает не на 5% в течении часа, а на
И, как я уже писал ранее — также в планах есть разработка веб приложения с API и БД, где будут сохраняться все собираемые ботом данные для более глубокого анализа.
На этом всё, если у вас есть замечания/предложения по коду или интересные истории, связанные с торговлей криптовалютами — оставляйте комментарии.
P.S. Полную версию бота можно скачать здесь. Главное, не забудьте в нужное место вставить токен вашего телеграм бота.
Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті
55 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів