На горизонте неизвестный континент - биржа Yobit.net. Больше 1000 активных (порой весьма экзотических) пар. Отличное место что бы что-то автоматизировать. Хотя бы даже без денег, так, поизучать. Погнали)
Как и большинство конкурентов, биржа предоставляет для роботов публичный и приватный методы получения данных. Прочитать детальное описание можно тут: https://www.yobit.net/ru/api/.
Попробуем для начала вытащить текущие пары и их активные курсы покупок и продаж?
Обычно именно для этого и используется метод ticker, но увы, тут он не предусмотрен выводить информацию по всем парам, можно лишь указывать нужные - например https://yobit.net/api/3/ticker/ltc_btc-nmc_btc.
Жаль, но давайте посмотрим, какую информацию можно получить. Для начала перейдем по этой ссылке сами, в браузере, что видим? Полезную информацию:
Отобразим в более удобном виде для чтения (jsoneditoronline.org):
Почитаем, что где что означает..
Судя по всему, поля buy и sell – это лучшие текущие цены покупки и продажи соответственно. Попробуем их вывести сначала для отдельно взятой пары. Пусть это будет ltc_btc.
(Тем, кто не установил себе Python, нужно это сделать, что бы повторять написанное далее – как установить питон и модули к нему, я писал в этой статье).
Запускаем Idle, и пишем туда текст скрипта по получению данных. Сохраняем (под любым именем, у меня он называется yobit0.py) и запускаем (f5).
Скрипт:
import json import requests
Реклама:
res = requests.get('https://yobit.net/api/3/ticker/ltc_btc') # получаем данные ticker'а res_obj = json.loads(res.text) # переводим полученный текст в объект с данными print("SELL: %0.8f" % res_obj['ltc_btc']['sell']) print("BUY: %0.8f" % res_obj['ltc_btc']['buy'])
Результат:
Теперь нам нужно научиться получать название пары, buy и sell для всех пар – но всего на бирже больше 1000 пар – задолбаешься проверять каждую, даже прописывая по несколько штук… хотя…
Активные пары можно посмотреть в методе info - https://yobit.net/api/3/info. Давайте ради интереса вытащим все активные пары и попробуем подставить их в URL? Раньше, я помню, было ограничение на длину 1024 символа при отправке данных методом GET, но потом вроде бы ограничение ушло из браузеров и переместилось на сторону конфигурации веб-серверов, так что заодно и проверим что получилось.
Скрипт:
import json import requests res = requests.get('https://yobit.net/api/3/info') # получаем данные res_obj = json.loads(res.text) # переводим полученный текст в объект с данными print("Получено %d пар(ы)!" % len(res_obj['pairs'])) pairs = '-'.join(res_obj['pairs']) # Формируем строку в нужном формате print(pairs)
Результат:
Все пары получены, и сформированы в строку, разделенную дефисами – за это отвечает функция join – но не заостряйте пока на этом внимание. Попробуем теперь эту строку отдать на вход ticker`у и посмотрим, что получится. Юхуу.
Меняем этот скрипт (или создаем новый файл, yobit2.py), запускаем и смотрим ответ сервера…
Скрипт:
import json import requests res = requests.get('https://yobit.net/api/3/info') # получаем данные res_obj = json.loads(res.text) # переводим полученный текст в объект с данными print("Получено %d пар(ы)!" % len(res_obj['pairs'])) pairs = '-'.join(res_obj['pairs']) # Формируем строку в нужном формате print(pairs)
О, горе, горе… Yobit использует веб-фронтенд Nginx версии 1.11.4, которому очень не нравится ссылка, которую мы сформировали.
Ладно, ладно…. Плохой Yobit, тогда будем разбивать массив полученных данных на кусочки по 50 30 пар, и получать инфу, потом следующие 30 пар.. Можно было бы взять по 100 пар, но тогда Yobit их отрезает и считает что ничего не передали) Можно просто идти в цикле по каждой паре, но это будет 1000 запросов к сайту, на месте Yobit’а я бы насторожился. Итак, режем список по 30 пар и выводим значения:
Скрипт:
import json import math import requests res = requests.get('https://yobit.net/api/3/info') # получаем данные info res_obj = json.loads(res.text) # переводим полученный текст в объект с данными pairs = [pair for pair in res_obj['pairs']] # создадим массив названий пар cnt = 1 # Проходим в цикле, отбирая каждый раз по 100 пар (или меньше, в хвосте) for i in range(0, int(math.ceil(len(pairs)/30))): pairs_str = '-'.join(pairs[i*30:(i+1)*30]) # формируем строку для передачи тикеру ticker_res = requests.get('https://yobit.net/api/3/ticker/'+pairs_str) # получаем данные info ticker_res_obj = json.loads(ticker_res.text) # переводим полученный текст в объект с данными for pair in ticker_res_obj: print( cnt, pair, '%0.8f' % ticker_res_obj[pair]['buy'], '%0.8f' % ticker_res_obj[pair]['sell'] ) cnt += 1
Результат:
Методы, которыми мы пользовались выше, относились к публичному API – т.е. данные доступны для всех без регистрации. Сейчас посмотрим приватное API – методы, доступные только для авторизованного пользователя, позволяющие выполнять действия от его имени.
Давайте попробуем получить свой баланс и создать ордер используя только программирование. Для этого сначала нужно получить ключи API (а для этого нужно быть зарегистрированным).
Нажать Create new key
Обратите внимание - слева от кнопки есть выпадающий список (но менять его не надо).
Info only – Вы сможете запрашивать баланс, открытые ордера, историю торгов и т.п., но не сможете торговать, отменять ордера и выполнять прочие активные действия.
Info & trade & deposits (по умолчанию, оставляем как есть) – помимо информации вы сможете торговать а так же пополнять баланс. Если хакер украдет ваши ключи API, он не сможет вывести у вас деньги (но сможет их проиграть).
Info & trade & deposits & withdrawals – вы сможете выполнять все доступные на сегодня методы API, включая вывод денег. Я бы не стал такое включать, пока в этом нет действительной нужды (но если пишете бота для межбиржевого арбитража, наверное стоит включить)
После этого получите ключи и сохраните их, они нам понадобятся.
Скрипт:
import os import json # import requests import urllib, http.client import hmac, hashlib # Вписываем свои ключи API_KEY = '' API_SECRET = b'' """ Каждый новый запрос к серверу должен содержать увеличенное число в диапазоне 1-2147483646 Поэтому храним число в файле поблизости, каждый раз обновляя его """ nonce_file = "./nonce" if not os.path.exists(nonce_file): with open(nonce_file, "w") as out: out.write('1') # Будем перехватывать все сообщения об ошибках с биржи class YobitException(Exception): pass def call_api(**kwargs): # При каждом обращении к торговому API увеличиваем счетчик nonce на единицу with open(nonce_file, 'r+') as inp: nonce = int(inp.read()) inp.seek(0) inp.write(str(nonce+1)) inp.truncate() payload = {'nonce': nonce} if kwargs: payload.update(kwargs) payload = urllib.parse.urlencode(payload) H = hmac.new(key=API_SECRET, digestmod=hashlib.sha512) H.update(payload.encode('utf-8')) sign = H.hexdigest() headers = {"Content-type": "application/x-www-form-urlencoded", "Key":API_KEY, "Sign":sign} conn = http.client.HTTPSConnection("yobit.net", timeout=60) conn.request("POST", "/tapi/", payload, headers) response = conn.getresponse().read() conn.close() try: obj = json.loads(response.decode('utf-8')) if 'error' in obj and obj['error']: raise YobitException(obj['error']) return obj except json.decoder.JSONDecodeError: raise YobitException('Ошибка анализа возвращаемых данных, получена строка', response) print ('Получаем информацию по аккаунту', '*'*30) print( call_api(method="getInfo") ) try: print ('Создаем ордер на покупку', '*'*30) print( call_api(method="Trade", pair="ltc_btc", type="buy", rate="0.1", amount=0.01) ) except YobitException as e: print("Облом:", e) try: print ('Создаем ордер на продажу', '*'*30) print( call_api(method="Trade", pair="ltc_btc", type="sell", rate="0.1", amount=0.01) ) except YobitException as e: print("Облом:", e) try: print ('Получаем список активных ордеров', '*'*30) print( call_api(method="ActiveOrders", pair="ltc_btc") ) except YobitException as e: print("Облом:", e) try: print ('Получаем информацию по ордеру', '*'*30) print( call_api(method="OrderInfo", order_id="123") ) except YobitException as e: print("Облом:", e) try: print ('Отменяем ордер', '*'*30) print( call_api(method="CancelOrder", order_id="123") ) except YobitException as e: print("Облом:", e) try: print ('Получаем историю торгов', '*'*30) print( call_api(method="TradeHistory", pair="ltc_btc") ) except YobitException as e: print("Облом:", e) try: print ('Получаем кошель для пополнения (BTC)', '*'*30) print( call_api(method="GetDepositAddress", coinName="BTC") ) except YobitException as e: print("Облом:", e)
Результат:
Как видите, все методы API отрабатывают, правда на моем новеньком голеньком аккаунте нет ни денег, ни истории торгов, так что все выглядит печально, у вас должны быть другие результаты, весь экран в данных.
Теперь, когда вы умеете получать информацию по активным парам, курсам, можете создавать , отменять и проверять ордера, вам остается только выстроить логику работы бота – когда что покупать, когда что продавать, и т.п. За основу можете взять алгоритм работы эксмобота из соседней статьи этого цикла, и поменять методы и поля в них – и все у вас получится.
Желаю вам большого, стабильного и легкого заработка!