Как стать автором
Обновить

Binance API и Telegram бот с уведомлениями о сделках

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров9.4K

Возникла задача сделать уведомления в Телеграм о сделках на Binance. Открытие и закрытие позиций, текущий профит, баланс и прочее. Это актуально когда надо быть в курсе если кто-то или что-то торгует на вашем счете.

Задача выглядела несложной - из Binance API забираем последние сделки и шлём в Телеграм - работы на пару часов. Но на практике это превратилось в квест в котором 90% времени ушло на изучение особенностей работы с Binance API, их довольно странную логику и жесткие лимиты.

В итоге, родился минималистичный скрипт на 40 строк кода и новый интересный проект о котором подробнее в конце статьи. Скрипт можно запустить на своем компьютере и все сделки на вашем счете превратятся в уведомления типа BUY BTCUSDT volume: 0.01 или CLOSE BTCUSDT profit: 10$

Подготовка

Для работы скрипта нужны:

  1. Ключи API созданные в личном кабинете на Binance. Заходим в "Управление API", жмём на кнопку "Создать API", выбираем "Сгенерированный системой" и копируем API key и Secret key. Убеждаемся, что права у ключей "только чтение".

  2. Токен Телеграм бота. Как сделать описывать не буду, инструкций много, смотрите здесь.

  3. Telegram id вашего аккаунта в Телеграм. Что бы его узнать, просто отправьте любое сообщение этому боту или аналогичному, таких сервисов много.

Скрипт

# pip install binance-futures-connector, pyTelegramBotAPI
import telebot
from binance.um_futures import UMFutures

binance_api_key = "..."
binance_api_secret = "..."
bot_token = "..."
my_telegram_id = "..."

bot = telebot.TeleBot(bot_token)
prev_symbols = []
prev_data = []
while True:
    new_symbols = []
    new_data = []
    client = UMFutures(key=binance_api_key, secret=binance_api_secret)
    try:
        info = client.account(recvWindow=6000)
    except Exception as e:
        print(e)
        break
    for p in info['positions']:
        if float(p['positionAmt']) != 0:
            new_symbols.append(p['symbol'])
            new_data.append([p['positionAmt'], p['unrealizedProfit']])
    if new_symbols != prev_symbols:
        symbol = list(set(new_symbols) ^ set(prev_symbols))[0]
        if len(new_symbols) > len(prev_symbols):
            amount = float(new_data[new_symbols.index(symbol)][0])
            text = symbol + " amount: " + str(abs(amount))
            if amount > 0:
                text = "BUY " + text
            else:
                text = "SELL " + text
        else:
            profit = round(float(prev_data[prev_symbols.index(symbol)][1]), 2)
            text = "CLOSE " + symbol + " profit, $: " + str(profit)
        prev_symbols = new_symbols
        prev_data = new_data
        print(text)
        bot.send_message(my_telegram_id, text)

Как он работает

У биржи Binance своё представление о "сделке". Для нас сделка - это основной юнит торговли. У сделки есть точка входа, точка выхода и, как итог, профит или убыток. У Binance такой сущности нет, у них есть "позиция" и "трейд" (речь идет о фьючерсах). Позиция - это открытая в данный момент сделка. После закрытия позиции информация о ней исчезает бесследно и достать ее из истории одним запросом невозможно. А трейд, в свою очередь, - вход или выход из позиции. Т.е. случился трейд - позиция открылась, случился следующий - позиция закрылась. Это все просто для отслеживания, пока вы не увеличили или не уменьшили объем открытой позиции. Тогда трейдов на одну позицию может быть неограниченное количество и начинается путаница.

Кроме этого, просто запросить все трейды нельзя, их можно запрашивать только с указанием конкретной торговой пары. Учитывая, что торговых пар более 200, опросить их все невозможно. По этой же причине нельзя отслеживать и ордера, запрос тоже требует торговую пару.

В итоге, для мониторинга событий остается только две точки входа - Account Information и Get Income History. В первом случае получим всю информацию о счете включая текущие открытые позиции, во втором - все начисления и списания. Get Income History содержит в себе указание на трейд результатом которого стало движение средств. По этому указателю можем достать нужный трейд и получить то, что надо - торговую пару, объем и направление сделки. Формально это самый правильный путь, но нам не подойдет. Он в 6 раз дороже (по ограничениям API) чем запрос Account Information и требует выстраивания цепочки из минимум двух запросов.

Поэтому оставляем первый вариант - Account Information. Всего один запрос и прилетает много информации включая открытые позиции. По наличию или отсутствию открытых позиций можно сделать вывод о случившемся трейде. Да, это выглядит немного криво, но работает и очень экономно.

По такой схеме в приведенном скрипте делаем несложную операцию - проверяем текущие открытые позиции и сравниваем с результатом предыдущей проверки. Если видим разницу то делаем вывод о случившемся событии и шлем уведомление.

Почему не Websocketы

Все то же самое можно делать используя User Data Streams. Это получение той же информациии, но не через периодическое опрашивание конечных точек API, а через websockets, просто в режиме ожидания. Такой вариант формально более правильный и быстрый, но в нашем случае, когда всего один клиент и разница в 0,5 сек скорости не имеет значения, не оправдан. Наш минималистичный скрипт сразу перестанет быть таким маленьким, а результат останется тот же.

Более продвинутый вариант

Все это нормально работает пока ботом пользуются не более 10 человек. А что если их не 10, а 1000? Я задался этим вопросом и попытался найти ответ. Одно за другим рождались технические решения, в итоге всё свелось в проект MyTradingPage.

Бот справляется с любым количеством пользователей. Понимает по какому типу ордера произошел трейд, видит изменение объема позиции, сообщает о новых ордерах и после закрытия каждой позиции присылает такие графические отчеты:

Как сделать такой отчет - тема следующей статьи.

Теги:
Хабы:
Всего голосов 3: ↑3 и ↓0+5
Комментарии2

Публикации

Работа

Data Scientist
41 вакансия

Ближайшие события