Пишем торгового робота для биржи Exmo

Теперь, когда мы разобрались, что такое биржа биткоинов, отложенные ордера и API, пришло время написать своего собственного бота.

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

Итак, что это за бот и как он будет работать

Бот будет выполнять рутинную работу за вас – он будет мониторить состояние биржи, отслеживать текущий курс, создавать ордера на покупку по выгодному курсу, и, после их выполнения, продавать купленную валюту.

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

Если сделка на покупку не реализуется в течении какого-то времени (у меня это три минуты) бот отменяет ордер и создает новый, с новым курсом.

Если сделка на покупку прошла, то бот создает ордер на продажу, и держит этот ордер до тех пор, пока он не будет целиком исполнен.

Бот берет среднюю цену по рынку за некоторый период (из-за ограничений exmo, за последние 100 сделок, на других биржах я действовал по другому), и создает ордера на покупку с указанной наценкой – т.е. ниже текущей цены рынка, после чего создает ордера на покупку – опять же с указанной наценкой – получается выше цены рынка. В сумму продаж/покупок закладывается комиссия биржи и, таким образом, нивелируется. Совершая сделки, бот отдает бирже требуемый ею кусок, но прибыль для владельца бота остается неизменной.

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

Бота можно останавливать и запускать в любой момент и с разных компьютеров – он при запуске проверит состояние ордеров, баланса и так далее – нет нужды бояться того, что при перезапуске потеряются ордера, деньги или что-то еще.

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

Сколько зарабатывает:

В рамках подготовки этой статьи (и отладки алгоритма), я играл на сумму 1 доллар 49 центов – и вот какие он сделки совершал (читать снизу вверх):

Сколько приносит бот на бирже

Если проанализировать доход/расход, то бот принес 3.5 цента за день – при том, что я играл на полтора доллара – это 2.4% со вклада в день.

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

Недостатки бота:

Так как бот учебный, некоторые вещи упрощены и убраны из кода – нет стоп-лоссов и тейк-профитов, курс берется по последним 100 сделкам, которые возвращает эта биржа, и есть вероятность, что бот купит на пике, и потом долго не сможет продать (тут придется либо ждать, либо продать по курсу рынка, выбор за человеком).

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

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



Алгоритм работы:

Для наглядности составлена блок-схема алгоритма работы – полностью транслировать её в текст я смысла не вижу, поясню основные принципы.

Бот играет на сумму которую вы указали – в данном случае для примера выбрана сумма 10 долларов США. На эту сумму бот старается купить биткойнов по курсу, чуть ниже текущего курса рынка. Если в течении некоторого времени (три минуты в примере) купить не получается, этот ордер на покупку отменяется, и создается новый, чуть ниже текущей цены уже на этот момент времени.

Если же ордер на покупку исполняется, то бот создает отложенный ордер на продажу этой валюты – он старается продать купленную валюту, и получить за это условные 10 долларов + желаемую наценку.

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

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

Вот блок-схема работы:

алгоритм работы торгового робота



Как начать пользоваться:

1. Регистрируйтесь на бирже (если еще этого не сделали):

2. Перейдите в Account-settings-API, нажмите “Generate and save”, и получите ключ и подпись: 

получить API ключи для робота

3. Установите интерпретатор Python 3.4 и выше (описано в этой статье)

4. Создайте файл с названием exmo.py и скопируйте туда код, указанный ниже

5. В коде, в строках 11 и 13, укажите ключи API, полученные в шаге 2

6. В строке  24 укажите сумму, на которую будет играть бот - CAN_SPEND = 1.45 – сейчас указано 1.45 доллара.

7. Сохраните и запускайте (F5) – бот начнет работать.

Вы можете его запустить, даже если на бирже сейчас нет денег – бот вас предупредит, и просто ничего не купит. Но, конечно, для успешной работы нужно, что бы деньги были :) На 11.04.2017 минимальная сумма на балансе должна составлять примерно 1.5 доллара – это примерно равно минимальной сумме сделки на бирже, 0.001 Btc.



Сам код бота:

import urllib, http.client
import time
import json
# эти модули нужны для генерации подписи API
import hmac, hashlib

# ключи API, которые предоставила exmo
API_KEY = 'YOUR API KEY'
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b'YOUR API SECRET'

# Тонкая настройка
CURRENCY_1 = 'BTC' 
CURRENCY_2 = 'USD'

CURRENCY_1_MIN_QUANTITY = 0.001 # минимальная сумма ставки - берется из https://api.exmo.com/v1/pair_settings/

ORDER_LIFE_TIME = 3 # через сколько минут отменять неисполненный ордер на покупку CURRENCY_1
STOCK_FEE = 0.002 # Комиссия, которую берет биржа (0.002 = 0.2%)
AVG_PRICE_PERIOD = 90 # За какой период брать среднюю цену
CAN_SPEND = 5 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1
PROFIT_MARKUP = 0.001 # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
DEBUG = True # True - выводить отладочную информацию, False - писать как можно меньше

STOCK_TIME_OFFSET = 0 # Если расходится время биржи с текущим 

# базовые настройки
API_URL = 'api.exmo.com'
API_VERSION = 'v1'

# Свой класс исключений
class ScriptError(Exception):
    pass
class ScriptQuitCondition(Exception):
    pass

CURRENT_PAIR = CURRENCY_1 + '_' + CURRENCY_2

# все обращения к API проходят через эту функцию
def call_api(api_method, http_method="POST", **kwargs):
    
    payload = {'nonce': int(round(time.time()*1000))}

    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(API_URL, timeout=60)
    conn.request(http_method, "/"+API_VERSION + "/" + api_method, payload, headers)
    response = conn.getresponse().read()
    
    conn.close()

    try:
        obj = json.loads(response.decode('utf-8'))

        if 'error' in obj and obj['error']:
            raise ScriptError(obj['error'])
        return obj
    except json.decoder.JSONDecodeError:
        raise ScriptError('Ошибка анализа возвращаемых данных, получена строка', response)

# Реализация алгоритма
def main_flow():
    
    try:
        # Получаем список активных ордеров
        try:
            opened_orders = call_api('user_open_orders')[CURRENCY_1 + '_' + CURRENCY_2]
        except KeyError:
            if DEBUG:
                print('Открытых ордеров нет')
            opened_orders = []
            
        sell_orders = []
        # Есть ли неисполненные ордера на продажу CURRENCY_1?
        for order in opened_orders:
            if order['type'] == 'sell':
                # Есть неисполненные ордера на продажу CURRENCY_1, выход
                raise ScriptQuitCondition('Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)')
            else:
                # Запоминаем ордера на покупку CURRENCY_1
                sell_orders.append(order)
                
        # Проверяем, есть ли открытые ордера на покупку CURRENCY_1
        if sell_orders: # открытые ордера есть
            for order in sell_orders:
                # Проверяем, есть ли частично исполненные
                if DEBUG:
                    print('Проверяем, что происходит с отложенным ордером', order['order_id'])
                try:
                    order_history = call_api('order_trades', order_id=order['order_id'])
                    # по ордеру уже есть частичное выполнение, выход
                    raise ScriptQuitCondition('Выход, продолжаем надеяться докупить валюту по тому курсу, по которому уже купили часть')
                except ScriptError as e:
                    if DEBUG:
                        print('Частично исполненных ордеров нет')
                
                    time_passed = time.time() + STOCK_TIME_OFFSET*60*60 - int(order['created'])

                    if time_passed > ORDER_LIFE_TIME * 60:
                        # Ордер уже давно висит, никому не нужен, отменяем
                        call_api('order_cancel', order_id=order['order_id'])
                        raise ScriptQuitCondition('Отменяем ордер -за ' + str(ORDER_LIFE_TIME) + ' минут не удалось купить '+ str(CURRENCY_1))
                    else:
                        raise ScriptQuitCondition('Выход, продолжаем надеяться купить валюту по указанному ранее курсу')
                

        else: # Открытых ордеров нет
            balances = call_api('user_info')['balances']
            if float(balances[CURRENCY_1]) >= CURRENCY_1_MIN_QUANTITY: # Есть ли в наличии CURRENCY_1, которую можно продать?
                """
                    Высчитываем курс для продажи.
                    Нам надо продать всю валюту, которую купили, на сумму, за которую купили + немного навара и минус комиссия биржи
                    При этом важный момент, что валюты у нас меньше, чем купили - бирже ушла комиссия
                    0.00134345 1.5045
                """
                wanna_get = CAN_SPEND + CAN_SPEND * (STOCK_FEE+PROFIT_MARKUP)  # сколько хотим получить за наше кол-во
                print('sell', balances[CURRENCY_1], wanna_get, (wanna_get/float(balances[CURRENCY_1])))
                new_order = call_api(
                    'order_create',
                    pair=CURRENT_PAIR,
                    quantity = balances[CURRENCY_1],
                    price=wanna_get/float(balances[CURRENCY_1]),
                    type='sell'
                )
                print(new_order)
                if DEBUG:
                    print('Создан ордер на продажу', CURRENCY_1, new_order['order_id'])
            else:
                # CURRENCY_1 нет, надо докупить
                # Достаточно ли денег на балансе в валюте CURRENCY_2 (Баланс >= CAN_SPEND)
                if float(balances[CURRENCY_2]) >= CAN_SPEND:
                    # Узнать среднюю цену за AVG_PRICE_PERIOD, по которой продают CURRENCY_1
                    """
                     Exmo не предоставляет такого метода в API, но предоставляет другие, к которым можно попробовать привязаться.
                     У них есть метод required_total, который позволяет подсчитать курс, но,
                         во-первых, похоже он берет текущую рыночную цену (а мне нужна в динамике), а
                         во-вторых алгоритм расчета скрыт и может измениться в любой момент.
                     Сейчас я вижу два пути - либо смотреть текущие открытые ордера, либо последние совершенные сделки.
                     Оба варианта мне не слишком нравятся, но завершенные сделки покажут реальные цены по которым продавали/покупали,
                     а открытые ордера покажут цены, по которым только собираются продать/купить - т.е. завышенные и заниженные.
                     Так что берем информацию из завершенных сделок.
                    """
                    deals = call_api('trades', pair=CURRENT_PAIR)
                    prices = []
                    for deal in deals[CURRENT_PAIR]:
                        time_passed = time.time() + STOCK_TIME_OFFSET*60*60 - int(deal['date'])
                        if time_passed < AVG_PRICE_PERIOD*60:
                            prices.append(float(deal['price']))
                    try:        
                        avg_price = sum(prices)/len(prices)
                        """
                            Посчитать, сколько валюты CURRENCY_1 можно купить.
                            На сумму CAN_SPEND за минусом STOCK_FEE, и с учетом PROFIT_MARKUP
                            ( = ниже средней цены рынка, с учетом комиссии и желаемого профита)
                        """
                        # купить больше, потому что биржа потом заберет кусок
                        my_need_price = avg_price + avg_price * (STOCK_FEE+PROFIT_MARKUP) 
                        my_amount = CAN_SPEND/my_need_price
                        
                        print('buy', my_amount, my_need_price)
                        
                        # Допускается ли покупка такого кол-ва валюты (т.е. не нарушается минимальная сумма сделки)
                        if my_amount >= CURRENCY_1_MIN_QUANTITY:
                            new_order = call_api(
                                'order_create',
                                pair=CURRENT_PAIR,
                                quantity = my_amount,
                                price=my_need_price,
                                type='buy'
                            )
                            print(new_order)
                            if DEBUG:
                                print('Создан ордер на покупку', new_order['order_id'])
                            
                        else: # мы можем купить слишком мало на нашу сумму
                            ScriptQuitCondition('Выход, не хватает денег на создание ордера')
                    except ZeroDivisionError:
                        print('Не удается вычислить среднюю цену', prices)
                else:
                    raise ScriptQuitCondition('Выход, не хватает денег')
        
    except ScriptError as e:
        print(e)
    except ScriptQuitCondition as e:
        if DEBUG:
            print(e)
        pass
    except Exception as e:
        print("!!!!",e)

while(True):
    main_flow()
    time.sleep(1)

Примечания по коду:

Строки 16 и 17  обозначают валютную пару. В данном примере это BTC_USD, но вы можете поменять на любую другую.

Строка 19  - CURRENCY_1_MIN_QUANTITY = 0.001. Это минимальная ставка, которая допускается на бирже. Для разных валют она разная, и, вообще, стоило бы получать её автоматически через API запрос. Но это усложнит код, поэтому я указал её как константу. Тем не менее, если вы планируете торговать другой валютой, вам следует поменять это значение, иначе торговля может затрудниться.

Строка 21 - ORDER_LIFE_TIME = 3. Если ордер на покупку не сыграл, то через сколько минут отменить его и создать новый, с новой ценой, более приближенной к текущим реалиям.

Строка 22 - STOCK_FEE = 0.002. Комиссия биржи за совершенную сделку. Непохоже, что бы она когда-то менялась, но, тем не менее, вы, при необходимости, сможете поменять её здесь если понадобится.

Строка 23 - AVG_PRICE_PERIOD = 90. Бот, в идеале, смотрит сделки за последние 90 минут, что бы узнать среднюю цену, в данной реализации он получает список совершенных сделок, и берет те из них, кто моложе 90 минут. Другой вопрос, что биржа не возвращает больше 100 записей, так что в данном случае число 90 сильно завышено.

Строка 24 - CAN_SPEND = 1.45. Важный параметр – сумма денег, которую вы доверяете боту для игры. В данном случае – 1 доллар 45 центов. Это удобно в том случае, когда бот играет на одну валютную пару, а вы – на другую, ну и еще гарантирует, что бот не проиграет всё, что нажито. В общем, чем больше эта сумма, тем больше денег он может заработать.

Строка 25  - PROFIT_MARKUP = 0.001. Это сумма наценки, которую вы хотите получить. В данном случае – это 0.1% от ставки. Чем больше это число, тем больше вы заработаете, но и курс будет раздуваться больше – т.е. вам придется дольше ждать исполнения сделки. Допускается дальнейшее дробление – например, число 0.00111 подходит. Если указать ноль, то бот будет работать вхолостую, обогащая биржу. Вы при этом, терять и зарабатывать не будете.

В строке 26 указано DEBUG = True. С этим параметром будет очень «разговорчивым», он будет комментировать каждое свое действие. Когда вам это надоест, советую вместо True написать False – тогда бот будет писать только по делу.

Так же не помешало бы в код добавить обработку некоторых исключительных ситуаций, перевести на ООП и так далее – но я не вижу смысла усложнять учебный код. Тот, кто заинтересуется, сможет сделать всё это и сам. Ну, или не делать, а просто пользоваться ботом как он есть :)



Заключение

Надеюсь, этот бот будет для вас полезен – и буду признателен обратной связи. Расскажите, каких результатов вы добились при использовании, с какими трудностями столкнулись и какие моменты показались вам непонятными.

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



Последнее изменение:


Крипто-кошельки для помощи и благодарности проекту:

Bitcoin адрес проекта: [[address]]

Перевод на сумму [[value]] BTC получен. Спасибо!.
[[error]]

Ethereum адрес проекта: [[address]]



Комментарии
12.05.2017 14:21:31
Андрей добрый день. Уточните пож-та такой момент, В базовых настройках у вас прописано # базовые настройки
API_URL = 'api.exmo.com'
 , но я пробовал заходить на биржу по адресу exmo.com и он заблокирован по России Ростелекомом. Можно зайти по адресу exmo.me Так мне все равно нужно прописать api.exmo.com' или все же нужно прописывать api.exmo.me?
ПроголосоватьПроголосовать
0 0
14.05.2017 11:38:04
Дмитрий, добрый день!

Смотрите, какая ситуация:
Технически, разницы нет - и тот и другой адрес являются зеркалами, и можно обращаться как к одному, так и к другому без изменения кода.
НО
Для зоны .com владельцы биржи оформили и держат валидным сертификат https, а для зоны .me сертификат является невалидным- это можно увидеть, если зайти на https://api.exmo.me/v1/ticker/ из браузера.
Надеюсь, это скоро будет исправлено, но пока что, что бы заставить скрипт работать в зоне .me, вам нужно не только изменить 

api.exmo.com на 
api.exmo.me, 

но еще и изменить 

conn = http.client.HTTPSConnection(API_URL) на 
conn = http.client.HTTPConnection(API_URL)  
(убрать букву S)

После этого всё заработает. Но надо иметь в виду, что бот будет забирать информацию по не защищенному каналу, и ваш трафик можно будет перехватить и модифицировать. Так что, когда на зоне .me заработает валидный сертификат или когда Ростелеком разлочит зону .com надо будет вернуть всё обратно. 
P.S. как ни странно, у меня exmo.com тоже был заблокирован Ростелекомом, но примерно с месяц назад стал снова доступен.
ПроголосоватьПроголосовать
0 0
14.05.2017 14:22:45
Спасибо Андрей, попробую. По результатам обязательно отпишусь.))
ПроголосоватьПроголосовать
0 0
15.05.2017 16:16:23
Здравствуйте. Сделал все как написано. Бот работает, но после создания ордера на покупку или продажу выпадает ошибка :
Traceback (most recent call last):
  File "C:\Python34\exmo.py", line 65, in call_api
    raise ScriptError(obj['error'])
ScriptError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Python34\exmo.py", line 199, in <module>
    main_flow()
  File "C:\Python34\exmo.py", line 132, in main_flow
    type='sell'
  File "C:\Python34\exmo.py", line 67, in call_api
    except json.decoder.JSONDecodeError:
AttributeError: 'module' object has no attribute 'JSONDecodeError'

И программу приходится перезапускать. Как можно это исправить?
                                                </module>
ПроголосоватьПроголосовать
0 0
15.05.2017 17:21:00
Здравствуйте.

Вы можете либо обновить версию Python до 3.5+, либо заменить 
except json.decoder.JSONDecodeError:
на 
except ValueError:
должно заработать.

Похоже, немного изменилось API, так что я еще изменил код, строку
if 'error' in obj:
заменил на
if 'error' in obj and obj['error']:
ПроголосоватьПроголосовать
0 0
15.05.2017 18:17:49
Спасибо, буду пробовать
ПроголосоватьПроголосовать
0 0
18.05.2017 23:09:53
У меня не торгует(пишет нет открытых ордеров(
ПроголосоватьПроголосовать
0 0
19.05.2017 12:26:46
Странно, проверил только что, все работает. Он может не торговать только если нет денег на балансе по этой валютной паре.

Может быть, у вас выводятся не все сообщения? 
Попробуйте заменить

except ScriptQuitCondition as e:
____if DEBUG:
________print(e)
____pass

на

except ScriptQuitCondition as e:
____print(e)
ПроголосоватьПроголосовать
0 0
21.05.2017 20:10:02
торгует но совсем слабо даже на 20 дол.одна сделка длится сутки!а обязательно торговать только этой парой?можно ли его запустить на полониксе или битрексе?
ПроголосоватьПроголосовать
0 0
26.05.2017 17:45:32
Это эксмо, там бывают такие периоды ) Для полоникса и прочих надо изменять код, я планирую это сделать и выложить, но попозже. А так можно торговать на любые пары - поменяйте
CURRENCY_1 = 'BTC' 
CURRENCY_2 = 'USD'
на
CURRENCY_1 = 'BTC' 
CURRENCY_2 = 'RUB'
например, или 
CURRENCY_1 = 'DOGE' 
CURRENCY_2 = 'BTC'

Так же можно сделать несколько версий скрипта - по одному на каждую пару, и запускать их параллельно.
Запускаете командую строку (cmd) в ней пишете python + путь к одному скрипту + Enter. Запускаете вторую командную строку, в ней python + путь к другому скрипту + Enter и т.п., будет одновременно играть по разным парам
ПроголосоватьПроголосовать
0 0
29.05.2017 18:39:47
Пишут, что за использование ботов на Exmo - бан.
Очень не хочется потерять $$
ПроголосоватьПроголосовать
0 0
30.05.2017 09:07:55
Здравствуйте, кто это говорит? В правилах такого нет, да и ни разу не банили.. В любом случае, отправил запрос в техподдержку Exmo, что бы получить официальную позицию по вопросу, как будет ответ, сообщу
ПроголосоватьПроголосовать
0 0
30.05.2017 09:18:54
А, вот уже и ответили. 

Вопрос:

Добрый день!
Иногда в интернете попадается информация о том, что на бирже Exmo предусмотрен бан за использование торговых роботов. Так ли это? Я не нашел прямого запрета в вашей базе знаний. Могу ли я использовать собственноручно написанного робота для торговли через ваш API?

Ответ: 

Добрый день! Да, можете, у нас нет запрета на использование ботов.
Best regards, Exmo.com Support Team.
ПроголосоватьПроголосовать
0 0
30.05.2017 14:54:45
Спасибо. Я такую инфу на форуме вычитал. Здесь https://forum.bits.media/index.php?/topic/35681-exmo-bot-bot-dlia-birzhi-exmo/
В примечании ТС к боту указано 
"Важное примечание: Для торговли ботом нужен отдельный аккаунт. 
Важно не регистрироваться под собой же! - "МОЖЕТ БЫТЬ БАН!" "
ПроголосоватьПроголосовать
0 0
30.05.2017 18:01:04
Возможно, это как-то связано с реферальной ссылкой, указанной сразу под этими словами ;)
ПроголосоватьПроголосовать
0 0
31.05.2017 01:36:55
= RESTART: C:/Users/маинер/AppData/Local/Programs/Python/Python36-32/5555.py =
Traceback (most recent call last):
  File "C:/Users/маинер/AppData/Local/Programs/Python/Python36-32/5555.py", line 199, in <module>
    main_flow()
  File "C:/Users/маинер/AppData/Local/Programs/Python/Python36-32/5555.py", line 76, in main_flow
    opened_orders = call_api('user_open_orders')[CURRENCY_1 + '_' + CURRENCY_2]
  File "C:/Users/маинер/AppData/Local/Programs/Python/Python36-32/5555.py", line 48, in call_api
    H = hmac.new(key=API_SECRET, digestmod=hashlib.sha512)
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36-32\lib\hmac.py", line 144, in new
    return HMAC(key, msg, digestmod)
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36-32\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>
ПроголосоватьПроголосовать
0 0
31.05.2017 10:09:32
# ключи API, которые предоставила exmo
API_KEY = 'YOUR API KEY'
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b'YOUR API SECRET'

Скорее всего, пропущена буква b перед строкой с API_SECRET , проверьте
ПроголосоватьПроголосовать
1 0
31.05.2017 15:52:52
Вы правы так и оказалось буквы b не хватало ,запустился  и сразуже продал все бикоины одним ордером  по рыночнои цене наибалансе было эквивалент 25долларам  в настроиках кода не чего не менял тока вставил апи что не так может быть
ПроголосоватьПроголосовать
0 0
01.06.2017 16:24:21
Да, действительно, такое возможно.. (
Бот рассчитан на увеличение кол-ва валюты 2 - т.е. долларов в дефолтной настройке.
Он задуман так, что на вторую валюту (доллары) покупает первую валюту (биткоины) ,потом эти биткоины все продает, что бы увеличить доллары. Вторая валюта растет , а первая то обнуляется, то вырастает. 
В данном случае вышло, что бот увидел, что у вас есть биткоины, подумал, что вы их купили и что их все нужно продать за 1.45$ + 0.1%(как написано в дефолтной настройке), ну и выставил лот. А эксмо продала по максимально выгодной цене для вас, по рыночной - т.е. вы за 25 долларов выручили не 1.45$, а сумму, близкую к 25$.
В общем, если вы больше ничего не делали и запустите бота еще раз, то все будет работать нормально. Первая валюта в паре изначально будет пустой, и будет покупаться на вторую валюту пары. 
Ну точнее, в настройках стоит 1.45$, и он будет пытаться создать ордера именно на эту сумму, сколько бы долларов у вас не было - а это мало на сегодня из-за курса биткоина, я обновил статью, поставил 5 долларов, что бы преодолевать минимальный рубеж ставки, вам тоже стоит поменять это значение.
ПроголосоватьПроголосовать
0 0
02.06.2017 21:27:22
Traceback (most recent call last):
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\43535uytyu.py", line 199, in <module>
    main_flow()
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\43535uytyu.py", line 76, in main_flow
    opened_orders = call_api('user_open_orders')[CURRENCY_1 + '_' + CURRENCY_2]
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\43535uytyu.py", line 56, in call_api
    conn.request(http_method, "/"+API_VERSION + "/" + api_method, payload, headers)
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1239, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1285, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1234, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1026, in _send_output
    self.send(msg)
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 964, in send
    self.connect()
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1392, in connect
    super().connect()
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 936, in connect
    (self.host,self.port), self.timeout, self.source_address)
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\lib\socket.py", line 722, in create_connection
    raise err
  File "C:\Users\маинер\AppData\Local\Programs\Python\Python36\lib\socket.py", line 713, in create_connection
    sock.connect(sa)
TimeoutError: [WinError 10060] Попытка установить соединение была безуспешной, т.к. от другого компьютера за требуемое время не получен нужный отклик, или было разорвано уже установленное соединение из-за неверного отклика уже подключенного компьютера
>>>  ошибка теперь вылазиет  и вот еще вопрос как можно сделать торговлю мелкими ордерами  к примеру по доллару 
                                                </module>
ПроголосоватьПроголосовать
0 0
03.06.2017 14:23:17
Судя по ошибке, он не смог попасть на сайт биржи - неполадки с интернетом у вас или у них, соединение закрыто антивирусом или опять же блокировка Ростелекомом м.б. А через браузер сайт Эксмо открывается?
ПроголосоватьПроголосовать
0 0
12.06.2017 17:05:30
Я ниже оставил комментарий про таймаут, попробуйте выставить настройку
ПроголосоватьПроголосовать
0 0
02.06.2017 21:36:20
и как сделать работу с несколькими ордерами
ПроголосоватьПроголосовать
0 0
03.06.2017 14:32:46
Я тут подумал, лучше наверное это не делать, это надо тонко просчитывать настройки в каждом файле. Разве что для совершенно разных валют можно безбоязненно это делать - например, если одна пара BTC_USD, то вторая ETH_RUB.
Для этого надо создать несколько копий файла, в каждом в настройках поменять валюту.
Потом запускаете командую строку (cmd) в ней пишете python + путь к одному скрипту + Enter. Запускаете вторую командную строку, в ней python + путь к другому скрипту + Enter и т.п., будет одновременно играть по разным парам.
ПроголосоватьПроголосовать
0 0
08.06.2017 22:57:02
Доброго времени суток! Поставил Вашего бота на пару ETH_USD. Он продал имеющийся эфир, закупился на указанную мной сумму (3USD), выставил ордер на продажу и примерно через пол часа выдаёт ошибку... Завтра скопирую код ошибки
ПроголосоватьПроголосовать
0 0
09.06.2017 18:03:45
Создает ордер, работает минут 10, цену не меняет. После этого вылетает:
Traceback (most recent call last):
  File "D:\exmobot\exmo.py", line 199, in <module>
    main_flow()
  File "D:\exmobot\exmo.py", line 76, in main_flow
    opened_orders = call_api('user_open_orders')[CURRENCY_1 + '_' + CURRENCY_2]
  File "D:\exmobot\exmo.py", line 56, in call_api
    conn.request(http_method, "/"+API_VERSION + "/" + api_method, payload, headers)
  File "C:\Python34\lib\http\client.py", line 1137, in request
    self._send_request(method, url, body, headers)
  File "C:\Python34\lib\http\client.py", line 1182, in _send_request
    self.endheaders(body)
  File "C:\Python34\lib\http\client.py", line 1133, in endheaders
    self._send_output(message_body)
  File "C:\Python34\lib\http\client.py", line 963, in _send_output
    self.send(msg)
  File "C:\Python34\lib\http\client.py", line 898, in send
    self.connect()
  File "C:\Python34\lib\http\client.py", line 1287, in connect
    server_hostname=server_hostname)
  File "C:\Python34\lib\ssl.py", line 362, in wrap_socket
    _context=self)
  File "C:\Python34\lib\ssl.py", line 580, in __init__
    self.do_handshake()
  File "C:\Python34\lib\ssl.py", line 807, in do_handshake
    self._sslobj.do_handshake()
ConnectionResetError: [WinError 10054] Удаленный хост принудительно разорвал существующее подключение

                                                </module>
ПроголосоватьПроголосовать
0 0
10.06.2017 07:39:39
Вроде работает.
Первый ордер всегда совершает в "-".
Пара ETH_BTC.
На балансе был только BTC.
После запуска сразу покупает ETH по завышеной: "по рынку" + 0,2%
ПроголосоватьПроголосовать
0 0
12.06.2017 16:58:33
Он покупает по завышенной + 0.2%, что бы остаться в плюсе после того, как биржа возьмет свою комиссию за совершенную сделку, и то же самое при покупке.
ПроголосоватьПроголосовать
0 0
09.06.2017 21:44:18
Когда ордер на продажу не срабатывает в течении 20-30 минут, то выдаёт такую ошибку:
Traceback (most recent call last):
  File "C:\Users\Мика\AppData\Local\Programs\Python\Python36-32\exmo.py", line 199, in <module>
    main_flow()
  File "C:\Users\Мика\AppData\Local\Programs\Python\Python36-32\exmo.py", line 76, in main_flow
    opened_orders = call_api('user_open_orders')[CURRENCY_1 + '_' + CURRENCY_2]
  File "C:\Users\Мика\AppData\Local\Programs\Python\Python36-32\exmo.py", line 56, in call_api
    conn.request(http_method, "/"+API_VERSION + "/" + api_method, payload, headers)
  File "C:\Users\Мика\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1239, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "C:\Users\Мика\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1285, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "C:\Users\Мика\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1234, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "C:\Users\Мика\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1026, in _send_output
    self.send(msg)
  File "C:\Users\Мика\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 964, in send
    self.connect()
  File "C:\Users\Мика\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 936, in connect
    (self.host,self.port), self.timeout, self.source_address)
  File "C:\Users\Мика\AppData\Local\Programs\Python\Python36-32\lib\socket.py", line 722, in create_connection
    raise err
  File "C:\Users\Мика\AppData\Local\Programs\Python\Python36-32\lib\socket.py", line 713, in create_connection
    sock.connect(sa)
TimeoutError: [WinError 10060] Попытка установить соединение была безуспешной, т.к. от другого компьютера за требуемое время не получен нужный отклик, или было разорвано уже установленное соединение из-за неверного отклика уже подключенного компьютера
>>> 
Подскажите, в чём проблема? И можно ли её решить?
                                                </module>
ПроголосоватьПроголосовать
0 0
12.06.2017 17:04:28
Похоже на нестабильный интернет, попробуйте увеличить таймаут операции

Строку 
    conn = http.client.HTTPSConnection(API_URL)
Замените на 
    conn = http.client.HTTPSConnection(API_URL, timeout=60)

60 - это кол-во секунд для ожидания, можете поэксперементировать с этим значением, может вам нужно ставить больше
ПроголосоватьПроголосовать
0 0
10.06.2017 20:41:40
Всё сделал по инструкции, скопировал код, запустил, а вышло вот это:

Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 17:54:52) [MSC v.1900 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> 
=============== RESTART: C:/Users/Вова/Desktop/exmo-ethrub.py ===============
Traceback (most recent call last):
  File "C:/Users/Вова/Desktop/exmo-ethrub.py", line 199, in <module>
    main_flow()
  File "C:/Users/Вова/Desktop/exmo-ethrub.py", line 76, in main_flow
    opened_orders = call_api('user_open_orders')[CURRENCY_1 + '_' + CURRENCY_2]
  File "C:/Users/Вова/Desktop/exmo-ethrub.py", line 56, in call_api
    conn.request(http_method, "/"+API_VERSION + "/" + api_method, payload, headers)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1239, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1285, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1234, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1026, in _send_output
    self.send(msg)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 964, in send
    self.connect()
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1400, in connect
    server_hostname=server_hostname)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 401, in wrap_socket
    _context=self, _session=session)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 808, in __init__
    self.do_handshake()
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 1061, in do_handshake
    self._sslobj.do_handshake()
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 683, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
>>> 

В чем ошибка, подскажите пожалуйста?
                                                </module>
ПроголосоватьПроголосовать
0 0
10.06.2017 22:03:24
С этим разобрался, поменяв на exmo.me
ПроголосоватьПроголосовать
0 0
10.06.2017 22:07:28
Другая фигня вылезла:

Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 17:54:52) [MSC v.1900 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> 
=============== RESTART: C:/Users/Вова/Desktop/exmo-ethrub.py ===============
Traceback (most recent call last):
  File "C:/Users/Вова/Desktop/exmo-ethrub.py", line 199, in <module>
    main_flow()
  File "C:/Users/Вова/Desktop/exmo-ethrub.py", line 76, in main_flow
    opened_orders = call_api('user_open_orders')[CURRENCY_1 + '_' + CURRENCY_2]
  File "C:/Users/Вова/Desktop/exmo-ethrub.py", line 56, in call_api
    conn.request(http_method, "/"+API_VERSION + "/" + api_method, payload, headers)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1239, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1285, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1234, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1026, in _send_output
    self.send(msg)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 964, in send
    self.connect()
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\http\client.py", line 1400, in connect
    server_hostname=server_hostname)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 401, in wrap_socket
    _context=self, _session=session)
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 808, in __init__
    self.do_handshake()
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 1061, in do_handshake
    self._sslobj.do_handshake()
  File "C:\Users\Вова\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 683, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
>>> 

Как можно сделать чтобы код не так часто обращался к серверу и в случае такой ошибки возвращался к началу исполнения, а не застопаривался на этом тексте ошибки?
                                                </module>
ПроголосоватьПроголосовать
0 0
11.06.2017 06:35:10
Частично справился поменяв sleep в конце на 10. Вылетела ошибка только один раз когда ещё дополнительно зашёл на exmo через браузер. 
Нужно дописать чтобы происходил рестарт после ошибки с задержкой выполнения секунд в 30.
ПроголосоватьПроголосовать
0 0
12.06.2017 17:32:25
Код бота на сайте обновлен, теперь бот отлавливает любые ошибки и перезапускается, вылетать не должен
ПроголосоватьПроголосовать
0 0
16.06.2017 05:51:40
Добрый день.
Огромное спасибо за программу. Потихоньку в ней пытаюсь разобраться, но столкнулся с непонятным.
Пытаюсь её настроить на пару USD/RUB но почему-то не хочет работать постоянно пишет
"
Открытых ордеров нет
buy 0.0854926829194002 58.484537264011735
Открытых ордеров нет
buy 0.0854926829194002 58.484537264011735
и т.д.
"
Цифры меняются относительно курса

В скрипте прописано :
CURRENCY_1_MIN_QUANTITY = 0.1 # минимальная сумма ставки - берется из https://api.exmo.com/v1/pair_settings/
ORDER_LIFE_TIME = 3 # через сколько минут отменять неисполненный ордер на покупку CURRENCY_1
STOCK_FEE = 0.002 # Комиссия, которую берет биржа (0.002 = 0.2%)
AVG_PRICE_PERIOD = 30 # За какой период брать среднюю цену
CAN_SPEND = 5 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1
PROFIT_MARKUP = 0.001 # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
DEBUG = True # True - выводить отладочную информацию, False - писать как можно меньше
на счету сумма достаточная. 
Помогите пожалуйста разобраться.

PS. С парой BTC/USD работает нормально. Со всеми остальными парами выше описанная проблема.
ПроголосоватьПроголосовать
0 0
16.06.2017 11:03:24
Добрый день.
Попробуйте CAN_SPEND поставить 10 (рублей) или чуть больше, что бы приблизиться к минимальному разрешенному объему по этой паре.
ПроголосоватьПроголосовать
0 0
19.06.2017 11:46:40
Андрей , добрый день. 
Запускаю скрипт и он стоит на месте. 
В дебаге много красного на подобие 
f0\fs28\fsmilli14400 \cf2 \cb3 # \uc0\u1082 \u1083 \u1102 \u1095 \u1080  API, \u1082 \u1086 \u1090 \u1086 \u1088 \u1099 \u1077  \u1087 \u1088 \u1077 \u1076 \u1086 \u1089 \u1090 \u1072 \u1074 \u1080 \u1083 \u1072  exmo\cb1 \uc0\u8232

Подскажите, что не так?
ПроголосоватьПроголосовать
0 0
19.06.2017 12:04:02
Все оказалось проще, чем я думал) при копировании отсюда в блокнот, перенеслась инфа о красном фоне и цвете букв :) 
Лучше конечно сразу в проект питона копировать. 
Вроде все работает!
ПроголосоватьПроголосовать
0 0
19.06.2017 12:37:44
О, отлично! )
ПроголосоватьПроголосовать
0 0
20.06.2017 15:17:08
Андрей, добрый день.
Стало интересно попробовать бота на poloniex.
Вопрос: изменения кода касаются только ссылки на ключи API или есть другие тонкие "нюансы"?
ПроголосоватьПроголосовать
0 0
21.06.2017 12:45:55
Добрый день.
Тут два момента - первый это изменение ключей (причем часть запросов на полоникс уходит через POST на один URL, а часть через GET на другой, но всё это легко решаемо).
Второй момент - это формат возвращения данных - JSON, возвращаемый биржами, различается, местами кардинально, так что по коду придется вписывать изменения.
ПроголосоватьПроголосовать
0 0
21.06.2017 13:05:56
А, еще есть нюанс с комиссией -https://poloniex.com/fees/
Для тех, кто ставит цену, отличную от рыночной, комиссия 0.15%, для тех, кто берет по рынку - 0.25%
НО если даже вы выставляете цену не по рынку, в какие-то моменты рыночная цена приближается к вашей, и со сделки вы отдаете 0.25%.
Поэтому, при исполнении ордера нужно проверять, какая комиссия была взята - это есть в api - returnTradeHistory
ПроголосоватьПроголосовать
0 0
21.06.2017 13:14:52
Спасибо, буду иметь ввиду.
ПроголосоватьПроголосовать
0 0
21.06.2017 07:21:37
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
с чем связано???
ПроголосоватьПроголосовать
0 0
21.06.2017 07:26:52
исправил exmo.com на exmo.me    и Строку 
conn = http.client.HTTPSConnection(API_URL)
Замените на 
conn = http.client.HTTPSConnection(API_URL, timeout=60)       -- заработало... теперь пишет    Открытых ордеров нет, Выход, не хватает денег.. причем деньги вроде есть....
ПроголосоватьПроголосовать
0 0
21.06.2017 07:33:36
хранилось в эфире.. поменялв коде BTC на ETH, все заработало) спасибо)
ПроголосоватьПроголосовать
0 0
21.06.2017 12:46:23
Пожалуйста ))
ПроголосоватьПроголосовать
0 0
21.06.2017 10:49:00
40009: The nonce parameter is less or equal than what was used before "1498041476990"
в чем ошибка?
ПроголосоватьПроголосовать
0 0
21.06.2017 12:50:56
Для передачи данных по протоколу используется параметр nonce.
Это число должно увеличиваться с каждым присланным запросом, что бы серверу не пришлось выполнять команды, которые пришли позже из-за сетевых задержек, так же этот параметр нужен криптографическому алгоритму, что бы подтвердить, что это новый запрос, а не кто-то перехватил пакет и отправил заново от вашего имени.
Сейчас nonce == текущему микровремени в формате UNIX, т.е. увеличивается с каждой микросекундой: int(round(time.time()*1000)).
Очевидно, что вы запустили код где-то, где время было больше, чем ваше текущее (может быть, изменился часовой пояс/дата на вашем компьютере), теперь биржа думает, что вы шлете пакеты данных из прошлого.
ПроголосоватьПроголосовать
0 0
21.06.2017 13:44:07
Спасибо за развернутый ответ! Понял свою ошибку
ПроголосоватьПроголосовать
0 0
25.06.2017 08:45:27
Здравствуйте, а для Bittrex его нельзя подправить?
ПроголосоватьПроголосовать
0 0
27.06.2017 14:42:34
Здравствуйте, полагаю, что можно - Bittrex предоставляет API - https://bittrex.com/home/api, но, конечно, в код надо будет внести некоторые изменения, что бы учесть разницу в возвращаемых данных.
Сам я этого пока не делал
ПроголосоватьПроголосовать
0 0
27.06.2017 16:03:50
А не планируете? 
Мож подправите, если время будет, я просто в этом ничего не понимаю 
ПроголосоватьПроголосовать
0 0
02.07.2017 15:00:26
Ну вообще не планировал) Но биржа популярная, так что, думаю, доберемся до неё рано или поздно
ПроголосоватьПроголосовать
0 0
25.06.2017 11:07:21
Здравствуйте, работает, но в самом начале выдаёт такую ошибку: 
{'result': True, 'error': '', 'order_id': 194229329}
что значит и как поправить?
ПроголосоватьПроголосовать
0 0
27.06.2017 14:40:04
Добрый день.
Судя по сообщению, это не ошибка а ответ биржи о том, что ордер успешно создан.
Выводится этой строкой
print(new_order)
Можете её удалить )
Я её добавил для отладки, так то она не нужна для работы.. Попозже я обновлю код на сайте, уберу строку
ПроголосоватьПроголосовать
0 0
29.06.2017 14:47:56
Не могу понять какую роль играет переменная STOCK_TIME_OFFSET = 0. Поясните пожалуйста.
ПроголосоватьПроголосовать
0 0
29.06.2017 18:03:16
Ну, например Московское время 18:00, а время биржи 15:00. Вы хотите получить информацию за последние 15 минут. Указываете с 17:45 до 18:00 а на бирже такое еще не наступило, и вам говорят нет записей. 
Если поставите 
STOCK_TIME_OFFSET =-3
то выровняете эту разницу.
Но это в общем-то нужно тем, у кого странные или пустые результаты возвращаются
ПроголосоватьПроголосовать
0 0
30.06.2017 09:00:33
Добрый день, Андрей!

Пытаюсь запустить бот, но возникает сообщение "Invalid syntax",
Первые строки модуля:
ython 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>>

import urllib, http.client
import time
import json
ПроголосоватьПроголосовать
0 0
30.06.2017 14:15:52
Посмотрите саму ошибку - там обычно пишется в какой строке что не так. Или присылайте, посмотрим
ПроголосоватьПроголосовать
0 0
30.06.2017 09:49:59
Я правильно понимаю, что после продажи CURRENCY_1 бот не ждет выгодного курса и сразу закупает ее обратно? Или ждет?
У меня что-то все операции идут с повышением курса ибо он сразу покупает валюту обратно, тем самым используя текущий курс. В итоге через пяток операций ордер на продажу выставился выше, чем пиковое значение курса.
ПроголосоватьПроголосовать
0 0
30.06.2017 11:19:41
Аналогичная проблема, через некоторое время бот задирает цену и ордер висит не исполняемый.
ПроголосоватьПроголосовать
0 0
30.06.2017 14:22:47
Нет, не ждет, это очень простой бот.
После того, как он купил валюту, он сразу же выставляет ордер на продажу, что бы избавиться от валюты и получить указанную наценку. Для продажи он рассчитывает кол-во купленной валюты и курс покупки, что бы потом продать за вычетом комиссии биржи и получить свою прибыль. 
Так что да, он может купить на пике и ждать (это указано в разделе недостатки:)). Если в итоге ему удастся продать, то следующий лот на покупку он выставит по средней цене, что может быть как выше, так и ниже текущей.
ПроголосоватьПроголосовать
0 0
02.07.2017 00:57:29
Спасибо за вашу работу. Бот заработал с первого раза, но получилось так же как и вы предупреждали. Последняя продажа зависла, так как тренд развернулся. 

Возможно ли вставить код, чтобы робот выполнял вот такой алгоритм? 

Бот купил криптовалюту и ждет пока она поднимется на 1%. Если поднялась, тогда для страховки от разворота программа ставит отложенный ордер на продажу при проседании на 0.5%. Если монета все же начала падать, тогда он ее продает и мы выходим в ноль. А если крипта пошла  вверх то поднимаем ордер на продажу еще на  0.5% на продажу. Это тоже самое  что и Stop-Limit на полонексе, только в автоматическом режиме.
ПроголосоватьПроголосовать
0 0
02.07.2017 14:56:36
Добрый день.
Общую мысль понял, только бот не должен заранее создавать ордер на продажу (т.к. это будет выгодная цена для для остальных участников, и не выгодная для вас, и ордер будет сразу исполняться биржей), а при достижении курсом роста в 1% должен мониторить ситуацию, и, в зависимости от дальнейшего направления тренда уже ждать, реагировать и создавать ордер на продажу по событию с той или иной наценкой. Впрочем, вы, наверное, это и имели в виду.

Думаю, это будет несложно добавить - надо ордер выставлять с наценкой в 1.5%, добавить ордеру признак ватерлинии в 1%, запоминать, переходила ли цена её или нет, если да, но потом пошла вниз то отменять и создавать дешевле, если да и цена пошла выше то ждать исполнения, но я сейчас не готов сказать, когда смогу за это взяться. Кроме того, это может с какой-то стороны и ухудшить торговлю, т.к. за то время, пока курс поднимется на 1% (а это иногда очень долго), можно провести несколько раундов торговли с меньшей наценкой на колебаниях, да и вообще курс может не вырасти. Тут надо подумать.

В любом случае, я специально выложил исходный код, что бы любой мог доработать его в соответствии со своими пожеланиями - сам или с помощью программистов, так что добавить возможно всё, что угодно)
ПроголосоватьПроголосовать
0 0
02.07.2017 17:08:17
Спасибо за ответ.

Да вы правильно поняли.

Процент написал приблизительный, главное в этом деле не стать инвестором при падающей цене. Лучше меньше прибыль, но зато с $.

Плохо, что я не программист :(   Буду заходить по чаше на эту страницу, может кто-то еще что-то сделает.

Спасибо за открытый код и тему.
ПроголосоватьПроголосовать
0 0
06.07.2017 00:36:19
Андрей, спасибо за код!
К сожалению, ни пример, который вложен на exmo ни ваш, не может выполнить метод request - либо ошибка приема сертификата (SSL: CERTIFICATE_VERIFY_FAILED) , либо (если поменять API_URL на api.exmo.me )  пишет, что api.exmo.me это не api.exmo.com, и он прав ))
Подскажите, куда копать, как отключить проверку сертификата в методе request? Может быть, версия питона не подходит, либо его нужно с каким-то надстройками? У меня вер. 3.6
ПроголосоватьПроголосовать
0 0
07.07.2017 15:21:36
Добрый день.

Если exmo.com меняется на exmo.me, то нужно еще и протокол соединения изменить с https на http:

conn = http.client.HTTPSConnection(API_URL) на 
conn = http.client.HTTPConnection(API_URL)  

т.к. на exmo.me висит (почему-то) тот же сертификат SSL,  что и на exmo.com, что, в результате делает его невалидным для домена, и приходится ходить вообще, увы, без сертификата. Более подробно расписано в комментариях выше.
ПроголосоватьПроголосовать
0 0
10.07.2017 10:35:13
как такой бот сделать для liqui.io?
ПроголосоватьПроголосовать
0 0
10.07.2017 13:24:39
Здравствуйте. При запуске бота (F5) выдается следующее сообщение:[WinError 10054] Удаленный хост принудительно разорвал существующее подключение. Выше в комментариях ответа не нашёл. Спасибо.
ПроголосоватьПроголосовать
0 0
10.07.2017 17:02:56
Добрый день.
Если вкратце, то соединение между вами и сервером неожиданно становится нерабочим.
Причина может быть разной, иногда у эксмо такое бывают какие-то неполадки, может быть антивирус обрывает вам коннект, может быть нестабильный интернет, может быть запущено слишком много скриптов одновременно и сервер биржи "рвет" лишние коннекты, может быть на вашем роутере каким-то образом ограничивается трафик, еще можно попробовать exmo.com заменить на exmo.me и https на http, теоретически это разные сервера в одной подсети, один может работать лучше другого..
ПроголосоватьПроголосовать
0 0
11.07.2017 08:20:54
Ещё раз здравствуйте. Проблема решилась заменой .com на .me и удалением S  из строки conn = http.client.HTTPSConnection(API_URL, timeout=60). Благодарю за помощь.
ПроголосоватьПроголосовать
0 0
11.07.2017 20:31:43
А у меня такой вопрос как его переделать наоборот (торговал на понижении) увеличивал не фиатные а
крипту
ПроголосоватьПроголосовать
0 0
15.07.2017 16:43:55
Присоединяюсь к предыдущему сообщению, как заставить бота играть на понижение?
ПроголосоватьПроголосовать
0 0
19.07.2017 17:32:04
Это надо код менять тут и там и тестировать, я вам отвечу, но не скоро, пока что нет возможности проверить работу кода.
Пока что можно поручить это какому-нибудь фрилансеру )

Так, если без проверки, то нужно 
CAN_SPEND поменять на значение в крипте, 

if order['type'] == 'sell':
заменить на 
if order['type'] == 'buy':

type='sell'
заменить на 
type='buy'

type='buy'
заменить на 
type='sell'

if float(balances[CURRENCY_2]) >= CAN_SPEND:
заменить на
if float(balances[CURRENCY_1]) >= CAN_SPEND:

Ну и вообще посмотреть, что из этого получится..
ПроголосоватьПроголосовать
0 0
16.07.2017 10:02:25
при запуске вижу это:
Traceback (most recent call last):
  File "start.py", line 3, in <module>
    import urllib, http.client
ImportError: No module named http.client

---
http.client должен входить в "ядро" python, но ничего не работает :(
                                                </module>
ПроголосоватьПроголосовать
0 0
16.07.2017 11:12:15
http.client - победил, однако:
!!!! [Errno 104] Connection reset by peer
!!!! [Errno 104] Connection reset by peer
!!!! [Errno 104] Connection reset by peer
!!!! [Errno 104] Connection reset by peer
ПроголосоватьПроголосовать
0 0
19.07.2017 17:14:06
Ростелеком?
Предлагаю для начала поменять exmo.com на exmo.me,  и протокол соединения изменить с https на http:

conn = http.client.HTTPSConnection(API_URL) на 
conn = http.client.HTTPConnection(API_URL)
ПроголосоватьПроголосовать
0 0
20.07.2017 08:35:09
Бот работает. Вроде исправно. торги ведет согласно алгоритму.
Однако, иногда в отладке прослеживаются строки: !!!! [Errno 11004] getaddrinfo failed
Подскажите, что это за ошибка и как ее править?
ПроголосоватьПроголосовать
0 0
20.07.2017 12:58:50
Ошибка говорит о том, что не удается получить IP адрес домена, к которому обращаетесь (exmo.com или exmo.me).
Первый совет - как и всем - попробуйте поменять  exmo.com на exmo.me,  и протокол соединения с https на http:
conn = http.client.HTTPSConnection(API_URL) на 
conn = http.client.HTTPConnection(API_URL)
Подробности выше в комментариях.
Если проблема останется - проверьте, не отваливается ли Wi-Fi в это время, или, может-быть, какие-то сетевые проблемы на стороне сетевой карты, роутера и дальше.. Сам код работает с тем, что предоставляет операционная система, а она сообщает ему, что не удается найти домен, причин может быть много..
ПроголосоватьПроголосовать
1 0
21.07.2017 10:04:57
Большое спасибо!
ПроголосоватьПроголосовать
0 0
20.07.2017 21:31:01
Добрый вечер, бот играет на повышение из-за комиссии биржи и прибыли.Возможно ли сделать какое-нибудь условие чтобы бот покупал валюту по выгодной цене (чтобы ждал хоть какого-нибудь падения курса)?
ПроголосоватьПроголосовать
0 0
21.07.2017 20:31:41
Ну, простое решение может быть таким:
Сейчас бот берет все сделки и считает среднюю цену, по которой и выставляет buy.
avg_price = sum(prices)/len(prices)
В выложенном примере он берет сделки за 
AVG_PRICE_PERIOD = 90 # 90 минут
Полученная цена может оказаться как выше, так и ниже текущей.

Вы можете изменить этот показатель, скажем, до одной минуты и брать не среднее число а минимальное за этот период, для этого надо заменить 
avg_price = sum(prices)/len(prices)
на
avg_price = min(prices)

Ну а нужный период, одна минута там или 15 нужно будет подбирать
ПроголосоватьПроголосовать
0 0
22.07.2017 20:29:08
Спасибо!
ПроголосоватьПроголосовать
0 0
Пожалуйста, авторизуйтесь, что бы оставить свой комментарий