Как торговать через API на Yobit.net

Андрей К…
Последнее изменение:
101
2
0

На горизонте неизвестный континент - биржа Yobit.net. Больше 1000 активных (порой весьма экзотических) пар. Отличное место что бы что-то автоматизировать. Хотя бы даже без денег, так, поизучать. Погнали)

Public API

Как и большинство конкурентов, биржа предоставляет для роботов публичный и приватный методы получения данных. Прочитать детальное описание можно тут: https://www.yobit.net/ru/api/.

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

Попробуем для начала вытащить текущие пары и их активные курсы покупок и продаж?

Обычно именно для этого и используется метод ticker, но увы, тут он не предусмотрен выводить информацию по всем парам, можно лишь указывать нужные - например https://yobit.net/api/3/ticker/ltc_btc-nmc_btc.

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

Отобразим в более удобном виде для чтения (jsoneditoronline.org):

Почитаем, что где что означает..

  • high: макcимальная цена
  • low: минимальная цена
  • avg: средняя цена
  • vol: объем торгов
  • vol_cur: объем торгов в валюте
  • last: цена последней сделки
  • buy: цена покупки
  • sell: цена продажи
  • updated: последнее обновление кэша

Судя по всему, поля 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

Результат:

Bingo, Yobit побежден, все 1002 пары получены.. Двигаемся дальше.


Реклама


Private API

Методы, которыми мы пользовались выше, относились к публичному API – т.е. данные доступны для всех без регистрации. Сейчас посмотрим приватное API – методы, доступные только для авторизованного пользователя, позволяющие выполнять действия от его имени.

Давайте попробуем получить свой баланс и создать ордер используя только программирование. Для этого сначала нужно получить ключи API (а для этого нужно быть зарегистрированным).

Нажать Create new key

Обратите внимание - слева от кнопки есть выпадающий список (но менять его не надо).

Info only – Вы сможете запрашивать баланс, открытые ордера, историю торгов и т.п., но не сможете торговать, отменять ордера и выполнять прочие активные действия.

Info & trade & deposits (по умолчанию, оставляем как есть) – помимо информации вы сможете торговать а так же пополнять баланс. Если хакер украдет ваши ключи API, он не сможет вывести у вас деньги (но сможет их проиграть).

Info & trade & deposits & withdrawals – вы сможете выполнять  все доступные на сегодня методы API, включая вывод денег. Я бы не стал такое включать, пока в этом нет действительной нужды (но если пишете бота для межбиржевого арбитража, наверное стоит включить)

После этого получите ключи и сохраните их, они нам понадобятся.

Ну а теперь пора наваять простецкую функцию для доступа по private API и погонять её. Возьмем за основу код из статьи про Эксмобота, немного адаптируем, ну и запустим.

Впишите API-ключи в API_KEY и API_SECRET!

Скрипт:

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 отрабатывают, правда на моем новеньком голеньком аккаунте нет ни денег, ни истории торгов, так что все выглядит печально, у вас должны быть другие результаты, весь экран в данных.


Реклама


Заключение

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

Желаю вам большого, стабильного и легкого заработка!

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

Комментарии: (101)
05.10.2017 14:45
Получение всех пар с ценами выдает:
 Traceback (most recent call last):
  File "yobit.py", line 11, in <module>
    for i in range(0, math.ceil(len(pairs)/50)):
TypeError: range() integer end argument expected, got float.

</module>
05.10.2017 16:29
Тогда для надежности заменим на 
for i in range(0, int(math.ceil(len(pairs)/50))):

(обновил код в примере)
05.10.2017 15:43
добрый день вопрос такого плана ,в данном примере делается запрос на историю только на одну валюту, как сделать так что б вся история читалась
И еще вопрос как сделать что б все открытые ордера показывались
05.10.2017 16:38
Боюсь, и в том и в другом случае нужно указывать нужные пары, т.е. сначала запускать для ltc_btc, потом тоже самое для ltc_zec и т.п., другой возможности yobit не дает, почему-то (
Причем, для истории торгов не утверждается (хотя подразумевается) что вернутся только ваши торги, так что лучше проверять)

И ого, у них уже под 6 000 пар)
05.10.2017 15:49
Валар М. выборка всех пар работает нормально ошибок нет ,смотрите где то у вас косяк в коде ,только что проверил питон 3.6 и пайчарм
06.10.2017 08:48
Ошибка походу из-за питона 2.7
06.10.2017 18:05
Еще вопросик, как вывести переменную со значением  pair за прeделы цикла for?
06.10.2017 19:43
представляю что можно через сохранение в файл, а более не нубские способы существуют?
06.10.2017 20:54
Можно вообще цикл не делать

# Например, можно вывести все содержимое
ticker_res_obj = json.loads(ticker_res.text)
print(ticker_res_obj) 

# Или из содержимого нужное значение
if 'ltc_btc' in ticker_res_obj:
        print(ticker_res_obj['ltc_btc'])

ну и тп
08.10.2017 19:04
Подскажите причину (в Вашем коде только вставил коды API, и закомментировал вызов функций, связанных с выставлением и снятием ордеров)

Получаем информацию по аккаунту ******************************
Traceback (most recent call last):
  File "D:\Python workspace\exercise.py", line 67, in call_api
    raise YobitException(obj['error'])
YobitException: invalid nonce (has already been used)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\Python workspace\exercise.py", line 74, in <module>
    print( call_api(method="getInfo") )
  File "D:\Python workspace\exercise.py", line 69, in call_api
    except json.decoder.JSONDecodeError:
AttributeError: 'module' object has no attribute 'JSONDecodeError'

Уже не в первой программе возникают ошибки Traceback (most recent call last), при этом видимых причин вроде бы нет, ведь насколько я понял такие ошибки возникают при несоответствии типов данных. Может ли у этого быть какая-то нетривиальная причина? Просто ошибка эта выскакивает регулярно даже на примерах из интернета где всё должно работать. Я что-то делаю не так, или мне нужно настроить/скачать библиотеки? 
</module>
08.10.2017 20:02
в заграничном инете https://stackoverflow.com/questions/44714046/python3-unable-to-import-jsondecodeerror-from-json-decoder говорят, что это из-за версии Python 3.4.
09.10.2017 01:19
В общем на  windowsXP который у меня стоял поддержка Python только до версии 3.4. Установил параллельно Linux mint, и там апгрейдил Python и Idle до версии 3.6.2. Одна из ошибок больше не отображается, но другие остались. 

Получаем информацию по аккаунту ******************************
Traceback (most recent call last):
  File "/home/serg/Python workspace/exercise.py", line 63, in <module>
    print( call_api(method="getInfo") )
  File "/home/serg/Python workspace/exercise.py", line 56, in call_api
    raise YobitException(obj['error'])
YobitException: invalid nonce (has already been used)

Подскажите почему опять возникает ошибка Traceback (most recent call last), и взаимосвязано ли это с invalid nonce. В файлике nonce счётчик работает. Так как пишет, что это значение уже использовалось, то я заменил в этом файлике число на десяток больше текущего, но ничего не изменилось - всё равно пишет, что это значение уже использовалось. Это тоже как-то связано с ошибками интерпретатора? Или что-то с ключами API? </module>
09.10.2017 11:17
Такс, по порядку. Да, JSONDecodeError не существовало в одной из версий, но можно заменить на ValueError. Впрочем, обновление версии питона более правильная идея.
Насчет nonce - тут заморочка с криптографией, к коду бота не относится. Возможно, вы пробовали какого-то другого бота и там счет пошел уже на миллионы, или указали API ключи в каком-то приложении для смартфона, и он там шпарит увеличивает.. 

Самое простое решение в данном случае - пересоздать ключи API на бирже - тогда можно снова начинать с единицы.

Если интересно узнать более подробно про nonce - как и почему - читайте в комментариях к статье https://bablofil.ru/bot-dlya-birjy-exmo/, там этот вопрос поднимался.
09.10.2017 21:45
О, заработало! Спасибо, добрый человек! Добавил нулей в файлик nonce - думал бестолку будет, потому что я ключи API на бирже новые создал как раз перед началом работы с этим кодом, ну то есть nonce эти у меня нулёвые были. Но как только заработало, так сразу и дошло в чём причина ошибки. Я, чтобы устранить проблему не восприятия версией Python 3.4, установил Linux, Python 3.6.2 и создал новый файл с этим же кодом и уже теми же ключами API. Но было необходимо перенести в ту же папку с новым файлом и файлик nonce с текущим значением, а я этого не сделал и программа создала новый файл и заново начала отсчёт. И главное мне пишет же почти по-русски: этот nonce уже использовался, а у меня в голове сидит мысль, что такого быть не может, как раз из-за того, что я типа предупредил развитие подобной ситуации, создав новые ключи API. В общем, спасибо ещё раз)
09.10.2017 13:02
код бы увидеть чтоб не гадать может вы просто тупо где то лишнее закомментировали
09.10.2017 21:49
Да не, саму функцию call_api я не трогал, закомментировал только некоторые вызовы этой функции, чтобы программа не насоздавала мне не нужных ордеров)
10.10.2017 11:52
не работает конструкция, не выбирает валюту, подскажите что не так

balances = call_api(method="getInfo", funds=['eth'])
10.10.2017 19:22
getInfo не принимает никаких параметров, а возвращает всё, что есть. Нужно как то так:

balances = call_api(method="getInfo")
eth = balances['return']['funds']['eth']
print(eth)
12.10.2017 08:36
Спасибо с этим разобрался. Питон пока знаю плохо. Изучаю по мере переписывания вашего скрипта для yobit.net
Еще вопрос.
Пишу
deals = call_api(method="TradeHistory", pair=CURRENT_PAIR)
print (deals)
ответ {'success': 1}

если пишу 
print (deals['return']['amount']['rate'])

в результате
Traceback (most recent call last):
  File "D:\tmp\bot\yobitbot.py", line 88, in <module>
    print (deals['success']['return']['amount'])
TypeError: 'int' object is not subscriptable

Подскажите что не правильно?</module>
17.10.2017 13:48
Тут два момента - во первых, в return возвращается набор сделок, т.е. надо персонально к каждой обращаться (мне не нравится, и я не понимаю зачем yobit так сделали).
Во вторых, amount и rate суть разные вещи, а в вашем коде вы непонятно что запрашиваете.
Вот так будет работать:

deals = call_api(method="TradeHistory", pair=CURRENT_PAIR)

for deal in deals['return']:
    print('Сделка #%s' % deal)
    print('Amount:', deals['return'][deal]['amount'])
    print('Rate:', deals['return'][deal]['rate'])
17.10.2017 15:38
Спасибо!
Работает. Я понял, что надо считывать в цикле. Но так как не знаю языка, не смог правильно написать код.
17.10.2017 23:06
Доброго времени суток. 
Подскажите, пожалуйста, хочу передавать первую валюту пары X / BTC, а также количество BTC, которое хочу потратить, из вводимых переменных, но не могу разобраться где это указать.

try:
    print ('Создаем ордер на покупку', '*'*30)
    print( call_api(method="Trade", pair="%s_btc", type="buy", rate="0.1", amount=0.01)%(ValutaX) )
except YobitException as e:
    print("Облом:", e)

Выше объявлю их ввод...amount - это то количество, которое хочу купить, правильно? А если я не знаю сколько будет, например LTC на мои 0.00999999 BTC?
17.10.2017 23:11
Или стоит amount выразить через соотношение "количество BTC, которое хочу потратить" к " res_obj['ltc_btc']['buy']"?..
17.10.2017 23:55
Это как раз на ваше усмотрение.

Вы знаете, что у вас есть 0.009BTC.
Вы можете:
А. Купить нужное вам количество LTC - например 10шт. В таком случае amount = 10, rate (высчитываете сами)=0.0009
Б. Купить по текущему (или желаемому курсу) сколько получится. Если желаемый курс 0.009, то rate=0.009, а amount (считаете сами) = 10
Это все, конечно, упрощенно, т.к. еще же надо учесть комиссию, которую возьмет биржа Т.е. купите вы не 10 LTC а 9.998 грубо говоря. 
А вообще примеры расчетов можно взять в этой статье, тут комиссии учитываются как при покупке, так и при продаже
https://bablofil.ru/bot-dlya-birjy-exmo

И еше замечание - вот так будет правильнее
 print( call_api(method="Trade", pair="%s_btc"  % ValutaX, type="buy", rate="0.1", amount=0.01) )
19.10.2017 13:40
Добрый день пишу вам по поводу роботов для бирж на эксмо запустил работает первый Профит 4$ перевел на ваш кошелёк большое спасибо на полониксе Сейчас пробую столкнулся с рядом проблем но так как в программировании полный ноль обращаюсь к вам если по возникновению ошибок буду напрямую вас беспокоить по эмайлу или Фэйсбуке поможете ? Вчера скачал самоучитель по питону попробую уложить в голову. Заранее благодарен
19.10.2017 22:51
Спасибо) Конечно, без проблем, пишите
19.10.2017 13:51
Писал на ваш mail пишет неверный Адрес...
19.10.2017 22:51
Получил ваше письмо, отвечу там)
22.10.2017 20:25
Доброго времени суток
..
for pair in ticker_res_obj:
		print(pair,ticker_res_obj[pair]['buy'])
..
выдает:    
print(pair,ticker_res_obj[pair]['buy'])
TypeError: 'int' object is not subscriptable
Как вылечить?
22.10.2017 20:32
С позапрошлого моего вопроса, мой код не продвинулся не на шаг..
Как отфильтровать разделить список ticker_res_obj по парно, чтобы получить цены и сравнить между собой?
23.10.2017 10:38
Сам отвечу на свой вопрос) Проблема решается при изменении количества отбора пар на 40.
# Проходим в цикле, отбирая каждый раз по 100 пар (или меньше, в хвосте)
for i in range(0, int(math.ceil(len(pairs)/40))):
    pairs_str = '-'.join(pairs[i*40:(i+1)*40]) # формируем строку для передачи тикеру
24.10.2017 10:07
Или вопрос может быть не правильно задаю. Помогите чем сможете. Не могу получить значения переменных ticker_res_obj после фильтрации по pair. Подскажите куда копать?
28.10.2017 21:57

Если короче написать , то у меня трудности с сопоставлением и нахождением разности значений.
Из такого:

а={'a3':3,'a1':1,'a2':2,'a4':5,'a5':4}
b={'b1':2,'b3':3,'b2':1}

Надо получить:

{'b1': 1, 'b2': -1, 'b3': 0}

25.10.2017 02:28
Баблофил, выручай)
29.10.2017 14:13
Такой кейс можно решить так:

a={'a3':3,'a1':1,'a2':2,'a4':5,'a5':4} 
b={'b1':2,'b3':3,'b2':1}
res = {}
for key in b:
    ident = key.split('b')[-1]
    a_val = a.get('a'+ident, 0)
    result = b[key] - a_val
    res[key] = result
    
print(res)    

Вернет

{'b1': 1, 'b3': 0, 'b2': -1}

В данном случае я разбиваю строку по символу b, что бы получить число на конце. Если там будут пары, то нужно использовать что-то вроде BTC_..
26.10.2017 18:46
Я тут)
Запутался в вопросах - не совсем пойму, как это сравнивать попарно - для тысячи пар это же около миллиона сравнений, причем некоторые торгуются к биткойну, некоторые к эфиру и т.п.? И к тому ж это нечетное кол-во.

Давайте про объект. Вот вы получили ticker_res_obj - сейчас он содержит несколько (тысяч) пар и данных по ним. Но возьмем для упрощения три пары https://yobit.net/api/3/ticker/ltc_btc-nmc_btc-cam_btc.
Откройте в браузере эту ссылку, скопируйте весь текст и идите на http://jsoneditoronline.org/. Там в левой части окна вставьте текст, нажмите сверху слева четыре такие полосочки, и он вам выровняет все как надо. Тогда вы увидите СТРУКТУРУ документа. Названия пар - это ключи, а все, что к ним относится - значения.
В данном случае вы видите три ключа, и относящуюся к ним информацию.
Для решения своих целей вы можете поступить по разному. 

Например, для нужной пары, можно обратиться напрямую к ключу и получить значения:
ltc_btc = ticker_res_obj['ltc_btc']
buy = ltc_btc['buy']
или сразу
buy =  ticker_res_obj['ltc_btc']['buy']
Обратите внимание - я просто следую СТРУКТУРЕ вложенности элементов.

Можно, как в примере в статье, идти в цикле и получать ключ - значение.
Можно в цикле пройти по всем ключам, выцепить нужные в отдельный массив, потом в другом цикле пройтись по нужным и выцепить значения и т.п.

Все зависит от задачи, суть одна - вы получаете данные в том виде, в каком они есть и приводите в тот вид, который вам нужен (а потом выполняете действия, которые сочтете нужными).  Например, если бы у меня стояла задача найти самые дорогие  валюты на yobit'e, я бы сварганил такой скрипт для вывода топ 10:

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

# Это словарь, в который мы будем собирать базовые валюты (btc, eth..) и что к ним торгуют
links = {}
max_pairs = 50

# Проходим в цикле, отбирая каждый раз по 100 пар (или меньше, в хвосте)
for i in range(0, int(math.ceil(len(pairs)/max_pairs))):
    pairs_str = '-'.join(pairs[i*max_pairs:(i+1)*max_pairs]) # формируем строку для передачи тикеру

    ticker_res = requests.get('https://yobit.net/api/3/ticker/'+pairs_str) # получаем данные info
    ticker_res_obj = json.loads(ticker_res.text) # переводим полученный текст в объект с данными
    print('Наберитесь терпения.... %d/%d'  % (i, len(pairs)/max_pairs))

    for pair in ticker_res_obj:
        if pair in ['success', 'error']:
            continue
        
        pair_obj = pair.split('_')
        if not pair_obj[1] in links:
            links[pair_obj[1]] =[]
        # Собираем полученные данные в словарь links - 
        links[pair_obj[1]].append({'curr': pair_obj[0],
                                  'buy': ticker_res_obj[pair]['buy'],
                                  'sell': ticker_res_obj[pair]['sell']
                                })
        cnt += 1

# Полученные данные для каждой базовой пары сортируем от большего к меньшему по цене продажи
for curr in links:
    # k['sell'] - сортировка по полю sell
    # reverse=True - от большего к меньшему. Замените True на False для обратного
    links[curr] = sorted(links[curr], key=lambda k: k['sell'], reverse=True) 

# Выводим отдельно для каждой базовой пары список top 10, отсортированный по ценам
for link in links:
    cnt = 1
    print('='*30, ' '  + link  + ' ', '=' * 30)
    for item in links[link]:
        print(cnt, item['curr'], '%0.8f' % item['sell'], '%0.8f' % item['buy'])
        cnt += 1
        if cnt > 10: # сколько выводить
            break
28.10.2017 22:11
Очень круто! Господибожемой, спасибо
17.12.2017 13:27
Здравствуйте! Скажите а как сделать так чтобы ордер выставлялся на весь остаток по паре вот в этом запросе? Как для amount указать всю доступную в кошельке сумму?

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)
17.12.2017 13:44
Немного ошибся, вот на этот запрос...

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)
18.12.2017 16:43
Боюсь, сначала нужно будет получить весь остаток, методом getInfo, потом уже указывать

Что то вроде

ltc_amount = call_api(method="getInfo")['return']['funds']['ltc']
try:
    print ('Создаем ордер на продажу', '*'*30)
    print( call_api(method="Trade", pair="ltc_btc", type="sell", rate="0.1", amount=ltc_amount ) )
except YobitException as e:
    print("Облом:", e)

Только он продаст весь лайт, который есть на балансе. Код не проверял, но вроде должно работать
20.12.2017 21:52
привет, попробовал пример с ключами, вывалилось такое , хз как под кат прятать
Получаем информацию по аккаунту ******************************
{'success': 1, 'return': {'rights': {'info': 1, 'trade': 1, 'deposit': 1, 'withdraw': 0}, 'funds': {'btc': 6e-08, 'dash': 1e-06, 'doge': 0, 'eth': 0, 'slfi': 5, 'pwr': 2, 'lbtc': 6e-08, 'egame': 1, 'week': 1, 'lc': 1, 'html5': 1, 'strb': 1, 'europe': 1, 'rur': 2e-08}, 'funds_incl_orders': {'btc': 6e-08, 'dash': 1e-06, 'doge': 0, 'eth': 0, 'slfi': 5, 'pwr': 2, 'lbtc': 6e-08, 'egame': 1, 'week': 1, 'lc': 1, 'html5': 1, 'strb': 1, 'europe': 1, 'rur': 2e-08}, 'transaction_count': 0, 'open_orders': 0, 'server_time': 1513806160}}
Создаем ордер на покупку ******************************
Облом: Insufficient funds in wallet of the second currency of the pair
Создаем ордер на продажу ******************************
Облом: Insufficient funds in wallet of the first currency of the pair
Получаем список активных ордеров ******************************
{'success': 1}
Получаем информацию по ордеру ******************************
Облом: ('Ошибка анализа возвращаемых данных, получена строка', b'html\n[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]\n[if IE 7]>    <html class="no-js ie7 oldie" lang="en-US"> <![endif]\n[if IE 8]>    <html class="no-js ie8 oldie" lang="en-US"> <![endif]\n[if gt IE 8]><! <html class="no-js" lang="en-US"> <!--<![endif]-->\n<head>\n<title>Access denied | yobit.net used Cloudflare to restrict access</title>\n<meta charset="utf-8"/>\n<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>\n<meta content="IE=Edge,chrome=1" http-equiv="X-UA-Compatible"/>\n<meta content="noindex, nofollow" name="robots"/>\n<meta content="width=device-width,initial-scale=1,maximum-scale=1" name="viewport"/>\n<link href="/cdn-cgi/styles/cf.errors.css" id="cf_styles-css" media="screen,projection" rel="stylesheet" type="text/css"/>\n<!--[if lt IE 9]><link rel="stylesheet" id=\'cf_styles-ie-css\' href="/cdn-cgi/styles/cf.errors.ie.css" type="text/css" media="screen,projection" /><![endif]-->\n<style type="text/css">body{margin:0;padding:0}</style>\n<!--[if lte IE 9]><script type="text/javascript" src="/cdn-cgi/scripts/jquery.min.js"></script><![endif]-->\n<!--[if gte IE 10]><!--><script src="/cdn-cgi/scripts/zepto.min.js" type="text/javascript"></script><!--<![endif]-->\n<script src="/cdn-cgi/scripts/cf.common.js" type="text/javascript"></script>\n\n</head>\n<body>\n  <div id="cf-wrapper">\n    <div class="cf-alert cf-alert-error cf-cookie-error" data-translate="enable_cookies" id="cookie-alert">Please enable cookies.</div>\n    <div class="cf-error-details-wrapper" id="cf-error-details">\n      <div class="cf-wrapper cf-header cf-error-overview">\n        <h1>\n          <span class="cf-error-type" data-translate="error">Error</span>\n          <span class="cf-error-code">1015</span>\n          <small class="heading-ray-id">Ray ID: 3d05c5de2d5c86fd • 2017-12-20 21:42:41 UTC</small>\n        </h1>\n        <h2 class="cf-subheadline" data-translate="error_desc">You are being rate limited</h2>\n      </div><!-- /.header -->\n\n      <section></section><!-- spacer -->\n\n      <div class="cf-section cf-wrapper">\n        <div class="cf-columns two">\n          <div class="cf-column">\n            <h2 data-translate="what_happened">What happened?</h2>\n            <p>The owner of this website (yobit.net) has banned you temporarily from accessing this website.</p>\n          </div>\n\n          \n        </div>\n      </div><!-- /.section -->\n\n      <div class="cf-error-footer cf-wrapper">\n  <p>\n    <span class="cf-footer-item">Cloudflare Ray ID: <strong>3d05c5de2d5c86fd</strong></span>\n    <span class="cf-footer-separator">•</span>\n    <span class="cf-footer-item"><span data-translate="your_ip">Your IP</span>: 217.29.182.172</span>\n    <span class="cf-footer-separator">•</span>\n    <span class="cf-footer-item"><span data-translate="performance_security_by">Performance & security by</span> <a data-orig-proto="https" data-orig-ref="www.cloudflare.com/5xx-error-landing?utm_source=error_footer" id="brand_link" target="_blank">Cloudflare</a></span>\n    \n  </p>\n</div><!-- /.error-footer -->\n\n\n    </div><!-- /#cf-error-details -->\n  </div><!-- /#cf-wrapper -->\n\n  <script type="text/javascript">\n  window._cf_translation = {};\n  \n  \n</script>\n\n</body>\n</html>\n')
Отменяем ордер ******************************
Облом: ('Ошибка анализа возвращаемых данных, получена строка', b'html\n[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]\n[if IE 7]>    <html class="no-js ie7 oldie" lang="en-US"> <![endif]\n[if IE 8]>    <html class="no-js ie8 oldie" lang="en-US"> <![endif]\n[if gt IE 8]><! <html class="no-js" lang="en-US"> <!--<![endif]-->\n<head>\n<title>Access denied | yobit.net used Cloudflare to restrict access</title>\n<meta charset="utf-8"/>\n<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>\n<meta content="IE=Edge,chrome=1" http-equiv="X-UA-Compatible"/>\n<meta content="noindex, nofollow" name="robots"/>\n<meta content="width=device-width,initial-scale=1,maximum-scale=1" name="viewport"/>\n<link href="/cdn-cgi/styles/cf.errors.css" id="cf_styles-css" media="screen,projection" rel="stylesheet" type="text/css"/>\n<!--[if lt IE 9]><link rel="stylesheet" id=\'cf_styles-ie-css\' href="/cdn-cgi/styles/cf.errors.ie.css" type="text/css" media="screen,projection" /><![endif]-->\n<style type="text/css">body{margin:0;padding:0}</style>\n<!--[if lte IE 9]><script type="text/javascript" src="/cdn-cgi/scripts/jquery.min.js"></script><![endif]-->\n<!--[if gte IE 10]><!--><script src="/cdn-cgi/scripts/zepto.min.js" type="text/javascript"></script><!--<![endif]-->\n<script src="/cdn-cgi/scripts/cf.common.js" type="text/javascript"></script>\n\n</head>\n<body>\n  <div id="cf-wrapper">\n    <div class="cf-alert cf-alert-error cf-cookie-error" data-translate="enable_cookies" id="cookie-alert">Please enable cookies.</div>\n    <div class="cf-error-details-wrapper" id="cf-error-details">\n      <div class="cf-wrapper cf-header cf-error-overview">\n        <h1>\n          <span class="cf-error-type" data-translate="error">Error</span>\n          <span class="cf-error-code">1015</span>\n          <small class="heading-ray-id">Ray ID: 3d05c5df9b3075e2 • 2017-12-20 21:42:41 UTC</small>\n        </h1>\n        <h2 class="cf-subheadline" data-translate="error_desc">You are being rate limited</h2>\n      </div><!-- /.header -->\n\n      <section></section><!-- spacer -->\n\n      <div class="cf-section cf-wrapper">\n        <div class="cf-columns two">\n          <div class="cf-column">\n            <h2 data-translate="what_happened">What happened?</h2>\n            <p>The owner of this website (yobit.net) has banned you temporarily from accessing this website.</p>\n          </div>\n\n          \n        </div>\n      </div><!-- /.section -->\n\n      <div class="cf-error-footer cf-wrapper">\n  <p>\n    <span class="cf-footer-item">Cloudflare Ray ID: <strong>3d05c5df9b3075e2</strong></span>\n    <span class="cf-footer-separator">•</span>\n    <span class="cf-footer-item"><span data-translate="your_ip">Your IP</span>: 217.29.182.172</span>\n    <span class="cf-footer-separator">•</span>\n    <span class="cf-footer-item"><span data-translate="performance_security_by">Performance & security by</span> <a data-orig-proto="https" data-orig-ref="www.cloudflare.com/5xx-error-landing?utm_source=error_footer" id="brand_link" target="_blank">Cloudflare</a></span>\n    \n  </p>\n</div><!-- /.error-footer -->\n\n\n    </div><!-- /#cf-error-details -->\n  </div><!-- /#cf-wrapper -->\n\n  <script type="text/javascript">\n  window._cf_translation = {};\n  \n  \n</script>\n\n</body>\n</html>\n')
Получаем историю торгов ******************************
Облом: ('Ошибка анализа возвращаемых данных, получена строка', b'html\n[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]\n[if IE 7]>    <html class="no-js ie7 oldie" lang="en-US"> <![endif]\n[if IE 8]>    <html class="no-js ie8 oldie" lang="en-US"> <![endif]\n[if gt IE 8]><! <html class="no-js" lang="en-US"> <!--<![endif]-->\n<head>\n<title>Access denied | yobit.net used Cloudflare to restrict access</title>\n<meta charset="utf-8"/>\n<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>\n<meta content="IE=Edge,chrome=1" http-equiv="X-UA-Compatible"/>\n<meta content="noindex, nofollow" name="robots"/>\n<meta content="width=device-width,initial-scale=1,maximum-scale=1" name="viewport"/>\n<link href="/cdn-cgi/styles/cf.errors.css" id="cf_styles-css" media="screen,projection" rel="stylesheet" type="text/css"/>\n<!--[if lt IE 9]><link rel="stylesheet" id=\'cf_styles-ie-css\' href="/cdn-cgi/styles/cf.errors.ie.css" type="text/css" media="screen,projection" /><![endif]-->\n<style type="text/css">body{margin:0;padding:0}</style>\n<!--[if lte IE 9]><script type="text/javascript" src="/cdn-cgi/scripts/jquery.min.js"></script><![endif]-->\n<!--[if gte IE 10]><!--><script src="/cdn-cgi/scripts/zepto.min.js" type="text/javascript"></script><!--<![endif]-->\n<script src="/cdn-cgi/scripts/cf.common.js" type="text/javascript"></script>\n\n</head>\n<body>\n  <div id="cf-wrapper">\n    <div class="cf-alert cf-alert-error cf-cookie-error" data-translate="enable_cookies" id="cookie-alert">Please enable cookies.</div>\n    <div class="cf-error-details-wrapper" id="cf-error-details">\n      <div class="cf-wrapper cf-header cf-error-overview">\n        <h1>\n          <span class="cf-error-type" data-translate="error">Error</span>\n          <span class="cf-error-code">1015</span>\n          <small class="heading-ray-id">Ray ID: 3d05c5e17bfe7672 • 2017-12-20 21:42:42 UTC</small>\n        </h1>\n        <h2 class="cf-subheadline" data-translate="error_desc">You are being rate limited</h2>\n      </div><!-- /.header -->\n\n      <section></section><!-- spacer -->\n\n      <div class="cf-section cf-wrapper">\n        <div class="cf-columns two">\n          <div class="cf-column">\n            <h2 data-translate="what_happened">What happened?</h2>\n            <p>The owner of this website (yobit.net) has banned you temporarily from accessing this website.</p>\n          </div>\n\n          \n        </div>\n      </div><!-- /.section -->\n\n      <div class="cf-error-footer cf-wrapper">\n  <p>\n    <span class="cf-footer-item">Cloudflare Ray ID: <strong>3d05c5e17bfe7672</strong></span>\n    <span class="cf-footer-separator">•</span>\n    <span class="cf-footer-item"><span data-translate="your_ip">Your IP</span>: 217.29.182.172</span>\n    <span class="cf-footer-separator">•</span>\n    <span class="cf-footer-item"><span data-translate="performance_security_by">Performance & security by</span> <a data-orig-proto="https" data-orig-ref="www.cloudflare.com/5xx-error-landing?utm_source=error_footer" id="brand_link" target="_blank">Cloudflare</a></span>\n    \n  </p>\n</div><!-- /.error-footer -->\n\n\n    </div><!-- /#cf-error-details -->\n  </div><!-- /#cf-wrapper -->\n\n  <script type="text/javascript">\n  window._cf_translation = {};\n  \n  \n</script>\n\n</body>\n</html>\n')
Получаем кошель для пополнения (BTC) ******************************
Облом: ('Ошибка анализа возвращаемых данных, получена строка', b'html\n[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]\n[if IE 7]>    <html class="no-js ie7 oldie" lang="en-US"> <![endif]\n[if IE 8]>    <html class="no-js ie8 oldie" lang="en-US"> <![endif]\n[if gt IE 8]><! <html class="no-js" lang="en-US"> <!--<![endif]-->\n<head>\n<title>Access denied | yobit.net used Cloudflare to restrict access</title>\n<meta charset="utf-8"/>\n<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>\n<meta content="IE=Edge,chrome=1" http-equiv="X-UA-Compatible"/>\n<meta content="noindex, nofollow" name="robots"/>\n<meta content="width=device-width,initial-scale=1,maximum-scale=1" name="viewport"/>\n<link href="/cdn-cgi/styles/cf.errors.css" id="cf_styles-css" media="screen,projection" rel="stylesheet" type="text/css"/>\n<!--[if lt IE 9]><link rel="stylesheet" id=\'cf_styles-ie-css\' href="/cdn-cgi/styles/cf.errors.ie.css" type="text/css" media="screen,projection" /><![endif]-->\n<style type="text/css">body{margin:0;padding:0}</style>\n<!--[if lte IE 9]><script type="text/javascript" src="/cdn-cgi/scripts/jquery.min.js"></script><![endif]-->\n<!--[if gte IE 10]><!--><script src="/cdn-cgi/scripts/zepto.min.js" type="text/javascript"></script><!--<![endif]-->\n<script src="/cdn-cgi/scripts/cf.common.js" type="text/javascript"></script>\n\n</head>\n<body>\n  <div id="cf-wrapper">\n    <div class="cf-alert cf-alert-error cf-cookie-error" data-translate="enable_cookies" id="cookie-alert">Please enable cookies.</div>\n    <div class="cf-error-details-wrapper" id="cf-error-details">\n      <div class="cf-wrapper cf-header cf-error-overview">\n        <h1>\n          <span class="cf-error-type" data-translate="error">Error</span>\n          <span class="cf-error-code">1015</span>\n          <small class="heading-ray-id">Ray ID: 3d05c5e35a9586af • 2017-12-20 21:42:42 UTC</small>\n        </h1>\n        <h2 class="cf-subheadline" data-translate="error_desc">You are being rate limited</h2>\n      </div><!-- /.header -->\n\n      <section></section><!-- spacer -->\n\n      <div class="cf-section cf-wrapper">\n        <div class="cf-columns two">\n          <div class="cf-column">\n            <h2 data-translate="what_happened">What happened?</h2>\n            <p>The owner of this website (yobit.net) has banned you temporarily from accessing this website.</p>\n          </div>\n\n          \n        </div>\n      </div><!-- /.section -->\n\n      <div class="cf-error-footer cf-wrapper">\n  <p>\n    <span class="cf-footer-item">Cloudflare Ray ID: <strong>3d05c5e35a9586af</strong></span>\n    <span class="cf-footer-separator">•</span>\n    <span class="cf-footer-item"><span data-translate="your_ip">Your IP</span>: 217.29.182.172</span>\n    <span class="cf-footer-separator">•</span>\n    <span class="cf-footer-item"><span data-translate="performance_security_by">Performance & security by</span> <a data-orig-proto="https" data-orig-ref="www.cloudflare.com/5xx-error-landing?utm_source=error_footer" id="brand_link" target="_blank">Cloudflare</a></span>\n    \n  </p>\n</div><!-- /.error-footer -->\n\n\n    </div><!-- /#cf-error-details -->\n  </div><!-- /#cf-wrapper -->\n\n  <script type="text/javascript">\n  window._cf_translation = {};\n  \n  \n</script>\n\n</body>\n</html>\n')
>>>
21.12.2017 10:32
>>> The owner of this website (yobit.net) has banned you temporarily from accessing this website
Вас забанили :) 
Непонятно почему, раньше такого не было) Может DDOSят их или еще чего - много ботов одновременно запущено?

Добавьте в самый вверх import time
и после каждого обращения к API пишите
time.sleep(1)
- замедлите количество обращений
20.12.2017 22:05
а при запуске через cmd 
Microsoft Windows [Version 6.1.7601]
(c) Корпорация Майкрософт (Microsoft Corp.), 2009. Все права защищены.

C:\Users\1>C:\OSPanel\domains\site.ru\phyton\scrypt+key.py
Получаем информацию по аккаунту ******************************
Traceback (most recent call last):
  File "C:\OSPanel\domains\site.ru\phyton\scrypt+key.py", line 62, in <module>
    print( call_api(method="getInfo") )
  File "C:\OSPanel\domains\site.ru\phyton\scrypt+key.py", line 56, in call_api
    raise YobitException(obj['error'])
__main__.YobitException: invalid nonce (has already been used)

C:\Users\1>
</module>
21.12.2017 10:33
Остановите всех ботов, смените ключи на бирже, должно помочь
08.01.2018 02:42
Здравствуйте!
А что означает (при попытке вывести цены для пары из вашего примера):
./001.py: строка 4: ошибка синтаксиса около неожиданной лексемы `('
./001.py: строка 4: `res = requests.get('https://yobit.net/api/3/info') # получаем данные'
13.01.2018 20:15
Лишняя кавычка в начале строки `res
Её там быть не должно
13.01.2018 19:22
С Эксмо работает всё хорошо а вот тук ни как всё время выдаёт ошибку 
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777)
что делать?
13.01.2018 20:19
Разобрался, ошибка вышла после установки Python 3.6 на Mac OS. Необходимо обновить сертификаты, решается вводом в терминал следующей строки  /Applications/Python\ 3.6/Install\ Certificates.command
13.01.2018 20:22
Сертификат не проходит проверку.. Возможно вы запускаете бота где-то, где админы прослушивают шифрованный трафик?
Как вариант запустите бота на стороннем сервере, пример https://bablofil.ru/kak-zapustit-bota-na-servere/.
Можно попробовать выйти в интернет через мобильную сеть, и попробовать через неё.
Можно попробовать работать через proxy, но это будет грустно, медленно и постоянно отваливаться.
13.01.2018 20:23
Здорово, спасибо за информацию
13.01.2018 20:23
BTW, размещена новая статья с ботом для yobit, можно потестить
https://bablofil.ru/bot-dlya-birgi-yobit/
17.01.2018 23:15
По скрипту для получения всех пар с ценами,
пробовал на разных ОС но всё время выходит ошибка 

после
 2950 moto_waves 0.00000043 0.00999269

Traceback (most recent call last):
  File "/Users/nikolay/Documents/test.py", line 21, in <module>
    '%0.8f' % ticker_res_obj[pair]['buy'],
TypeError: 'int' object is not subscriptable
дебагером выловил значение вместо очередной пары, пишет равно success 
</module>
22.01.2018 05:44
Добрый день.

Что-то youbit по публичному API из python-a выдает 503 ошибку. Из браузера все нормально. С разных ip пробовал тоже.
Даже headers пробовал добавлять.

import json
import requests

headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}

res = requests.get('http://yobit.net/api/3/ticker/ltc_btc-nmc_btc', headers=headers)
print (res)
res_obj = json.loads(res.text)
print (res_obj)

Вывод:
<response [503]="">
Traceback (most recent call last):
  File "test3_1.py", line 8, in <module>
    res_obj = json.loads(res.text)
  File "/usr/lib/python2.7/json/__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python2.7/json/decoder.py", line 366, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python2.7/json/decoder.py", line 384, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

Пробовал публичный API от криптопии, все работает.
res = requests.get('https://www.cryptopia.co.nz/api/GetCurrencies', headers=headers)
</module></response>
22.01.2018 06:41
У них защита от DDOS
Замените yobit.net на yobit.io как временное решение
22.01.2018 18:32
Заменил, спасибо. Днем работало. Сейчас и на io тоже 503 стало, к сожалению.
22.01.2018 18:38
И вообще их логика не совсем понятна. Api же именно для роботов сделали. Если бы еще по частоте обращений к API какую-то паузу включали, а тут прям с первого раза.
23.01.2018 06:39
workaround - https://github.com/Anorov/cloudflare-scrape
23.01.2018 20:07
Здравствуйте!
Подскажите, пожалуйста, ответ на нубский вопрос:
Как должны прописаться в итоге параметры и значения, т.е. как должна выглядеть итоговая ссылка  https://yobit.net/api/3/....  к примеру для:

TradeHistory
Метод возвращает историю сделок.
Требования: привилегия ключа info
Параметры:
from: номер сделки, с которой начинать вывод (значения: числовые, по умолчанию: 0)
count: количество сделок для вывода (значения: числовые, по умолчанию: 1000)
from_id: ID сделки, с которой начинать вывод (значения: числовые, по умолчанию: 0)
end_id: ID сделки, на которой заканчивать вывод (значения: числовые, по умолчанию: )
order: сортировка при выводе (значения: ASC или DESC, по умолчанию: DESC)
since: с какого времени начинать вывод (значения: unix time, по умолчанию: 0)
end: на каком времени заканчивать вывод (значения: unix time, по умолчанию: )
pair: пара (пример: ltc_btc)
23.01.2018 21:17
Добрый день!
Ссылка будет выглядеть именно так: https://yobit.net/tapi/
В браузере вы этого не посмотрите, т.к. данные должны быть отправлены POSTом , подписаны криптографией и т.п. - это приватные методы, а по прямой ссылке без авторизации можно смотреть только публичные.

Если говорить про код из статьи, то необходимо нужные параметры передать в функцию, например
call_api(
    method="TradeHistory", 
    pair="ltc_btc",
    from=1000,
    count=200,
    order="ASC"
)
25.01.2018 10:15
Андрей, подскажите как правильно воспользоваться методом пополнения купонов RedeemCoupon
при попытке выполнить такой код 
                   x = "YOBIT.....USD"
                    try:
                         print('Попытка пополнить баланс', '*' * 30)
                         call_api(method="RedeemCoupon", coupon=x)
                     except ScriptError as e:
                         print(e)
                     except ScriptQuitCondition as e:
                         print(e)
                     except Exception as e:
                         print("!!!!", e)
получаю ошибку('Ошибка анализа возвращаемых данных, получена строка', b'html\n[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]\n[if IE 7]>    <html class="no-js ie7 oldie" lang="en-US"> <![endif]\n[if IE 8]>    <html class="no-js ie8 oldie" lang="en-US"> <![endif]\n[if gt IE 8]><! <html class="no-js" lang="en-US"> <!--<![endif]-->\n<head>\n<title>Access denied | yobit.net used Cloudflare to restrict access</title>\n<meta charset="utf-8"/>\n<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>\n<meta content="IE=Edge,chrome=1" http-equiv="X-UA-Compatible"/>\n<meta content="noindex, nofollow" name="robots"/>\n<meta content="width=device-width,initial-scale=1,maximum-scale=1" name="viewport"/>\n<link href="/cdn-cgi/styles/cf.errors.css" id="cf_styles-css" media="screen,projection" rel="stylesheet" type="text/css"/>\n<!--[if lt IE 9]><link rel="stylesheet" id=\'cf_styles-ie-css\' href="/cdn-cgi/styles/cf.errors.ie.css" type="text/css" media="screen,projection" /><![endif]-->\n<style type="text/css">body{margin:0;padding:0}</style>\n<!--[if lte IE 9]><script type="text/javascript" src="/cdn-cgi/scripts/jquery.min.js"></script><![endif]-->\n<!--[if gte IE 10]><!--><script src="/cdn-cgi/scripts/zepto.min.js" type="text/javascript"></script><!--<![endif]-->\n<script src="/cdn-cgi/scripts/cf.common.js" type="text/javascript"></script>\n\n</head>\n<body>\n  <div id="cf-wrapper">\n    <div class="cf-alert cf-alert-error cf-cookie-error" data-translate="enable_cookies" id="cookie-alert">Please enable cookies.</div>\n    <div class="cf-error-details-wrapper" id="cf-error-details">\n      <div class="cf-wrapper cf-header cf-error-overview">\n        <h1>\n          <span class="cf-error-type" data-translate="error">Error</span>\n          <span class="cf-error-code">1015</span>\n          <small class="heading-ray-id">Ray ID: 3e2a68837da3840c • 2018-01-25 10:04:25 UTC</small>\n        </h1>\n        <h2 class="cf-subheadline" data-translate="error_desc">You are being rate limited</h2>\n      </div><!-- /.header -->\n\n      <section></section><!-- spacer -->\n\n      <div class="cf-section cf-wrapper">\n        <div class="cf-columns two">\n          <div class="cf-column">\n            <h2 data-translate="what_happened">What happened?</h2>\n            <p>The owner of this website (yobit.net) has banned you temporarily from accessing this website.</p>\n          </div>\n\n          \n        </div>\n      </div><!-- /.section -->\n\n      <div class="cf-error-footer cf-wrapper">\n  <p>\n    <span class="cf-footer-item">Cloudflare Ray ID: <strong>3e2a68837da3840c</strong></span>\n    <span class="cf-footer-separator">•</span>\n    <span class="cf-footer-item"><span data-translate="your_ip">Your IP</span>: 46.211.120.1</span>\n    <span class="cf-footer-separator">•</span>\n    <span class="cf-footer-item"><span data-translate="performance_security_by">Performance & security by</span> <a data-orig-proto="https" data-orig-ref="www.cloudflare.com/5xx-error-landing?utm_source=error_footer" id="brand_link" target="_blank">Cloudflare</a></span>\n    \n  </p>\n</div><!-- /.error-footer -->\n\n\n    </div><!-- /#cf-error-details -->\n  </div><!-- /#cf-wrapper -->\n\n  <script type="text/javascript">\n  window._cf_translation = {};\n  \n  \n</script>\n\n</body>\n</html>\n')
25.01.2018 10:48
The owner of this website (yobit.net) has banned you temporarily from accessing this website.
Yobit на вас обиделся, за то, что слишком часто дергаете его API, попробуйте остановить всех ботов и попробовать через пару минут.
Можно еще попробовать сменить yobit.net на yobit.io, по идее это разные настройки CloudFlare
Ну и если не будет получаться, попробуйте RedeemCoupon сменить на RedeemYobicode
28.01.2018 20:44
Спасибо банк таки сняли со временем. Но с RedeemCoupon и RedeemYobicode ни как не справлюсь, всё время выдаёт  "invalid method"
29.01.2018 12:05
Я смотрю, этот метод добавили несколько месяцев назад (https://twitter.com/yobitexchange/status/908319069195120640), но не вижу, что бы у кого-то работал.. Я взял php код из их твита, проверил на нём - то же самое.. Написал в техподдержку, не знаю когда ответят..
25.01.2018 20:16
"Открытых ордеров нет" это cloudflare и ли ошибка авторизации? Запускал в течении дня несколько раз и не разу не вошел
25.01.2018 21:19
Вроде всё верно прописал, ничего лишнего не трогал.
HttpAnalyzer выдало:
Date: Thu, 25 Jan 2018 21:12:36 GMT
Content-Type: text/html; charset=utf8
Connection: keep-alive
Set-Cookie: __cfduid=dba592affd2bc33f044f534d39a06750d1516914756; expires=Fri, 25-Jan-19 21:12:36 GMT; path=/; domain=.yobit.io; HttpOnly; Secure
Set-Cookie: locale=en; expires=Tue, 25-Jan-2028 21:12:36 GMT; path=/
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block;
x-download-options: noopen
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 3e2e3b49487e8ecd-DME
Content-Length: 61

{"success":0,"error":"invalid nonce (has already been used)"}
25.01.2018 21:35
Разобрался , увеличил нонсе до приемлемого получил ответ 
{"success":1,"return":{"rights":{"info":1,"trade":1,"deposit":1,"withdraw":0},"transaction_count":0,"open_orders":0,"server_time":1516915491}}.
Андрей, в кодировании я слаб, это первый код на питоне которым пользуюсь, подскажите пожалуйста, как, куда  можно внедрить на основе этого скрипта другие  методы - "TradeHistory" и тд., что удалить приписать
call_api(
    method="TradeHistory", 
    pair="ltc_btc",
    from=1000,
    count=200,
    order="ASC"
)
25.01.2018 21:42
Прошу прощения, похоже не туда запостил, надо было в теме бота
25.01.2018 23:21
Вообщем внедрил ).
Для примера использовал некоторые методы выше. На купон отозвалось invalid method,  а вариант
 call_api(
    method="TradeHistory", 
    pair="ltc_btc",
    from=1000,
    count=200,
    order="ASC"
)
 не прокатил. почему-то IDLE  стопорится на  from. Питон оказывается очень чувствителен к местоположению кода, пробелам, но так я этот from не победил, похоже принимает за функцию
26.01.2018 07:00
Да уж, с from нехорошо вышло, это зарезервированное слово, и вот так вот его использовать нельзя, к сожалению
26.01.2018 04:33
Здравствуйте, возникают такие ошибки:
Traceback (most recent call last):
  File "C:\Users\....\pyt1.py", line 66, in <module>
    print( call_api(method="getInfo") )
  File "C:\Users\....\pyt1.py", line 40, in call_api
    H = hmac.new(key=API_SECRET, digestmod=hashlib.sha512)
  File "C:\Users\...\hmac.py", line 144, in new
    return HMAC(key, msg, digestmod)
  File "C:\Users\...\lib\hmac.py", line 42, in __init__
    raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
TypeError: key: expected bytes or bytearray, but got 'str'

Как их исправить?</module>
26.01.2018 06:44
Вы букву b забыли перед строкой с секретом
API_KEY = ''
API_SECRET = b''
28.01.2018 12:56
Спасибо за класные статьи про программирование ботов на Python - самом няшном языке, даже такой двоечник как я , все понимаю, ну почти все  :)  Можно пару маленьких вопросов и одну большую просьбу?
Не могу понять что происходит в этих строчках? Поясни пожалуста.

inp.seek(0) 
inp.truncate()  
payload =  urllib.parse.urlencode(payload) 
H.update(payload.encode('utf-8'))  
sign = H.hexdigest()   

Если отключится интернет, тоже ведь ошибка выскочит и бот закроется? Как ее грамотно обработать? Мож так?
try:
    conn = http.client.HTTPSConnection("yobit.net", timeout=60) 
    conn.request("POST", "/tapi/", payload, headers) 
    response = conn.getresponse().read() 
except YobitException:  
   print ("Нет связи с сайтом! ", Exception )
finally:  
   conn.close()       #  ? Можно ли закрывать соединение, если его не удалось открыть ?

Ты используешь в боте модуль http.client а не requests. Почему? Он быстрее работает? 
Не ограничивает ли биржа Yobit количество запросов в минуту и не забанит ли IP если их будет слишком много? А то как запущю 10 ботов и все, приехали. 

Большая просьба - Напиши пожалуйста функцию для GET запросов (info, ticker, depth, trades). Они жеш тожеш нужныжеш. :) А то у меня не получается. Сделал по аналогии с твоей функцией, пишет ошибка в json и 404 страница не найдена. Понимаю можно на requests'е сделать, но я читал, что он самый медленный, http вроде побыстрее.

def call_api_Get(**kwargs):
    payload = {}                 
    if kwargs:            
       payload.update(kwargs)      
       
    payload = urllib.parse.urlencode(payload)  
    payload = payload.encode('utf-8')          
    
    headers = {"Content-type": "application/x-www-form-urlencoded"} 
    conn = http.client.HTTPSConnection("yobit.net", timeout=60)     
    conn.request("GET", "/api/3/", 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('Ошибка json - ', response)
28.01.2018 17:05
На сайте есть пример бота для yobit,  https://bablofil.ru/bot-dlya-birgi-yobit/ там используется и requests и публичные методы, можно взять всё нужное оттуда.
requests отличный модуль, очень жаль что он не идет по умолчанию в с питоном, а http.client идет, поэтому иногда проще дать готовый код, который не требует доустановки модулей. Забирайте им публичные данные, вам все равно нельзя часто запросы делать на биржу, забанят. 
Yobit якобы разрешает 100 запросов в минуту - так они сами говорят, но по опыту они считают по секундам - если 10 или 15 запросов прошли за несколько секунд (5, вроде бы), то временная блокировка. Если переждать минутку, можно продолжать. Если продолжать бомбить, то блокировка надолго. Они напишут в ответе что-то вроде DDOS 20-50 min, и сам сайт нельзя будет открыть, т.к. он будет отдавать 429 заголовок через CloudFlare.
inp.seek(0)  - перейти в самое начало файла
inp.truncate()  - очистить содержимое файла
payload =  urllib.parse.urlencode(payload)  - привести содержимое массива в строку GET/POST запроса. Выведите на экран до и после
H.update(payload.encode('utf-8'))   - добавить строку для создания криптоподписи
sign = H.hexdigest()  - забрать шестнадцатеричные символы, они и будут отправлены на биржу
28.01.2018 18:14
Понял. спасибо. На сайте yobit вроде нигде не видел инфы про лимиты на запросы, думал таки что их нет. Интересно а можно как-то обмануть сервер и подсунуть ему другой IP ?
28.01.2018 18:30
Вот ссылка https://yobit.net/ru/rules/, не знаю как с сайта на неё выйти )
IP подсунуть можно, но ведь и ответ сервера на этапе установления соединения уйдет на чужой IP, и ничего не выйдет
30.01.2018 13:51
Подскажите, пожалуйста, как можно получить номера ордеров и присвоить им переменные, к примеру, a - номер 1го ордера, b - номер 2го ордера.
try:
    print ('Получаем список активных ордеров', '*'*30)
    print( call_api(method="ActiveOrders", pair="doge_rur") )
except YobitException as e:
    print("Облом:", e)
    
получаем
Получаем список активных ордеров ******************************
{'success': 1, 'return': {'150008417528326': {'pair': 'doge_rur', 'type': 'buy', 'amount': 1, 'rate': 0.25, 'timestamp_created': '1517319714', 'status': 0}, '150008417528164': {'pair': 'doge_rur', 'type': 'buy', 'amount': 1, 'rate': 0.25, 'timestamp_created': '1517319708', 'status': 0}}}

нужно
a = 150008417528326
b = 150008417528164

а также хотелось бы вынести
amount = 1
rate = 0.25
30.01.2018 17:46
Пройтись по ордерам можно, например, так:

active_orders =  call_api(method="ActiveOrders", pair="doge_rur").get('return', {})
for order in active_orders:
    print("OrderID", order)
    print("Amount", active_orders[order]['amount'])
    print("Rate", active_orders[order]['rate'])

Ну а там можно и переменные присвоить, но зачем если все и так уже сохранено в словаре?
30.01.2018 18:21
Большое спасибо за ответ.  Я хочу, чтобы программа узнавала номер ордера и автоматически, если он ненужный, ставила его на удаление, поэтому каждому ордеру хочу присвоить переменную, чтобы потом подставить в номер ордера. Или же если так не получится- код на удаление всех ордеров на покупку или продажу.

try:
    print ('Отменяем ордер', '*'*30)
    print( call_api(method="CancelOrder", order_id="номер ордера") )
except YobitException as e:
    print("Облом:", e)

OrderID 150008417528326
Amount 1
Rate 0.25
OrderID 150008417528164
Amount 1
Rate 0.25
Подскажите, пожалуйста, как сделать присвоение перемеренных каждому номеру ордера.
30.01.2018 19:12
Для того, что бы хранить однотипные ордера существуют словари и массивы.
Что если у вас будет 50 ордеров? Как вы их будете называть? Чем вас не устраивают ID которые уже есть у них? )

Вот этот кусок кода отменит все открытые ордера по паре - при этом на каждой итерации цикла переменная order содержит в себе значение order_id биржи. Эта переменная передается функции, которая отменяет ордер.

active_orders =  call_api(method="ActiveOrders", pair="doge_rur").get('return', {})
for order in active_orders:
    print("OrderID", order)
    print("Amount", active_orders[order]['amount'])
    print("Rate", active_orders[order]['rate'])
    print( call_api(method="CancelOrder", order_id=order) )

Вы можете его как-то расширить, например, добавить проверку, например, отменять только те ордера, у которых объем меньше, чем 0.1:

active_orders =  call_api(method="ActiveOrders", pair="doge_rur").get('return', {})
for order in active_orders:
    print("OrderID", order)
    print("Amount", active_orders[order]['amount'])
    print("Rate", active_orders[order]['rate'])
    if float(active_orders[order]['amount']) < 0.1:
        print( call_api(method="CancelOrder", order_id=order) )
30.01.2018 19:56
Огромное спасибо. Я просто новичок в этом.
31.01.2018 20:16
Я написал программу, прикрепил к ней для управления бота Телеграм, протестировал на компьютере, все работает, перенес на VDS - функция покупки(сама отправка запроса на покупку) перестала работать. С чем это может быть связано?
Действия с публичным API выполняются корректно, с приватным - нет.
31.01.2018 20:26
nonce наверное забыли перенести.
Попробуйте создать API ключи новые, должно завестись
01.02.2018 18:14
Пищу такой код, то есть "насильно" заставляю покупать на сумму, больше, чем 0.0001 BTC, в 10 раз.
buy_coin = call_api(method="Trade", pair= zapros, type="buy", rate=0.00002016, amount=50)
0.00002016 * 50 =0.001 BTC
Выдает такую ошибку:
Total transaction amount is less than minimal total: 0.00010000
 Как с этим бороться? Пробовал и не один раз, с монетами, которые мало стоят, часто такое происходит.
01.02.2018 18:45
Попробуйте так - может быть из-за формы записи такое

buy_coin = call_api(
    method="Trade", 
    pair= zapros, 
    type="buy", 
    rate="{rate:0.8f}".format(rate=0.00002016), 
    amount="{amount:0.8f}".format(amount=50)
)

Ну и плюс там еще могут быть механизмы округления внутри биржи, при обработке поступившего запроса, попробуйте передать чуть больше для проверки
05.02.2018 16:08
Здравсвуйте, подскажите в чем может быть дело. Скопировал Ваш код, подставил свой апи и секрет, запусткаю и выдает вот это. 

Получаем информацию по аккаунту ******************************
Traceback (most recent call last):
  File "yobit-test.py", line 62, in <module>
    print( call_api(method="getInfo") )
  File "yobit-test.py", line 47, in call_api
    conn.request("POST", "/tapi/", payload, headers)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1239, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1285, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1234, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1026, in _send_output
    self.send(msg)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 964, in send
    self.connect()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1400, in connect
    server_hostname=server_hostname)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 407, in wrap_socket
    _context=self, _session=session)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 814, in __init__
    self.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 1068, in do_handshake
    self._sslobj.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 689, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777)</module>
05.02.2018 16:18
Прошу прощения, ответ сам нашел. https://stackoverflow.com/questions/38835270/i-get-certificate-verify-failed-when-i-try-to-install-the-spacy-english-language
06.02.2018 17:47
Андрей, спасайте. Что то они там на Yobit сделали, и теперь ничего не работает, хотя еще вчера все работало как часы. Обычные гет запросы присылают ошибку 503, а пост запосы - страничку "Включите джаваскипт и перезагрузитесь". Пауза между запросами 2 секунды.
 Поисковик выдает только анлоязычные странички с решением проблемы и я чтото не осилю, как их внедрить в бота, может вы постмотрите. Они вроде маленькие.
https://stackoverflow.com/questions/8049520/web-scraping-javascript-page-with-python
Как я понял самый грамотный вариант с "from PyQt4..."
https://impythonist.wordpress.com/2015/01/06/ultimate-guide-for-scraping-javascript-rendered-web-pages/
https://www.youtube.com/watch?v=FSH77vnOGqU
Да, я поменял yobit.net на yobit.io, и он работает, но нет гарантии что завтра и он не заставит включать джаваскрипты. К тому же, может вам тоже будет это интересно на будущее, как парсить такие сайты.
08.03.2018 13:06
Здравствуйте подскажите как разбить данные из запроса https://yobit.net/api/3/depth/ltc_btc?limit=1, нужно вывести на экран сумму стоящего в стакане ордера покупка/продажа.
Пока получается только так:
res = requests.get('https://yobit.net/api/3/depth/ltc_btc?limit=1')
res_obj = json.loads(res.text)

print(res_obj['ltc_btc']['asks'])
10.03.2018 10:37
Нашел у Вас в статьях! Спасибо огромное.
31.05.2018 20:11
а можно торговать на Yobit через прокси Tor?
пытаюсь отправить get запрос с использованием прокси, ответ не приходит. без использования прокси - всё работает.
понадобилось, чтобы обойти лимит на частоту запросов.

proxies = {
    'http': 'socks5://localhost:9060',
    'https': 'socks5://localhost:9060'
}
#проверяю, что ip поменялся
url = 'http://icanhazip.com/'
out = requests.get(url, proxies=proxies).text
out = (out.replace('\n',''))
print(out)

#запрос к бирже
depth = requests.get('https://yobit.io/api/3/depth/ltc_btc?limit=1', timeout=60)
depth_call = json.loads(depth.text)  # переводим полученный текст в объект с данными


результат:
Traceback (most recent call last):
  File "C:/arazr/python_temp/pump/tst_tor.py", line 87, in <module>
    depth_call = json.loads(depth.text)  # переводим полученный текст в объект с данными
  File "C:\Users\A\AppData\Local\Programs\Python\Python36-32\lib\json\__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "C:\Users\A\AppData\Local\Programs\Python\Python36-32\lib\json\decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:\Users\A\AppData\Local\Programs\Python\Python36-32\lib\json\decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)</module>
31.05.2018 20:13
Выше ошибся:
запрос отправляю так:
depth = requests.get('https://yobit.io/api/3/depth/ltc_btc?limit=1', timeout=60, proxies=proxies)
01.06.2018 08:50
Да, но надо на каждый запрос новое identity или цепь создавать, иначе все равно упретесь в ограничения
Перед строкой
depth_call = json.loads(depth.text)  # переводим полученный текст в объект с данными
добавьте 
print(depth.text) 
Посмотрите, что там пишется
P.S. обычно тор запускается на порту 9050, а у вас указано 9060, может быть, опечатка?
01.06.2018 10:11
Спасибо за помощь!
Я настроил Тор для запуска нескольких экземпляров на разных портах, тор точно ip меняет - тут проблем никаких.
мне кажется  это у ёбита защита, а как понять куда она смотрит  и как её обойти я не знаю.


Вывод depth.text:

html
[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]
[if IE 7]>    <html class="no-js ie7 oldie" lang="en-US"> <![endif]
[if IE 8]>    <html class="no-js ie8 oldie" lang="en-US"> <![endif]
[if gt IE 8]><! <html class="no-js" lang="en-US"> <!--<![endif]-->
<head>
<title>Attention Required! | Cloudflare</title>
<meta id="captcha-bypass" name="captcha-bypass"/>
<meta charset="utf-8"/>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<meta content="IE=Edge,chrome=1" http-equiv="X-UA-Compatible"/>
<meta content="noindex, nofollow" name="robots"/>
<meta content="width=device-width,initial-scale=1,maximum-scale=1" name="viewport"/>
<link href="/cdn-cgi/styles/cf.errors.css" id="cf_styles-css" media="screen,projection" rel="stylesheet" type="text/css"/>
<!--[if lt IE 9]><link rel="stylesheet" id='cf_styles-ie-css' href="/cdn-cgi/styles/cf.errors.ie.css" type="text/css" media="screen,projection" /><![endif]-->
<style type="text/css">body{margin:0;padding:0}</style>


<!--[if gte IE 10]><!--><script src="/cdn-cgi/scripts/zepto.min.js" type="text/javascript"></script><!--<![endif]-->
<!--[if gte IE 10]><!--><script src="/cdn-cgi/scripts/cf.common.js" type="text/javascript"></script><!--<![endif]-->




</head>
<body>
  <div id="cf-wrapper">
    <div class="cf-alert cf-alert-error cf-cookie-error" data-translate="enable_cookies" id="cookie-alert">Please enable cookies.</div>
    <div class="cf-error-details-wrapper" id="cf-error-details">
      <div class="cf-wrapper cf-header cf-error-overview">
        <h1 data-translate="challenge_headline">One more step</h1>
        <h2 class="cf-subheadline"><span data-translate="complete_sec_check">Please complete the security check to access</span> yobit.io</h2>
      </div><!-- /.header -->
      
      <div class="cf-section cf-highlight cf-captcha-container">
        <div class="cf-wrapper">
          <div class="cf-columns two">
            <div class="cf-column">
            
              <div class="cf-highlight-inverse cf-form-stacked">
                <form action="/cdn-cgi/l/chk_captcha" class="challenge-form" id="challenge-form" method="get">
  <script async="" data-ray="4240d9cc1ec369b2" data-sitekey="6LfBixYUAAAAABhdHynFUIMA_sa4s-XsJvnjtgB0" data-type="normal" src="/cdn-cgi/scripts/cf.challenge.js" type="text/javascript"></script>
  <div class="g-recaptcha"></div>
  <noscript class="cf-captcha-info" id="cf-captcha-bookmark">
    <div><div style="width: 302px">
      <div>
        <iframe frameborder="0" scrolling="no" src="https://www.google.com/recaptcha/api/fallback?k=6LfBixYUAAAAABhdHynFUIMA_sa4s-XsJvnjtgB0" style="width: 302px; height:422px; border-style: none;"></iframe>
      </div>
      <div style="width: 300px; border-style: none; bottom: 12px; left: 25px; margin: 0px; padding: 0px; right: 25px; background: #f9f9f9; border: 1px solid #c1c1c1; border-radius: 3px;">
        <textarea class="g-recaptcha-response" id="g-recaptcha-response" name="g-recaptcha-response" style="width: 250px; height: 40px; border: 1px solid #c1c1c1; margin: 10px 25px; padding: 0px; resize: none;"></textarea>
        <input type="submit" value="Submit"/>
      </div>
    </div></div>
  </noscript>
</form>

              </div>
            </div>

            <div class="cf-column">
              <div class="cf-screenshot-container">
              
                <span class="cf-no-screenshot"></span>
              
              </div>
            </div>
          </div><!-- /.columns -->
        </div>
      </div><!-- /.captcha-container -->

      <div class="cf-section cf-wrapper">
        <div class="cf-columns two">
          <div class="cf-column">
            <h2 data-translate="why_captcha_headline">Why do I have to complete a CAPTCHA?</h2>
            
            <p data-translate="why_captcha_detail">Completing the CAPTCHA proves you are a human and gives you temporary access to the web property.</p>
          </div>

          <div class="cf-column">
            <h2 data-translate="resolve_captcha_headline">What can I do to prevent this in the future?</h2>
            

            <p data-translate="resolve_captcha_antivirus">If you are on a personal connection, like at home, you can run an anti-virus scan on your device to make sure it is not infected with malware.</p>

            <p data-translate="resolve_captcha_network">If you are at an office or shared network, you can ask the network administrator to run a scan across the network looking for misconfigured or infected devices.</p>
            
          </div>
        </div>
      </div><!-- /.section -->
      

      <div class="cf-error-footer cf-wrapper">
  <p>
    <span class="cf-footer-item">Cloudflare Ray ID: <strong>4240d9cc1ec369b2</strong></span>
    <span class="cf-footer-separator"></span>
    <span class="cf-footer-item"><span>Your IP</span>: 95.130.10.69</span>
    <span class="cf-footer-separator"></span>
    <span class="cf-footer-item"><span>Performance & security by</span> <a href="https://www.cloudflare.com/5xx-error-landing?utm_source=error_footer" id="brand_link" target="_blank">Cloudflare</a></span>
    
  </p>
</div><!-- /.error-footer -->


    </div><!-- /#cf-error-details -->
  </div><!-- /#cf-wrapper -->

  <script type="text/javascript">
  window._cf_translation = {};
  
  
</script>

</body>
</html>
01.06.2018 11:30
Ну да, именно защита. Это CloudFlare, за которой прячется yobit, просит вас включить куки и разгадать капчу
Тут выше в комментариях есть ссылка на библиотеку, которая позволяет эту защиту обходить
04.06.2018 10:32
попробовал с библиотечкой поиграться - не получилось обойти защиту (
сама библиотека работает, без прокси всё ок, запросы через прокси на Yobit не срабатывают. 
может такое быть, что CloudFlare понимает, что это адреса Tor и блокирует их?
Проверить на других адресах тоже пока не получается, т.к. ip из открытых списков совсем плохо работают, а других нет.

https://github.com/Anorov/cloudflare-scrape
04.06.2018 17:31
upd.
Похоже, действительно проблема именно в Tor:
нашел рабочий прокси - через него Api работает
08.10.2018 18:27
Этот скрипт не очень актуален так ка сейчас на йобите 7797 пар. Получения их занимает примерно 1 минуту. Хорошим вариантом было бы отсортировать те пары на которых есть волатильность и добавить их в файл. А запрос отправлять с этого файла. Обновления файла делать раз в день.
P.S. Просто мысли в слух.
19.01.2019 19:05
Даааа, с количеством пар они конечно хватанули через край.
Пришлось сделать небольшую выборку, допустим по BTC. Прогнал разок, сделал более конкретный запрос API и радуюсь.
Вот только проблемка нарисовалась:
Traceback (most recent call last):
  File "C:\!\!bots\!my\1_1.py", line 28, in <module>
    ticker_res_obj = json.loads(ticker_res.text) # переводим полученный текст в объект с данными
  File "C:\Program Files\Python37\lib\json\__init__.py", line 348, in loads
    return _default_decoder.decode(s)
  File "C:\Program Files\Python37\lib\json\decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:\Program Files\Python37\lib\json\decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Выдает то одно количество пар, то другое. Вроде и погуглил но в чем проблема не понимаю.

Сам скрипт:
    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:
            if '_btc' in pair:
                if (float(ticker_res_obj[pair]['vol']) > 0.5):
                    print(''.join((pair,'-')))
                    cnt += 1
</module>
21.01.2019 06:47
Думаю, вас время от времени подбанивает Yobit, добавьте time.sleep(1) в конце цикла, что бы делал паузы между запросами.
И еще: сейчас ваш скрипт берет все пары, получает по ним информацию, и выводит только нужное ( if '_btc' in pair:)
Но это неоптимально, т.к. он тратит время на запросы к бирже по парам, которые не нужны
Можно вот эту строку
pairs = [pair for pair in res_obj['pairs']] 
заменить на
pairs = [pair for pair in res_obj['pairs'] if pair.endswith('btc')]
А эту убрать
if '_btc' in pair:
Тогда скрипт изначально будет брать только пары с btc, и проверять и отображать только их, что ускорит его работу.
24.01.2019 11:42
Добрый день. Использую api v3. Делаю запрос на depth и заметил, что ответы сервера обновляются каждые 11 секунд. Похоже, будто ответы кешируются, и все это время я получаю не актуальную информацию. С api v2 такой проблемы нет, но мне нужно именно v3. 
Запрашивая https://yobit.net/api/3/info в поле server_time можно даже увидеть как часто обновляется информация и это соответсвует моим наблюдениям.
Не знаете, можно ли с этим что-то сделать? Никакой бот не сможет работать в таких условиях
Пожалуйста, Авторизуйтесь что бы оставить свой комментарий