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

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

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

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

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


Реклама


Сам код бота:

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

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

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

CURRENT_PAIR = CURRENCY_1 + '_' + CURRENCY_2




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

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


# Запросить с биржи лимиты и использовать данные в работе
PAIR_LIMITS = {}
with urllib.request.urlopen("https://api.exmo.com/v1.1/pair_settings") as url:
    pairs_settings = json.loads(url.read().decode())
    if CURRENT_PAIR in pairs_settings:
        PAIR_LIMITS = pairs_settings[CURRENT_PAIR]
    else:
        print("Не удалось найти настройки пары", CURRENT_PAIR, "в ответе от биржи", pairs_settings)
        sys.exit(1)

CURRENCY_1_MIN_QUANTITY = float(PAIR_LIMITS["min_quantity"]) # минимальная сумма ставки - берется из https://api.exmo.com/v1/pair_settings/
PRICE_PRECISION = int(PAIR_LIMITS["price_precision"])

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

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




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

    # Если в ф-цию переданы параметры в формате ключ:значение
    if kwargs:
        # добавляем каждый параметр в словарь payload
        # Получится {'nonce':123172368123, 'param1':'val1', 'param2':'val2'}
        payload.update(kwargs)

    # Переводим словарь payload в строку, в формат для отправки через GET/POST и т.п.
    payload =  urllib.parse.urlencode(payload)

    # Из строки payload получаем "подпись", хешируем с помощью секретного ключа API
    # sing - получаемый ключ, который будет отправлен на биржу для проверки
    H = hmac.new(key=API_SECRET, digestmod=hashlib.sha512)
    H.update(payload.encode('utf-8'))
    sign = H.hexdigest()
    
    # Формируем заголовки request для отправки запроса на биржу. 
    # Передается публичный ключ API и подпись, полученная с помощью hmac
    headers = {"Content-type": "application/x-www-form-urlencoded",
           "Key":API_KEY,
           "Sign":sign}

    # Создаем подключение к бирже, если в течении 60 сек не удалось подключиться, обрыв соединения
    conn = http.client.HTTPSConnection(API_URL, timeout=60)
    # После установления связи, запрашиваем переданный адрес
    # В заголовке запроса уходят headers, в теле - payload
    conn.request(http_method, "/"+API_VERSION + "/" + api_method, payload, headers)
    # Получаем ответ с биржи и читаем его в переменную response
    response = conn.getresponse().read()
    # Закрываем подключение
    conn.close()

    try:
        # Полученный ответ переводим в строку UTF, и пытаемся преобразовать из текста в объект Python
        obj = json.loads(response.decode('utf-8'))

        # Смотрим, есть ли в полученном объекте ключ "error"
        if 'error' in obj and obj['error']:
            # Если есть, выдать ошибку, код дальше выполняться не будет
            raise ScriptError(obj['error'])
        # Вернуть полученный объект как результат работы ф-ции
        return obj
    except ValueError:
        # Если не удалось перевести полученный ответ (вернулся не JSON)
        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 'Error 50304' in str(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('Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло %s секунд' % str(time_passed))
                    else:
                        raise ScriptQuitCondition(str(e))

        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= "{price:0.{prec}f}".format(prec=PRICE_PRECISION, 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="{price:0.{prec}f}".format(prec=PRICE_PRECISION, price=my_need_price),
                                type='buy'
                            )
                            print(new_order)
                            if DEBUG:
                                print('Создан ордер на покупку', new_order['order_id'])
                            
                        else: # мы можем купить слишком мало на нашу сумму
                            raise ScriptQuitCondition('Выход, сумма для торгов (CAN_SPEND) меньше минимально разрешенной биржей')
                    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)


try:
    balances = call_api('user_info')['balances']
    alt_balance = float(balances[CURRENCY_1])

    poss_profit = (CAN_SPEND*(1+STOCK_FEE) + CAN_SPEND * PROFIT_MARKUP) / (1 - STOCK_FEE) 

    if float(balances[CURRENCY_1]) > 0:
        decision = input("""
            У вас на балансе есть {amount:0.8f} {curr1}
            Вы действительно хотите, что бы бот продал все это по курсу {rate:0.8f}, выручив {wanna_get:0.8f} {curr2}?
            Введите Д/Y или Н/N
        """.format(
            amount=alt_balance,
            curr1=CURRENCY_1,
            curr2=CURRENCY_2,
            wanna_get=poss_profit,
            rate=poss_profit/alt_balance
        ))
        if decision in ('N','n','Н','н'):
            print("Тогда избавьтесь от {curr} (как вариант создайте ордер с ними по другой паре) и перезапустите бота".format(curr=CURRENCY_1))
            sys.exit(0)
except Exception as e:
    print(str(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 – тогда бот будет писать только по делу.

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


Реклама


Заключение

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

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

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

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

Смотрите, какая ситуация:
Технически, разницы нет - и тот и другой адрес являются зеркалами, и можно обращаться как к одному, так и к другому без изменения кода.
НО
Для зоны .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 тоже был заблокирован Ростелекомом, но примерно с месяц назад стал снова доступен.
14.05.2017 14:22
Спасибо Андрей, попробую. По результатам обязательно отпишусь.))
15.05.2017 16:16
Здравствуйте. Сделал все как написано. Бот работает, но после создания ордера на покупку или продажу выпадает ошибка :
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>
15.05.2017 17:21
Здравствуйте.

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

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

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

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

на

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

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

Вопрос:

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

Ответ: 

Добрый день! Да, можете, у нас нет запрета на использование ботов.
Best regards, Exmo.com Support Team.
30.05.2017 14:54
Спасибо. Я такую инфу на форуме вычитал. Здесь https://forum.bits.media/index.php?/topic/35681-exmo-bot-bot-dlia-birzhi-exmo/
В примечании ТС к боту указано 
"Важное примечание: Для торговли ботом нужен отдельный аккаунт. 
Важно не регистрироваться под собой же! - "МОЖЕТ БЫТЬ БАН!" "
30.05.2017 18:01
Возможно, это как-то связано с реферальной ссылкой, указанной сразу под этими словами ;)
31.05.2017 01:36
= 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>
31.05.2017 10:09
# ключи API, которые предоставила exmo
API_KEY = 'YOUR API KEY'
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b'YOUR API SECRET'

Скорее всего, пропущена буква b перед строкой с API_SECRET , проверьте
31.05.2017 15:52
Вы правы так и оказалось буквы b не хватало ,запустился и сразуже продал все бикоины одним ордером по рыночнои цене наибалансе было эквивалент 25долларам в настроиках кода не чего не менял тока вставил апи что не так может быть
01.06.2017 16:24
Да, действительно, такое возможно.. (
Бот рассчитан на увеличение кол-ва валюты 2 - т.е. долларов в дефолтной настройке.
Он задуман так, что на вторую валюту (доллары) покупает первую валюту (биткоины) ,потом эти биткоины все продает, что бы увеличить доллары. Вторая валюта растет , а первая то обнуляется, то вырастает.
В данном случае вышло, что бот увидел, что у вас есть биткоины, подумал, что вы их купили и что их все нужно продать за 1.45$ + 0.1%(как написано в дефолтной настройке), ну и выставил лот. А эксмо продала по максимально выгодной цене для вас, по рыночной - т.е. вы за 25 долларов выручили не 1.45$, а сумму, близкую к 25$.
В общем, если вы больше ничего не делали и запустите бота еще раз, то все будет работать нормально. Первая валюта в паре изначально будет пустой, и будет покупаться на вторую валюту пары.
Ну точнее, в настройках стоит 1.45$, и он будет пытаться создать ордера именно на эту сумму, сколько бы долларов у вас не было - а это мало на сегодня из-за курса биткоина, я обновил статью, поставил 5 долларов, что бы преодолевать минимальный рубеж ставки, вам тоже стоит поменять это значение.
02.06.2017 21:27
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>
03.06.2017 14:23
Судя по ошибке, он не смог попасть на сайт биржи - неполадки с интернетом у вас или у них, соединение закрыто антивирусом или опять же блокировка Ростелекомом м.б. А через браузер сайт Эксмо открывается?
12.06.2017 17:05
Я ниже оставил комментарий про таймаут, попробуйте выставить настройку
02.06.2017 21:36
и как сделать работу с несколькими ордерами
03.06.2017 14:32
Я тут подумал, лучше наверное это не делать, это надо тонко просчитывать настройки в каждом файле. Разве что для совершенно разных валют можно безбоязненно это делать - например, если одна пара BTC_USD, то вторая ETH_RUB.
Для этого надо создать несколько копий файла, в каждом в настройках поменять валюту.
Потом запускаете командую строку (cmd) в ней пишете python + путь к одному скрипту + Enter. Запускаете вторую командную строку, в ней python + путь к другому скрипту + Enter и т.п., будет одновременно играть по разным парам.
08.06.2017 22:57
Доброго времени суток! Поставил Вашего бота на пару ETH_USD. Он продал имеющийся эфир, закупился на указанную мной сумму (3USD), выставил ордер на продажу и примерно через пол часа выдаёт ошибку... Завтра скопирую код ошибки
09.06.2017 18:03
Создает ордер, работает минут 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>
10.06.2017 07:39
Вроде работает.
Первый ордер всегда совершает в "-".
Пара ETH_BTC.
На балансе был только BTC.
После запуска сразу покупает ETH по завышеной: "по рынку" + 0,2%

12.06.2017 16:58
Он покупает по завышенной + 0.2%, что бы остаться в плюсе после того, как биржа возьмет свою комиссию за совершенную сделку, и то же самое при покупке.
09.06.2017 21:44
Когда ордер на продажу не срабатывает в течении 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>
12.06.2017 17:04
Похоже на нестабильный интернет, попробуйте увеличить таймаут операции

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

60 - это кол-во секунд для ожидания, можете поэксперементировать с этим значением, может вам нужно ставить больше

10.06.2017 20:41
Всё сделал по инструкции, скопировал код, запустил, а вышло вот это:

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>
10.06.2017 22:03
С этим разобрался, поменяв на exmo.me
10.06.2017 22:07
Другая фигня вылезла:

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>
11.06.2017 06:35
Частично справился поменяв sleep в конце на 10. Вылетела ошибка только один раз когда ещё дополнительно зашёл на exmo через браузер.
Нужно дописать чтобы происходил рестарт после ошибки с задержкой выполнения секунд в 30.
12.06.2017 17:32
Код бота на сайте обновлен, теперь бот отлавливает любые ошибки и перезапускается, вылетать не должен
16.06.2017 05:51
Добрый день.
Огромное спасибо за программу. Потихоньку в ней пытаюсь разобраться, но столкнулся с непонятным.
Пытаюсь её настроить на пару 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 работает нормально. Со всеми остальными парами выше описанная проблема.
16.06.2017 11:03
Добрый день.
Попробуйте CAN_SPEND поставить 10 (рублей) или чуть больше, что бы приблизиться к минимальному разрешенному объему по этой паре.
19.06.2017 11:46
Андрей , добрый день.
Запускаю скрипт и он стоит на месте.
В дебаге много красного на подобие
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

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

Пытаюсь запустить бот, но возникает сообщение "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
30.06.2017 14:15
Посмотрите саму ошибку - там обычно пишется в какой строке что не так. Или присылайте, посмотрим
30.06.2017 09:49
Я правильно понимаю, что после продажи CURRENCY_1 бот не ждет выгодного курса и сразу закупает ее обратно? Или ждет?
У меня что-то все операции идут с повышением курса ибо он сразу покупает валюту обратно, тем самым используя текущий курс. В итоге через пяток операций ордер на продажу выставился выше, чем пиковое значение курса.
30.06.2017 11:19
Аналогичная проблема, через некоторое время бот задирает цену и ордер висит не исполняемый.
30.06.2017 14:22
Нет, не ждет, это очень простой бот.
После того, как он купил валюту, он сразу же выставляет ордер на продажу, что бы избавиться от валюты и получить указанную наценку. Для продажи он рассчитывает кол-во купленной валюты и курс покупки, что бы потом продать за вычетом комиссии биржи и получить свою прибыль.
Так что да, он может купить на пике и ждать (это указано в разделе недостатки:)). Если в итоге ему удастся продать, то следующий лот на покупку он выставит по средней цене, что может быть как выше, так и ниже текущей.
02.07.2017 00:57
Спасибо за вашу работу. Бот заработал с первого раза, но получилось так же как и вы предупреждали. Последняя продажа зависла, так как тренд развернулся.

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

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

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

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

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

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

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

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

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

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

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

Так, если без проверки, то нужно 
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:

Ну и вообще посмотреть, что из этого получится..
01.12.2017 09:09
Так, если без проверки, то нужно 
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:

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

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

Ну и вообще посмотреть, что из этого получится..

на такое изменение программа пишет:
нет открытых ордеров
выход, не хватает денег
06.12.2017 08:29
бот заработал когда, на двух счетах USD и BTC были средства, но он очень странно торгует, вначале в 0, потом выставлял цену независимо от текущего курса
07.01.2018 11:08
принцип биржи не знаете что ли? по вашему коду покупаете по дороже а продаете дешевле!
16.07.2017 10:02
при запуске вижу это:
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>
16.07.2017 11:12
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
19.07.2017 17:14
Ростелеком?
Предлагаю для начала поменять exmo.com на exmo.me, и протокол соединения изменить с https на http:

conn = http.client.HTTPSConnection(API_URL) на
conn = http.client.HTTPConnection(API_URL)
20.07.2017 08:35
Бот работает. Вроде исправно. торги ведет согласно алгоритму.
Однако, иногда в отладке прослеживаются строки: !!!! [Errno 11004] getaddrinfo failed
Подскажите, что это за ошибка и как ее править?
20.07.2017 12:58
Ошибка говорит о том, что не удается получить 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 в это время, или, может-быть, какие-то сетевые проблемы на стороне сетевой карты, роутера и дальше.. Сам код работает с тем, что предоставляет операционная система, а она сообщает ему, что не удается найти домен, причин может быть много..
21.07.2017 10:04
Большое спасибо!
20.07.2017 21:31
Добрый вечер, бот играет на повышение из-за комиссии биржи и прибыли.Возможно ли сделать какое-нибудь условие чтобы бот покупал валюту по выгодной цене (чтобы ждал хоть какого-нибудь падения курса)?
21.07.2017 20:31
Ну, простое решение может быть таким:
Сейчас бот берет все сделки и считает среднюю цену, по которой и выставляет buy.
avg_price = sum(prices)/len(prices)
В выложенном примере он берет сделки за 
AVG_PRICE_PERIOD = 90 # 90 минут
Полученная цена может оказаться как выше, так и ниже текущей.

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

Ну а нужный период, одна минута там или 15 нужно будет подбирать
22.07.2017 20:29
Спасибо!
26.07.2017 14:09
Приветствую. С парой BTC_USD все прекрасно работает. С парой ETH_USD застрял. Название в скрипте поменял. На продажу бот кидает в 2 раза дороже. на сегодня это около 205-410. Лишние нолики поубирал - все равно такая ж дичь...
26.07.2017 14:18
А купленное и проданное кол-во совпадает? Бот пытается закупить на CAN_SPEND = 5 - 5 долларов, и купленное продать за 5$ + навар. Чем меньше он купит валюты, тем выше задерется курс, но таких разрывов еще не было.. Может быть вы поставили прибыль в 100%?
И не совсем понял про лишние нолики
26.07.2017 14:31
# Тонкая настройка
CURRENCY_1 = 'ETH' 
CURRENCY_2 = 'USD'

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

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


Такие вот настройки.   Даже те же эфиры которые он купил, пытается продать в два раза дороже.

435.76229209  0.01181837  5.14999999
26.07.2017 14:53
Так ордер на покупку был?
Бот работает так, что если на балансе были эфиры, он их пытается продать..
Если на балансе были эфиры, то он их выставил с целью продать за 5$, а т.к. их было мало, то вот такой курс.
Остановите бота, продайте все эфиры до нуля по нужному курсу, запустите и должно работать..
26.07.2017 15:03
Все, спасибо, заработало. Ордер на покупку был, потом разрыв, перезапуск
26.07.2017 17:40
Здравствуйте. Я не знаю может я один такой у кого не получилось запустить бот? Скачал питон, запускаю и ни чего. Посоветуйте что делать. Что и где читать для того что бы получилось. Второй день кручу верчу бестолку.
26.07.2017 18:14
Все спасибо заработал.
26.07.2017 23:38
На сумму CAN_SPEND за минусом STOCK_FEE, и с учетом PROFIT_MARKUP
( = ниже средней цены рынка, с учетом комиссии и желаемого профита)
"""
# купить больше, потому что биржа потом заберет кусок
my_need_price = avg_price + avg_price * (STOCK_FEE+PROFIT_MARKUP)
Разве при вычислении my_need_price должен стоять '+'? Так получается что он покупает выше средней, а не ниже.
27.07.2017 12:19
Да, вы правы, что бы покупать ниже средней, нужен минус, поправил в статье. Впрочем, прибыль по сделке от этого не изменится, а вот на количество и качество сделок повлияет. Спасибо.
26.07.2017 23:40
И не плохо бы предупредить, что при запуске на балансе не должно быть currency_1.
27.07.2017 12:27
Точно, добавил предупреждение
27.07.2017 21:25
А почему Вы не захотели сделать чтобы размер лота на продажу так же расчитывался, а не тупо сливалось все что есть? Мне кажется это усложнило бы код несильно, а ограничение это снялось.
30.07.2017 16:44
Я думал об этом, и так я сделал позже, в боте для полоникса. А когда писал эту статью (первой) не хотел усложнять код базой данных, хотел сделать все в одном маленьком файле, где всё просто и понятно, и можно менять что угодно в любую сторону. Т.е. изначально посыл был не в том, что вот он бот, а в том что смотрите как просто и легко на Питоне такие всякие штуки делать, и они работают.
27.07.2017 17:37
Я так понял что через 3 минуты(ORDER_LIFE_TIME) если ордер на покупку не сработал должно пересчитываться заново. Почему то не пересчитывается, если только принудительно закрыть ордер, то он создает заново пересчитанный. В чем может быть проблема?
27.07.2017 20:23
Разница часовых поясов, скорее всего.
Бот берет текущее время с компьютера, и сравнивает со временем создания ордера по времени биржи. И это кстати, также касается периода, за который он берет среднюю цену.
Вам нужно посмотреть, насколько расходится время, и внести коррективу в STOCK_TIME_OFFSET. Например, если расходится на час в каком-то направлении, то
STOCK_TIME_OFFSET = 1 # у вас на час раньше
или
STOCK_TIME_OFFSET = -1
01.08.2017 23:07
У меня стоит STOCK_TIME_OFFSET = -3 и неисполненные ордера на покупку отменяются через три часа. Как поправить? Ведь если я поставлю STOCK_TIME_OFFSET = 0 то он неправильно будет определять закупочную цену?
27.07.2017 21:50
Ну, например Московское время 18:00, а время биржи 15:00. Вы хотите получить информацию за последние 15 минут. Указываете с 17:45 до 18:00 а на бирже такое еще не наступило, и вам говорят нет записей.
Если поставите
STOCK_TIME_OFFSET =-3
то выровняете эту разницу.
Но это в общем-то нужно тем, у кого странные или пустые результаты возвращаются (делал по вашему ответу в предыдущих комментариях). У меня время Калининградское и я поставил STOCK_TIME_OFFSET =-2. Или надо было ставить +2?
27.07.2017 22:28
-2... Всё равно не работает?
Я в код добавил вывод кол-ва прошедших секунд со времени создания ордера
raise ScriptQuitCondition('Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло %s секунд' % str(time_passed))
, можете запустить с ним, проверить что там происходит?
28.07.2017 00:52
создания ордера прошло -10473.463473558426 секунд
40009: The nonce parameter is less or equal than what was used before "1501188391596"
Проверяем, что происходит с отложенным ордером 223738623
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло -10470.726317167282 секунд=======> как все было так и осталось (ну только что секунды пишет, это значит что снимет ордер через 3 часа?)))
28.07.2017 12:30
Именно так) Значит нужно не -2, а +1
28.07.2017 13:16
А почему? Почему +1, а не -2. Я все поставил. ОН убирает ордер на покупку и ставит заново каждую секунду. Что делать? Может увеличить ORDER_LIFE_TIME = 3 на что нибудь другое?
28.07.2017 13:18
Интересно это у меня одного. Или другим и так нормально не разбираясь?
28.07.2017 13:33
STOCK_TIME_OFFSET = 0 при таком значении стало работать правильно. Только не будет ли это влиять на что нибудь другое? к примеру на расчет средней стоимости?
30.07.2017 15:41
Извиняюсь за задержку с ответом. Если отменяет правильно, через три минуты, то и среднюю стоимость считает правильно - там один и тот же принцип. Насчет того почему изначально не работало с 0, а потом заработало, там целая эпопея возможных причин.. Или вы изначально поставили -2? Просто когда питон берет время указанным в коде способом, он не учитывает часовой пояс, и получается время, близкое к UTC (зависит от версии питона), и эксмо работает по времени UTC, так что в большинстве случаев 0 должен давать правильные результаты, а +1, -2 и т.п. нужны редко когда, для подгонки
30.07.2017 23:58
Большое спасибо за ответ и за эту статью. Все очень интересно.
30.07.2017 08:34
Здравствуйте. Отличный бот, работает, как часы. Спасибо.
Что нужно сделать, что бы отображалось время операции? Не так:
buy 0.0854926829194002 58.484537264011735
А вот так, примерно:
12:32:07 buy 0.0854926829194002 58.484537264011735
Возможно ли это вообще?
30.07.2017 15:57
Конечно, время добавить несложно

print('buy', my_amount, my_need_price)
заменить на
print(time.strftime("%Y-%m-%d %H:%M:%S"), 'buy', my_amount, my_need_price)

print('sell', balances[CURRENCY_1], wanna_get, (wanna_get/float(balances[CURRENCY_1])))
заменить на
print(time.strftime("%Y-%m-%d %H:%M:%S"), 'sell', balances[CURRENCY_1], wanna_get, (wanna_get/float(balances[CURRENCY_1])))

и т.п. 
Я это попозже в статье поменяю
01.08.2017 20:46
Это текущее время на данной машине - а как время с биржи сюда поставить?!
У мен задрал цену и не может продать теперь.
Буду модифицировать код под более менее умную покупку.
01.08.2017 20:46
Это текущее время на данной машине - а как время с биржи сюда поставить?!
У мен задрал цену и не может продать теперь.
Буду модифицировать код под более менее умную покупку.
31.07.2017 00:09
Столкнулся вот с чем: на торговой паре с небольшим объемом торгов робот пытается купить CURRENCY_1 и у него это получается не полностью, после того как он купил CURRENCY_1 не полностью он ставит это все это дело на продажу за стоимость CAN_SPEND тем самым увеличивая стоимость продажи до ценника (20%-30%) по которому могут купить довольно таки не скоро. То есть он забывает что не все купил на CAN_SPEND и начинает продавать неполный CURRENCY_1 за большую сумму пытаясь вернуть ставку. С этим можно что-нибудь сделать?
01.09.2017 22:51
Ну, как быстрый вариант можно модифицировать код, указывая, сколько грубо говоря наноцентов вы хотите получать с каждой купленной сатоши) Соответственно, при продаже формировать цену)
02.08.2017 14:12
wanna_get = CAN_SPEND + CAN_SPEND * (STOCK_FEE+PROFIT_MARKUP) # сколько хотим получить за наше кол-во
При текущем:
PROFIT_MARKUP = 0,001
STOCK_FEE = 0,002
Мы будем в минусе.

По моему нужно написать вот так:
wanna_get = CAN_SPEND + CAN_SPEND * (STOCK_FEE*2+PROFIT_MARKUP) # сколько хотим получить за наше кол-во

Комиссию-то мы дважды платим, при покупке и при продаже. Можно конечно еще более точнее написать, у нас же после покупки еще меньше стало, комиссию же заплатили.
03.08.2017 07:32
Да это так, можно это учесть в PROFIT_MARKUP, я сейчас на данном боте сделал плавующий порог покупки продажи - где то 5 рублей в день дает при операции с 250 рублями на паре ETH/RUB
03.08.2017 07:37
Вообще STOCK_FEE стоит и в цене покупки и в цене продаже - так, что она компенсируется - другой вопрос, что маловато дает - а так как вы хотите сделать
wanna_get = CAN_SPEND + CAN_SPEND * (STOCK_FEE*2+PROFIT_MARKUP) # сколько хотим получить за наше кол-во
это тройная компенсация комиссии - 1 при покупке и 2 при продаже.
03.08.2017 07:46
Подскажите пожалуйста ситуация такая:
С майнинга приходит на биржу валюта ETH и бот ее быстро сливает на рубли, причем по не выгодному курсу.
Как сделать так, что бы бот продавал валюту только в определенном количестве - то, что разрешено по курсу в рублях CAN_SPEND
03.08.2017 16:43
except Exception as e:
        print("!!!!",e)
Что означает данный код в конце скрипта - он срабатывает у меня когда куплена валюта
и пишет 
List indices must be integers or slices, not str
05.08.2017 19:20
Здравствуйте, сделал, вроде все по инструкции)
вот:

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 = b'ключ ввел полностью' 
CURRENCY_2 = b'ключ ввел полностью'

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 = 1.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('Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло %s секунд' % str(time_passed))
                

        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)

нажимаю F5, и появляется вот это:

Traceback (most recent call last):
  File "C:\Users\Я\AppData\Local\Programs\Python\Python36-32\exmo.py", line 37, in <module>
    CURRENT_PAIR = CURRENCY_1 + '_' + CURRENCY_2
TypeError: can't concat str to bytes</module>
05.08.2017 19:54
У меня все работает, я в спайдере Питон 3.6 Запускаю.
20.08.2017 16:17
у вас -= Тонкая настройка
CURRENCY_1 = b'ключ ввел полностью'
CURRENCY_2 = b'ключ ввел полностью'

а надо

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

у вас бот не понимает на какой паре торговать
05.08.2017 20:50
а что за спайдер?)
09.08.2017 18:52
Подскажите плиз, что нужно прописать в коде бота, чтобы бот для каждой пары выставлял цену покупки чуть лучше лучшей цены на бирже (Bid=Bid+0.00000001). Тоже самое и с ценой продажи (Ask=Ask-0.00000001). Это нужно чтобы при покупке и продаже у бота всегда была наилучшая цена и тем самым увеличивалось кол-во сделок в единицу времени, даже если имеется разница в 1 сатошу или цент.
01.09.2017 23:05
Тут надо код переделывать.
Для примера, если вы хотите получить лучшую цену покупки, то фрагмент кода будет таким
# Получаем предложения из книги ордеров
offers = call_api('order_book', pair=CURRENT_PAIR)
# bid_top - максимальная цена покупки
bid_top = float(offers[CURRENT_PAIR]['bid_top'])
# ask_top - минимальная цена продажи
ask_top = float(offers[CURRENT_PAIR]['ask_top'])
Берете тот параметр, который нужен, и прибавляете/отнимаете сатошу.
Тут будет хитрость с комиссией - которая попозже добавится к цене, так что вам, после получения цены, нужно рассчитать так, что бы сумма с комиссией равнялась лучшей цене, после чего вы бы прибавляли сатошу
19.08.2018 17:43
Доброго времени суток. Подскажите куда именно нужно прописать эту комбинацию, чтоб на бирже лот был на 1-ну сатошу больше чем у конкурента ????
20.08.2018 07:12
Доброго.
Ну, например, замените строку
my_need_price = avg_price - avg_price * (STOCK_FEE+PROFIT_MARKUP)
на
my_need_price = float(offers[CURRENT_PAIR]['bid_top'])+0.00000001
20.08.2018 23:24
к сожалению не получается настроить, т.к мои познания в программи́рование равны абсолютному нулю.... при замене рекомендуемой вами строки на другую пишет что не может открыть ордер на покупку, цену пары прописал минимум для торговой пары (( никак не поддается...
24.08.2018 05:43
добрый день. можеет подсказать куда прописать продажу по лучшей цене +0000001 ???
12.08.2017 16:55
Не понял что он от меня хочет ? :(
python3.4 exmo.py 
  File "exmo.py", line 49
    H.update(payload.encode('utf-8'))
    ^
IndentationError: unexpected indent
01.09.2017 23:05
Лишний отступ в коде, пробелы и табуляции важны
13.08.2017 14:55
Добрый день!
Строка 21 - ORDER_LIFE_TIME = 3. Если ордер на покупку не сыграл, то через сколько минут отменить его и создать новый, с новой ценой, более приближенной к текущим реалиям

Можно добавить еще время и на продажу? Спасибо!
01.09.2017 23:07
Можно, но куда её снижать? Вы будете торговать в минус
18.08.2017 16:09
я не пойму как его запустить!
18.08.2017 16:10
может кто поможет?
20.08.2017 16:12
в инструкции выше написано как его запускать, у меня запустился с первого раза
22.08.2017 07:19
Автор, напишите пожалуйста, как на сайте exmo формируют процент роста или падения - цену среднюю удалось получить - как процент формируется?!
01.09.2017 23:09
Я так думаю, что как и на полониксе - берется разница в курсе за сутки, и считается процент.
23.08.2017 22:35
Добрый день. С самого начала начала выпадать такая  ошибка. 


Traceback (most recent call last):
  File "C:\Users\Admin\Desktop\exmo.py", line 1, in <module>
    import urllib, http.client
ImportError: No module named http.client
>>> </module>
01.09.2017 23:11
Я подозреваю, что вы установили Питон ветки 2.7.+
Вам нужно установить другую версию, 3.+
23.08.2017 22:52
Автор . У Вас ошибка. Ваш ордер отменяется через 3 часа. Исправил на 3 минуты. Вот код: 

 time_passed = time.time() + STOCK_TIME_OFFSET*60*1 - int(order['created'])

                    if time_passed > ORDER_LIFE_TIME * 1:
                        # Ордер уже давно висит, никому не нужен, отменяем
                        call_api('order_cancel', order_id=order['order_id'])
                        raise ScriptQuitCondition('Отменяем ордер -за ' + str(ORDER_LIFE_TIME) + ' минут не удалось купить '+ str(CURRENCY_1))
                    else:
                        raise ScriptQuitCondition('Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло %s секунд' % str(time_passed))
01.09.2017 22:42
Это зависит от часового пояса того, кто запускает. Т.е. зачастую достаточно оставить STOCK_TIME_OFFSET=0, что бы отменялся через 3 минуты. Но в некоторых случая приходится колдовать с часовым поясом, спасибо за ваше решение.
03.10.2017 23:51
Евгений, доброго времини суток , можно по подробнее в какой строке и что на что поменять?
27.08.2017 01:02
Бот отлично работает , спасибо.
Вопрос такой, по какой формуле формируется цена входа в торги?
01.09.2017 23:12
В боте или вообще?)
02.09.2017 12:36
в боте конечно) я так понял бот берет среднюю цену за последние 90 минут, и пытается купить за цену на какой то % ниже средней?
09.10.2017 11:27
Да, все правильно. Создает отложенный ордер и ждет, когда цена торгов приблизится к желаемой. Если за три минуты не приблизилась, то отменяет и создает новый, с новым значением.
28.08.2017 11:36
Добрый день!! Помогите советом. Вроде все сделал по инструкции. Запускаю бот - он пишет: 

Открытых ордеров нет
!!!! unorderable types: float() >= tuple()

и так много много раз. на счету в долларах есть деньги. что я сделал не так??
01.09.2017 23:16
Есть подозрение, что где-то стоит лишняя запятая, например после CURRENCY_1_MIN_QUANTITY или CAN_SPEND
т.е.
CAN_SPEND = 5
хорошо, а
CAN_SPEND = 5,
очень, очень плохо
28.08.2017 14:57
Помогите кто-нибудь!
29.08.2017 09:34
а ты скопируй сюда полностью свой код из питона, тогда будет видно, что сделал не так и подскажут
29.08.2017 09:39
разобрался, все заработало
Может кто подскажет, как добавить еще одну валютную пару?
предполагаю, что нужно в питоне нужно создать еще один файл?
29.08.2017 11:02
Да копируешь этот файл, но меняешь название второй валюты, например на 'ETH'. Ну и запускаешь оба файла одновременно. По крайней мере у меня все работает.
29.08.2017 11:19
ок, спасибо, работает)
29.08.2017 11:21
сколько можно валютных пар, если питон для 32 бит?
29.08.2017 23:51
можно тупо несколько idle запускать с каждым скриптом. Можно в командную строку прописывать названия скриптов. на x86 ограничение 2гб. не думаю что пара таких скриптов на питоне будет жрать больше 2х гб
29.08.2017 11:35
или как скачать питон 64 бит?
30.08.2017 00:19
Доброго времени суток, а не подскажите как этого бота запустить например на хостинге. Возможно ли вообще такое реализовать?
01.09.2017 23:27
Запросто, у меня и не такое крутится. Только хостинг нужен VPS/VDS, и на него нужно установить питон третьей ветки. Мм, надо бы это отдельно расписать, сделаю попозже.
В двух словах:
1. Получаете выделенный VPS/VDS. Мне нравится DigitalOcean
Отступление - если получаете по моей ссылке https://m.do.co/c/41ea66be21d8, то вам дают 10$ в долг, этого хватит на 2 месяца аренды - 5$/мес самый простой вариант, для бота его выше крыши
2. Если берете на ОС Убунту, то там скорее всего уже установлен Python 3, ничего делать не надо, только доустановить модуль requests (pip install requests). Иначе устанавливаете Python 3
3. Закидываете туда бота и запускаете.
Я потом отдельно распишу пошагово, что и как сделать
29.10.2017 20:21
Собственно, вот статья: https://bablofil.ru/kak-zapustit-bota-na-servere/
06.11.2017 18:55
"Запросто, у меня и не такое крутится." - вот об этом хотел бы Вас еще расспросить по подробней на mail :-)
30.08.2017 21:48
Спасибо за бота! Все настроил по инструкции. Экспериментирую с настройками.Все работает.
01.09.2017 23:28
Вам спасибо ) Удачи!
31.08.2017 09:57
Здравствуйте, работа бот какое-то время нормально, за часов 8 даже профит в 0.2% заметил. Но в один прекрасный момент он решил продавать валюту в 3 раза дороже её реальной цены. А именно на продаже ETH UAH, вместо цены на валюту в 9600, бот продает за 28713. Никаких настроек не менял.
01.09.2017 23:30
Такое может быть, если на балансе оказывается валюта, о которой бот не знает. Он пытается её продать за цену, которая указана в настройках. Чем меньше валюты, тем выше цена. Постарайтесь не играть на пары с общими альтами..
02.09.2017 00:11
Вкратце - запускайте бота не раз в секунду, а раз в две/три. Мне помогало
time.sleep(2)
Развернуто:
Тут вот в чем причина. У вас висит к примеру ордер на покупку монеты. Биржа разбила счет на две части. Вы купили только часть монет, которые собирались. Бот запускается раз в секунду, видит что ордеров нет (биржа не успела выставить вторую часть ордера), думает что купил все и выставляет ордер по такой цене, чтобы часть монеты которую Вы успели купить продать за такую сумму, за которую должен был продать все.
02.09.2017 00:04
Андрей, доброго времени суток!
Тестирую на паре LTC/BTC. Бот не может выставить ордер на покупку. В логах нечто такое "buy 0.0 0.xxxxxxxxxxxxxxxxxxxxxxxxxxxx" где x - цифра. Судя по всему он генерирует цену с большим количеством знаков после запятой, чем может обработать биржа.
CAN_SPEND = 0.006
PROFIT_MARKUP = 0.05

Я к сожалению не удержался и выставил ордер на покупку вручную. Сейчас висит ордер на продажу, точный лог выдать не могу.
Может посдкажете что нужно изменить в коде? Или выдать точную строчку лога?
08.09.2017 11:53
Вопрос снят.
16.09.2017 19:29
Добрый день! Бот выдает такую ошибку, много раз, что это может быть, и как проблему решить?

!!!! '>=' not supported between instances of 'float' and 'tuple'
16.09.2017 19:50
вопрос снят)
17.09.2017 21:09
Спасибо большое! Бот рабочий.
25.09.2017 01:27
Здравствуйте, спасибо за бота!)
Все сразу заработало, но выводит "Открытых ордеров нет" и курс.
На exmo лежит 15$. Если вручную меняю usd->btc, после запуска бота он сливает btc->usd и опять "Открытых ордеров нет".
Менял can_spend от 0.1 до 5, profit от 0.0009 до 0.00111.
25.09.2017 14:24
Теперь бесконечно ждет исполнения ордера на продажу (BTC - USD). Не подскажите за, сколько по времени обычно ордер исполняется?
25.09.2017 14:52
Что-то мне подсказывает, что CAN_SPEND - 5$ в пересчете на BTC по текущему курсу сильно ниже минимальной ставки на эксмо.. Попробуйте увеличить или играть скажем на DASH_USD, там должно хватать
29.09.2017 12:59
Добрый день,версия питона 3.4.0, бот не пересчитывает цену покупки ,каждые 3
минуты ,менял +3 на ,-3, обратно на 0, с пробелами и без и все равно не пересчитывает,скажите что можно сделать?
29.09.2017 13:38
Время сервера отстает на 3 часа ,может версию питона установить другую ,но какую?,подскажите пожалуйста.
02.10.2017 17:01
Добрый день.
Можно попробовать решение Евгения В. - выше в комментариях, возможно ваш случай. Или установить версию питона другой разрядности (32, 64)
29.09.2017 21:06
Добрый вечер. возможно к боту прикрутить индикатор,что бы он по индикатору открывал сделку?
02.10.2017 17:10
Добрый!
Технически - да, почему нет. Вот статья где я описывал как получить данные для индикатора (и построить график, если надо) - https://bablofil.ru/python-indicators/.
Соответственно, перед строкой
if float(balances[CURRENCY_2]) >= CAN_SPEND: 
нужно получить значения нужного индикатора, проанализировать,  и видоизменить её наподобие
if float(balances[CURRENCY_2]) >= CAN_SPEND and macd_hist> 0.001: 
- т.е. если деньги на балансе есть и  некий посчитанный индикатор позволяет торговать, то торгуй
29.10.2017 13:54
Выложил обновленный код с пояснениями в этой статье: https://bablofil.ru/macd-python-stock-bot/
04.10.2017 00:26
Подскажите пожалуйста как торговать на увиличение btc а не usd ?
05.10.2017 22:07
Это надо код переписывать, выше в комментариях посмотрите, было обсуждение
05.10.2017 21:04
Подскажите пожалуйста внес ключи апи при запуске выдает ошибку ImportError: No module named http.client с чем связано не пойму погуглил толком ничего не нашел .кто может сталкивался?
05.10.2017 22:06
Видимо, питон второй версии...
Ну или файл с ботом назвали http
05.10.2017 23:16
Андрей Всё сделал по инструкции выше. Бот пишит "нет открытых ордеров".
Подскажите что сделать необходим.. Хочу заставить бота трудиться.
06.10.2017 15:37
Питон последней версии 32 бит файл с именем ехмо.ру  назван, правда pip instal я не смог установить смд пишет команда не является исполнительным файл ом и тд
06.10.2017 23:13
Андрей ! Бот в разгар торговли ставит несуразно высокую цену и не меняет ее! при ручном закрытии ордера , бот ее повторяет.
несколько раз ставил цену в 2 раза выше рынка . а последний раз на 30 % .торговая пара ETH _ EUR

ORDER_LIFE_TIME = 5 #
STOCK_FEE = 0.002 #
AVG_PRICE_PERIOD =
CAN_SPEND = 250 #
PROFIT_MARKUP = 0.002 #
07.10.2017 16:25
Видимо, откуда-то берутся на балансе эфиры, всю пачку которых бот пытается продать за CAN_SPEND + (CAN_SPEND*PROFIT_MARKUP). Чем меньше на счету таких эфиров, тем выше задирается цена.
Такое может происходить, если параллельно торгуете на эфиры по другой паре, или отменяете частично исполненный ордер..
07.10.2017 10:09
запустил сейчас на 8 виндовсе запустилось сразу почему с 7-кой тупит непойму выдает туже ошибку ImportError: No module named http.client.
07.10.2017 16:27
Странно, может быть в 7ке две версии питона паралелльно установлены? Ошибка как правило говорит о том, что запускается python 2.7.+
08.10.2017 10:26
Здравствуйте кажется нашел в чем причина запускал на нетбуке асус стоит ультимате 7 неоригинал должна стартер стоять. загрузил на ноуте с 7 работает как часы пез правок подгонок просто на ура .небольшая проблема с командной строкой на разные валютные пары изначально был запущен на 8профешене следом был запущен на ноутбуке на другую валютную пару написал возможно ошибку я еще не переводил быстро мелькает не скопировать но пишет тоже самое постоянно и дальше не пускает решил из постов выше что через смд запускать надо указываю путь пишет как обычно не является исполнительным файлом вопрос запускать копии на валютные пары надо с одного компьютера через смд или с разных тоже должно работать ?.
08.10.2017 18:37
Можно с разных, бот должен работать. Что-то не так у вас настроено. Запустите командную строку, и в ней выполните
python -V
Что там пишется?
09.10.2017 21:01
Люди если кто переделал бот на увиличение крипты а не валюты выложиье кусочек кода заранее спасибо
09.10.2017 22:04
Пишет не является исполнительным файлом и тд.
09.10.2017 22:04
Пишет не является исполнительным файлом и тд.
10.10.2017 08:22
Сутки тестил всё работает но всё по нулям покупает продаёт без профита пробовал на разных валютных парах результат такой же Сейчас изменил процентную ставку профита посмотрим что будет.
17.10.2017 12:33
Оч странно.. Без профита он может играть либо если профит нулевой установлен либо если API сбоит..
13.10.2017 11:19
поставил одновременно на 4ре не пересекающихся валютные пары торговать..
увеличил желаемый на 0,05 профит , трудятся)
но конечно поведение бота продать , когда курс в верх летит- не человеческая логика)
как бы их научить различать восходящий и на понижение тренды
в любом случае боты выгодны для биржи.... те в профите.
17.10.2017 13:05
Насчет логики :) Изначальная идея была как раз закупать/продавать как можно больше и чаще, пока курс вверх растет, наживаться на маленьких суммах, и скидывать купленное на отскоках, если таковые будут. В общем, брать не суммой сделок, а количеством мелких профитов, и после каждой сделки выставлять покупку по курсу ниже рынка, что бы примерно следовать за волной. В общем, некоторый уклон в высокочастотность)
Насчет построения трендов и и работы с индикаторами тут есть отдельная статья (ссылка над комментариями), может быть и правда пора их к боту прикрутить..
16.10.2017 13:29
Добрый день Андрей! Вы можете написать торгового бота для биржи Exmo, для MAC OS X, с графическим интерфейсом?
17.10.2017 13:13
Добрый)
Смотря, что имеется в виду.. Если некий коробочный закрытый продукт, под продажу и прочее, то лучше обратиться к какой-нибудь команде, что специализируется под маки.
Если для себя, то могу на том же питоне или яве, но не хочу)
Мне представляется более правильным вынос бота на выделенный сервер и работу с ним через веб-интерфейс - тогда можно управлять из любой системы, включая смартфоны и прочее, бот не зависит от того, включен ли у вас комп и т.п. Свои последние решения я именно так и делаю.
17.10.2017 20:32
Интересно! Как это сделать?
17.10.2017 07:22
Здравствуйте Андрей! Бот работает . У меня вопрос по поводу исполнения ордеров. Когда бот покупает в buy и потом встает в sell, он должен в это время высталять отложенный ордер в buy ? Или он верно будет ждать исполнения sell и только после этого опять встанет в buy?
17.10.2017 13:21
Здравствуйте.
Бот выставляет бай на указанную сумму (5 долларов, например), после того, как бай выполнится, он выставляет купленное в селл, что бы получить 5.01 доллара. После того, как селл сработает, он снова выставляет бай на 5 долларов, цент идет в копилку. В общем, единовременно в торгах задействовано ровно столько, сколько указано в конфиге.
17.10.2017 15:03
Понятно...было бы удобней при просадке задействовать еще и между двух селл выводить среднею + %...в конфиге ограничивать такие действия либо наоборот разрешать.
17.10.2017 10:55
Андрей в отпуске;))
17.10.2017 13:21
Не не, я тут)
22.10.2017 21:10
40009: The nonce parameter is less or equal than what was used before "1508695268565"
Иногда проскакивает эта ошибка не пойму где я накосячил
23.10.2017 19:58
Лаги, скорее всего.. Может ботов одновременно несколько запущено или запросы вызываются ну очень часто (nonce же ко времени привязано). А вообще я тоже наблюдал такие глюки на эксмо, в такие моменты еще и интерфейс подтормаживает
24.10.2017 19:46
Здравствуйте, Андрей!
Спасибо за бота.

Скажите, почему может выдаваться ошибка:
Копирую и вставляю код бота, 
редактирую ключи апи
нажимаю F5
получаю сообщение об ошибке invalid syntax

Жаль, не могу сюда скриншот скинуть.
Оранжевым цветом в первой строке (до кода) помечена "6" в "Python 3.6.3"

Python 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 17:26:49) [MSC v.1900 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
25.10.2017 20:26
Error 50321: Price by order is more than permissible maximum for this pair
sell 0.02293607 102.77741 4481.038381902393

С предыдущим разобрался. Нужно было  создать новый файл без шапки. Этот текст не должен быть в начале кода бота.
25.10.2017 20:28
Error 50321: Price by order is more than permissible maximum for this pair
sell 0.02293607 102.77741 4481.038381902393 - что это за ошибка, подскажите, друзья

Бот работает исправно, но закрались вопросы. Он закупил эфира и не продает и ничего с ним не делает.
26.10.2017 18:48
Наценка лихая.. Вот мне тоже, например, не дало продать даш по цене 100 BTC за штуку )
Ошибка 10469: Цена по ордеру больше максимально допустимой по этой валютной паре (10 BTC)
28.10.2017 12:03
Ахаха))
27.10.2017 13:05
!!!! [WinError 10061] Подключение не установлено, т.к. конечный компьютер отверг запрос на подключение 

Такое бывает иногда? :) От прихоти биржи зависит? ) Вчера все работало, а сегодня такой контекст вылезает. )
27.10.2017 14:01
Бывает, особенно когда интернет сбоит. Ну и кстати сервер exmo.me зачастую более стабильно работает чем exmo.com, можно попробовать поменять настройки
28.10.2017 14:32
Здравствуйте Андрей. Большое спасибо за Бота :-) . Интересный способ авторизации. Авторизовался через ВК, как-то очень давно на ВК мой аккаунт подвергался взлому, поэтому имя здесь указано не корректно (только сейчас написал в поддержку по этому поводу).

Вопрос вот какого характера. Бот при работе с мелкими суммами (10$) работает довольно таки исправно, подключил на три пары, в целях эксперимента, но когда сумма доходит уже до 50$ бот не закупает на 50$ (практически всегда) закупает на меньшую сумму меньшее количество криптовалюты, а потом то что закупил пытается продать и в итоге стоимость валюты при таком раскладе увеличивается в 1,5-2 раза, и конечно же бот долгое время не может продать, помогите разрешить этот момент. Я читал все комментарии, знаю здесь такие вопросы задавали, но как решить этот вопрос? И второе, сложно будет немного изменить код, и научить бота после выставления ордера на продажу использовать другую сумму для создания другого ордера на покупку, то есть что бы бот работал с несколькими ордерами, то есть будет легче купить и продать по 10$ несколькими ордерами, чем к примеру работать одним ордером в 100$. Заранее благодарен. с Уважением Сергей К.
P.S. это не все вопросы :-) другие (по проще) напишу по позже...
28.10.2017 19:50
Добрый день
В любом случае всё сводится к изменению кода) Я постепенно веду статьи к боту версии 2, но со временем какая-то беда.. Думаю, оба вопроса, так же как и другие вопросы в комментариях, вполне можно заложить в новый алгоритм, так что пишите еще :)
По поводу аккаунта - когда вы восстановите данные со своей страницы и авторизуетесь тут, должно обновиться - если что, решим отдельно.
28.10.2017 16:08
40009: The nonce parameter is less or equal than what was used before "1509195220626000" время сервера на сайте 13:05, у меня 16:05. пробовала STOCK_TIME_OFFSET выставить и +3 и -3 и в том и в другом случае выдает одну и ту же ошибку.
28.10.2017 16:14
я даже попробовала перенастроить время самого компьютера в формат UTC - не помогло
28.10.2017 19:26
Возможно, сейчас у вас все правильно, но в какой-то момент вы отправили nonce из будущего, а теперь шлете из настоящего.. Самое простое решение - удалить на бирже API ключи и сгенерировать новые, тогда отсчет пойдет с начала
28.10.2017 19:39
Андрей?
28.10.2017 19:51
Oui?
28.10.2017 20:54
Bonjour. Ferez l'attention à mon message plus haut, merci.
28.10.2017 21:07
Bien sûr, mon ami, j'ai déjà répondu
29.10.2017 15:11
Выложил статью с тем же ботом, но еще и с индикатором MACD, код и пояснения можете найти тут: https://bablofil.ru/macd-python-stock-bot/
01.11.2017 08:00
Здравствуйте ув. Андрей К. Спасибо вам за бота. :)
Такой вопрос. У меня установлен Питон 3.4.4 на windows xp. Через /exmo.com не заходит, поэтому я захожу через /exmo.me. Код поправил согласно вашему ответу к первому коменту. На счету есть usd. При запуске скрипта отладчик выдает следующее:
Python 3.4.4 (v3.4.4:737efcadf5a6, Dec 20 2015, 19:28:18) [MSC v.1600 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> 
 RESTART: D:\exmo.py 
Открытых ордеров нет
Не удается вычислить среднюю цену []
Открытых ордеров нет
Не удается вычислить среднюю цену []
и т.д.

В чем проблемка?
01.11.2017 09:27
Разобрался. Проблема была в разнице часовых поясов.
Еще вопрос. Vladislav M. задавал вопрос про выгодную цену для покупки. Вы ему в ответе сказали, что нужно заменить avg_price = sum(prices)/len(prices)
на avg_price = min(prices), а нужный период, одна минута там или 15 нужно будет подбирать.
Пробовал указать новый период в AVG_PRICE_PERIOD, но тогда дебагер пишет:
 !!!! min() arg is an empty sequence
Как или где указывается нужный период?
01.11.2017 13:33
Вы всё делаете правильно, но из-за небольшого периода боту не удалось получить цены.  Он попытался выбрать минимальное значение, но выбирать оказалось не из чего, поэтому он и ругнулся.
Если используете min, то замените (или добавьте после)

except ZeroDivisionError:
    print('Не удается вычислить среднюю цену', prices)

except ValueError:
    print('Не удается вычислить минимальную цену', prices)
27.11.2017 21:44
Добрый день. Скажите пожалуйста как вы решили проблему часовых поясов
01.11.2017 10:57
здравствуйте, помогите пожалуйста разобраться в такой вот ошибке
Python 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 17:26:49) [MSC v.1900 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> 
 RESTART: C:\Users\URV\AppData\Local\Programs\Python\Python36-32\exmo_macd.py 
Traceback (most recent call last):
  File "C:\Users\URV\AppData\Local\Programs\Python\Python36-32\exmo_macd.py", line 7, in <module>
    import talib
ModuleNotFoundError: No module named 'talib'
>>> </module>
01.11.2017 13:36
Добрый день.
Видимо, не установлен модуль talib.
Вот тут подробно расписано, какие шаги нужно выполнить:

https://bablofil.ru/python-indicators/
01.11.2017 18:49
Здравствуйте, к сожалению от програмирования далёк. выходит вот такая фигня.Traceback (most recent call last):
  File "C:\Users\Администратор\AppData\Local\Programs\Python\Python36-32\eksmo.ру.py", line 8, in <module>
    API_KEY = K-e5c51237df0049f803b66405b3f59251936453a3
NameError: name 'K' is not defined
>>> </module>
01.11.2017 18:56
Добрый день.
Надо ключи в кавычках указывать, все как в примере
02.11.2017 08:35
Большое спасибо, бот заработал но стал выдавать такие вещи: buy 0.0007278151647535697 6869.8760923632935
Открытых ордеров нет
buy 0.0007277781978274247 6870.225042363293
Открытых ордеров нет
buy 0.0007277781978274247 6870.225042363293
Открытых ордеров нет
buy 0.0007277781978274247 6870.225042363293
Открытых ордеров нет
buy 0.0007277781978274247 6870.225042363293
Открытых ордеров нет
buy 0.00072773728009725 6870.611327389787
Открытых ордеров нет
buy 0.0007276537274545655 6871.400243479407
Открытых ордеров нет
buy 0.0007275260251239471 6872.606377411942
Открытых ордеров нет
buy 0.0007274259917260993 6873.551477223913
Открытых ордеров нет
buy 0.0007274259917260993 6873.551477223913
02.11.2017 10:02
Я немного обновил код бота, теперь будет писать чуть подробнее.
Скорее всего, сумма, выделенная для торгов в переводе на биткойны слишком мала - когда я писал статью, биткойн стоил в 10 раз меньше, и 5 долларов еще что-то да значили)
02.11.2017 11:52
Поставил сумму на покупку 25 долларов, всё пошло) Спасибо!
02.11.2017 11:49
У меня стоит 25 долларов, при тех же настройках ка в примере
03.11.2017 21:13
Добрый день, Андрей. Подскажите, что нужно изменить или дописать в бот, чтобы он после покупки и выставления ордера на продажу сразу бы пытался купить следующий уже по новой средней закупочной цене и.т.д. на сколько хватит депо, (если цена не в нашу сторону) Получится сетка ордеров Sell. Как сделать, чтобы он не следил за активными ордерами на sell, а думал,что все ордера проданы и выставлял новые, Сам попытался, не получилось, Бот EXMO без MACD. За бот спасибо! Работает без проблем. За ранее благодарен.
03.11.2017 22:16
Добрый день!

Не проверял, но вроде бы достаточно вот эту строку

raise ScriptQuitCondition('Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)')

заменить на вот это:

pass
04.11.2017 14:04
Андрей здравствуйте. Я ознакомился с Вашими сообщениями, адресованными мне, был немного занят, то есть сильно, а сейчас уже немного, поэтому не отписался, а сейчас выкроил 5сек, так как читаю новые сообщения и наткнулся вот именно на то, что и хотел Вас попросить подсказать, то есть, я Вас правильно понял, простите за тавтологию (масло масляное), если я заменю эту строку - raise ScriptQuitCondition('Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)')
на pass, он выставит ордер на продажу и забудет о нем?
Великолепно :-D это ведь и было нужно.
Простите за наглость, но сразу Вам напомню о еще одном не разрешенном вопросе, помните из предыдущего комментария, такая проблемка встречалась и у других :-) испытуемых, если я использую более крупную сумму, да и при менее крупных такое бывает, но реже, Бот не закупив на всю сумму допустим 50$, он закупает, допустим на 10$ и то что закупил, он почему то думает что закупил на все 50$, так вот, то что закупил продает за 50$ + комиссия биржи + %, условно будем считать 51%, в Итоге крипта выставляется по баснословной цене и он не может её продать - здесь неприятность в чём, если пользователь сразу заметил, он может сразу исправить, если момент упущен, то цена за упущенное время меняется, и средства замерзают до той поры пока валюта опять не вернется в этот коридор - этот вопросик ведь еще не решен?
И в завершении Андрей, Вы упомянули что обновили код Бота - это V2, или ничего существенного не изменилось?
О-о-ой Андрюха (простите за панибратство), я попробую эту строчку pass, если сработает, да и заработок появится какой-то (так то у меня Бот пока отдыхает), млин в долгу не останусь :-D
04.11.2017 16:16
Да, всё так=)
Нет-нет, это еще не V2. Насчет второго подумаю
19.05.2018 12:16
сегрей может вы мне подскажете ? меняю raise   на   pass   у меня бот перестаёт запускатся!  где искать причину???
04.11.2017 01:00
Спасибо! Уже час работает как надо. Если что то не так, отпишусь, Еще раз, спасибо!
04.11.2017 13:01
Здравствуйте! Подскажите, пожалуйста, как остановить бота, какой комбинацией?
04.11.2017 14:06
Ctrl+Alt+Del
04.11.2017 14:08
Простите за сарказм Ирина М., здравствуйте, если Вы закроете окошко, в котором видите работу Бота, нажмете на крестик, Бот выключится.
04.11.2017 16:56
у меня другой бот выключается CTRL+C, поэтому уточняю
04.11.2017 17:51
Добрый день.
Ctrl+C тоже пойдет
06.11.2017 17:53
Андрей здравствуйте.
pass работает :-)
отчетик завтра, после завтра напишу, так то не плохо получается, по моему, ладно...
Я Вам хочу письмецо бросить, на mail, гляньте, может удалось...

И еще вт штука какая с Ботом возникла, пара LTC_RUB, на ней частенько сбоит, так вот, как так получилось, что Бот buy 0.01 LTC я не понял, то есть других buy и sell просто нет, теперь Бот пытается свои 0.01 LTC (фактически получилось чуть меньше, где-то 0.009 и т.д.), а Биржа то Боту не дает выставить LTC на продажу, так как это меньше минимального порога. Вот так Бот и зациклился, то есть докупить он не может, так как т, что купил нужно сначала выставить на продажу, а выставить на продажу не может, так как средств слишком мало и Биржа не позволяет (кстати уточню, что других ордеров ни на покупку ни на продажу не было). Что думаете?
06.11.2017 18:03
Добрый день.
Торги могли быть по любой другой паре, в итоге на баланс упало (или осталось после торгов) немного LTC, которое бот и пытается продать.
ETH/LTC
LTC/BTC
LTC/USD
LTC/EUR
LTC/RUB
Еще на exmo добавили кешбек, может вам там что-то компенсировали?
06.11.2017 18:53
О!!! Вы мне уже написали...
Я проследил, Андрей, подглядел за Ботом, чего он делает, так вот он отменяет :-( частично исполненный ордер, сегодня начал так делать, то есть частично исполняется buy 0.01 LTC и он отменяет ордер, а потом продать не может.
А так LTC взяться не откуда пары у меня все разные...
Кстати Андрей, что касается валюты, я задаю Боту работу в 10RUB (USD, EUR) и эту сумму увеличиваю, 25, 50, 100, 200. Вот сейчас Бот берет для сделки 25 USD, 25 EUR, и 200 RUB, вот когда я поставил 200 RUB Бот начинает ошибаться по частично исполненным ордерам, либо выставляет часть по завышенной цене, либо вообще выставить не может, как я сегодня заметил. Завтра хочу увеличить для USD и EUR до 50 или 100, посмотреть как будет работать, нужно баланс пополнить, а может обновлю Бота, а после суммы увеличу. Решения по этому вопросу так и нет Андрей?
10.11.2017 10:10
Я обновил код бота (этого и macd), попробуйте поторговать с новой версией
06.11.2017 17:55
И Вы мне уточните имеет смысл переписать обновленный Бот, или обновления не существенны?
06.11.2017 18:07
Обновленный бот менее подвержен покупкам на пике, он создает ордера когда рынок разворачивается после падения.
Но для его работы нужно установить пару библиотек, там в статье расписано. Смотрите сами, я бы обновил)
06.11.2017 18:45
да, я понял, вот это https://bablofil.ru/macd-python-stock-bot/ перечитал, и решил обновится, ток сегодня не буду... :-)
07.11.2017 23:29
Здравствуйте, Андрей. Не получается установить  ta-lib. Все команды проходят, а последняя (на сайте pip install ta-lib) выдает 
talib/common.c(240): fatal error c1083: Cannot open include file: " ta_libc.h " : No such file or directory
error: command " С:\\Programm Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\cl.exe"failed with exit status 2.
Что делаю не так? 
Visual Studio 14.0 установлена. Спасибо.
08.11.2017 11:44
Я это решил так: 

https://github.com/mrjbq7/ta-lib#dependencies

"Download ta-lib-0.4.0-msvc.zip and unzip to C:\ta-lib"
08.11.2017 00:00
Еще вопрос. У меня винда 10 х64. Имеет значение разрядность Python? Пробовал и тот и тот, все-равно не получается запустить Талиб.
09.11.2017 00:02
Да вроде бы нет. Скачайте whl файл и будет счастье

Скачайте талиб отсюда - http://www.lfd.uci.edu/%7Egohlke/pythonlibs/, для любой разрядности, потом нужно установить его pip install путь_к_файлу.whl
09.11.2017 09:52
Спасибо, помогло.
08.11.2017 12:29
Господа.

FYI

exmo.ME заработал по HTTPS

кто пользовался этим доменом, меняем настройки на защищенность )
08.11.2017 23:42
Андрей, доброго времени суток Вам. 
А не подскажете куда копать в случае такой ошибки 
Error 40016: Maintenance work in progress
08.11.2017 23:59
Ждать.. Видимо, разработчики на сервере что-то меняют. Хотя обычно заранее предупреждают...
Можно попробовать exmo.me сменить на exmo.com, биржа одна, точки входа разные
09.11.2017 10:19
Добрый день, Андрей. У меня код для EXMO не хочет рисовать графики. Даже не запускается. Это на Win 10 64 бит. Причем на 8,1 32 бит работает. Причину найти не смог. :(
09.11.2017 08:22
А теперь выскакивает такая строка
('Ошибка анализа возвращаемых данных, получена строка', b'<html>\r\n<head><title>503 Service Temporarily Unavailable</title></head>\r\n<body bgcolor="white">\r\n<center><h1>503 Service Temporarily Unavailable</h1></center>\r\n<hr/><center>nginx</center>\r\n</body>\r\n</html>\r\n')
09.11.2017 09:53
У меня тоже...
09.11.2017 10:20
Проверил, сейчас работает.
Ошибка 503 означает, что на сервере, к которому вы обращаетесь, что-то не запущено.
Т.е. вопрос к владельцам биржи, что там по ночам админы вертят ) Наверное, чинили что-то
09.11.2017 23:44
Андрей, доброго времени суток.
Может это глюк или еще что-то, но не однократно наблюдал как бот когда часть ордера продал или купил. Отменял другую часть и ставил на продажу с вдвое завышенной ценой.
Валютная пара рип-рубли играл на сумму 777,56
10.11.2017 10:12
Добавил еще одну проверку в код бота, должно уйти. Обновил код на сайте (на этой странице и на https://bablofil.ru/macd-python-stock-bot/)
13.11.2017 09:25
Андрей, доброго дня.
Все таки проблема   осталась с делением ордера потом его отменой, а потом выставление нового ордера по завышенной цене, но стала появляться вот такая надпись "40009: The nonce parameter is less or equal than what was used before "1510554126439""
16.11.2017 16:35
Pavel K.
Диагноз: Параметр nonce меньше или равен тому, что было использовано до "1510554126439". Это может быть случае если параллельно к API идёт обращаение с бота и еще с чего либо.
Лечение: Нужно поменять API key и API secret
14.11.2017 12:02
Vivat. Андрей я вернулся, решив вопросы с поддержкой ВК, вернул свое имя :-)
Pavel К. я ставил Бота на USD, EUR, RUR - вот когда задаешь крупную сумму, в частности пара LTC-RUR сумму устанавливаю 200руб. для одного ордера, тогда Бот начинает здесь "путаться" скажем так. То есть закупив часть монет он отменяет не исполненный ордер, точнее не полностью исполненный, а потом то, что закупил продает за эти же 200руб, + комиссия биржи + навар, и получается цена практически в два раза выше имеющейся. Если сумма меньше 50, 100 тогда не глючит, конкретнее при 100RUR глючит реже, при этом Бот работает на паре BTC_USD на 100USD, и на паре ETH_EUR на 50EUR и таких ошибок не наблюдается.
Вот как бы Андрей эту ошибочку исправить, точне я бы сказал разрешить этот момент, почему так происходит, по сути он же проверяет исполнение ордера, и проверяет на наличие частично исполненного ордера, но почему то потом отменяет частично исполненный ордер :-(
И ещё я заметил (как мне показалось), чем выше сумма, которой Бот единовременно апеллирует, тем чаще Бот ошибается при работе.
Сегодня, завтра попробую испытать обновленный код Бота.
14.11.2017 12:09
P.S. Что касается прибыльности, то за сутки Бот показал навар на паре BTC_USD 0,84%, и на паре LTC_RUR 0,34%, я думаю при стабильной работе Бота, а плюс ещё если использовать обновленный код (где Бот не должен закупаться на пике), думаю будет картинка более радужная, хотя та, что имеется тоже очень даже ничего особенно на паре BTC_USD. Вот устранить бы только этот моментик...
В очередной раз Андрей выражаю Вам признательность за Бота, за открытый код и за поддержку.
с Уважением Сергей К.
14.11.2017 15:50
На паре ETH_EUR за 5 дней + ориентировочно 6%
15.11.2017 00:29
Андрей, здравствуйте!
Во первых - спасибо за БОТа!
Я конечно же, соответственно с Вашими рекомендациями по освоению трейдинга новичками, сейчас в минусе ))
Делаю совсем первые шаги, но вот какой у меня вопрос - как можно сделать (что изменить в коде), чтобы цену продажи программа рассчитывала не из завершенных сделок, а из стоящих в очереди ордеров на продажу.

Т.к. когда торговля активная, то бот практически не может купить, т.к. с ценой опаздывает всегда. Я меняла установочные параметры, но не помогает. К примеру цена покупки 6650, он ставит 6621 (это далеко в списке ордеров очень)

И еще в AVG_PRICE_PERIOD у Вас задан 90, а затем еще умножается на 60 в строке 158. Не значит ли, что AVG_PRICE_PERIOD надо задавать в минутах? (прошу прощения, программирования не знаю).

Заранее благодарна за ответ!
17.11.2017 12:42
Для этого нужно в коде поменять кусок

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)

на что-то вроде
offers = call_api('order_book', pair=CURRENT_PAIR)[CURRENT_PAIR]
try:
    avg_price = min([item[0] for item in offers['bid']]) # мин спрос

ну или там
avg_price = max([item[0] for item in offers['bid']]) # макс спрос
avg_price = max([item[0] for item in offers['ask']]) # макс предложение
avg_price = min([item[0] for item in offers['ask']]) # мин предложение
avg_price = sum([item[0] for item in offers['bid']]])/len(offers['bid']) # средний спрос
и т.п.

Параметр да, в минутах, обновил примечание к статье. Причем тут для каждой пары нужно подбирать.
Если, например днем BTC_USD торгуется десятками сделок в минуту, то среднюю лучше брать минут за 5-10, а какой-нибудь DOGE-BTC порой одна сделка в 10 минут, а ночью и того реже - тут лучше ставить час-полтора.. Но это всё индивидуально, конечно
17.11.2017 18:15
Я заменила на кусок 
offers = call_api('order_book', pair=CURRENT_PAIR)[CURRENT_PAIR]
try:
avg_price = min([item[0] for item in offers['bid']]) # мин спрос

но выдается ошибка : TabError : Inconsistent use of tabs and spaces in identation  - на строке offers...

Я совсем не программист, может надо было что-то оставить из удаленной части?
17.11.2017 20:22
Для питона важна структура текста - в частности, отступы. В данном случае в комментариях пробелы съедаются, вам нужно добавить пробелов, как в статье
offers = call_api('order_book', pair=CURRENT_PAIR)[CURRENT_PAIR]
try:
____avg_price = min([item[0] for item in offers['bid']]) # мин спрос
Ну и перед ними, конечно, как было
18.11.2017 00:45
с пробелами понятно, спасибо! 
блок заменила, бот запустился, перевел одну валюту в другую (я забыла, что не должно быть currrency_1), но дальше  выдает ошибку : 
______
- открытых ордеров нет
!!!! can`t multiply sequence by not-int of type 'float'
_______
и на этом циклится
18.11.2017 14:21
Тогда вот так:
avg_price = min([float(item[0]) for item in offers['bid']])
Хотя вас, скорее интересует
avg_price = min([float(item[0]) for item in offers['ask']])  # лучшая цена продажи из стакана
И имейте в виду, что бот же добавляет комиссию, так что ордер на покупку создастся по немного более низкому курсу, чем лучшая цена продажи.
В данном случае, вам, вероятно, подойдет
avg_price = sum([float(item[0]) for item in offers['ask'][:20]])/20
Т.е. берутся 20 лучших цен из стакана, из них средняя, из неё вычитается комиссия, и выставляется ордер на продажу.
18.11.2017 15:16
Андрей, честно сказать - я не поняла алгоритма.

мне кажется логичным, что на покупку лот выставляется или верхним (по максимальной цене покупки), или в верхней тройке стакана покупки - и пытается там удержаться. Не ориентируясь на стакан продаж.

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

Какую строчку кода брать для этого?

Или я не права? И алгоритм гораздо более сложный?
18.11.2017 17:07
А, ну вы написали "из стоящих в очереди ордеров на продажу", я понял так, что вы хотите покупать по тем ценам, по которым кто-то уже продает, что бы быстрее  сделки совершались. У каждого своя стратегия)

Если вы хотите получить лучшую цену из стакана покупок, то будет так:
avg_price = float(offers['bid'][0][0])
Если среднюю из топ-3 стакана, то так:
avg_price = sum([float(item[0]) for item in offers['bid'][:3]])/3

Но бот устроен так, что после определения цены продает с учетом комиссии, например сейчас лучшая цена покупки BTC_USD - 7620.21540187. Бот определил её по формуле avg_price = float(offers['bid'][0][0]). 

После этого бот берет имеющееся кол-во денег, узнает сколько можно купить и по какому курсу нужно купить, что бы компенсировать комиссию (0.2%), и итоговый курс покупки составит уже 7597.354755664391 - и вы уже не в топе стакана, а ниже.

Если убрать комиссию при покупке - то вы сможете оказываться в топе стакана, но эту комиссию придется компенсировать при продаже, так что цена продажи будет задираться намного выше, и будет намного сложнее продать купленное.
18.11.2017 19:18
Со строкой 
avg_price = float(offers['bid'][0][0])
все равно не получается лучшая цена из стакана покупок, и даже близкая к лучшей.

привожу пример: 
пятерка стакана покупок:
125.3738964	0.01196421	1.49999962
125.184745	1.99891612	250.233804
125.18474481	0.19666428	24.6193677
125.180001	22.97	2875.38462
125.0941	0.0113531	1.42020582

бот выставил 

buy
124.99777471


т.е. ну очень далеко...

код такой (стоит в строках 165-167  между двумя рыжими комментариями): 
 offers = call_api('order_book', pair=CURRENT_PAIR)[CURRENT_PAIR]
                    try:
                        avg_price = float(offers['bid'][0][0])
18.11.2017 19:20
Я что-то не так делаю?
18.11.2017 19:26
Я что-то не так делаю?
18.11.2017 19:34
Андрей, прошу прощения. Видимо интерпретатор питона не брал исправленный файл, пока я совсем не закрыла окно с командной строкой. Я делала прерывание, он видимо исполнял предыдущую программу с Вашим кодом, который указан на этой странице. Сейчас все пошло. Спасибо Вам! О результатах напишу ))
18.11.2017 21:01
И все же:
стакан покупок
129.1 0.89941013 116.113847
129 2.92629127 377.491573
128.9 0.32355078 41.7056955
128.73315792 0.19154096 24.6576726
128.6542 0.21202776 27.2782618

робот упорно стоит на
buy
128.5836

т.е. это 7-8 место в стакане. Я уже время ожидания поставила 1.5 минуты, но все равно он ставит цену значительно ниже верхушки стакана.
Торги не активные, в минуту 3-4 сделки, т.е. верхние ставки стакана меняются не часто.
18.11.2017 22:21
Да, и если вы внимательно прочитаете мой предыдущий ответ, то узнаете почему :)
Если вы хотите покупать по лучшей цене из стакана, и готовы перенести комиссии на продажу, то нужно весь этот блок

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) 
заменить на
offers = call_api('order_book', pair=CURRENT_PAIR)[CURRENT_PAIR]
try:
____my_need_price =  float(offers['bid'][0][0])

Так же сверху строку 

price=wanna_get/float(balances[CURRENCY_1]),
заменить на
price=wanna_get/float(balances[CURRENCY_1])/(1-STOCK_FEE),
15.11.2017 00:53
Присоединяюсь к выше стоящему вопросу.Чуть балуюсь программированием, для своей программы интересует как прочитать текущие заявки в стакане и какие методы отвечают за покупку/продажу напрямую со стакана? Или всё же надо выставлять свои ордера по текущему курсу в стаканах?
17.11.2017 12:55
Для получения информации из стакана можно воспользоваться методом order_book (пример выше в комментариях).
У него такая структура

{
  "BTC_USD": {
    "ask_quantity": "3",
    "ask_amount": "500",
    "ask_top": "100",
    "bid_quantity": "1",
    "bid_amount": "99",
    "bid_top": "99",
    "ask": [[100,1,100],[200,2,400]],
    "bid": [[99,1,99]]
  }
}
Что бы получить все предложения на продажу, например, вам нужно получить данные, (пример - https://api.exmo.com/v1/order_book/?pair=BTC_USD), по нужной валюте получить ask, и из массива данных выбрать цены.
Т.е. в ask массив вот таких наборов данных, каждый из которых состоит из трех элементов - цена, кол-во и итоговая сумма
"ask": [
      [
        "7630",
        "0.0038922",
        "29.697486"
      ],
      [
        "7632.75585412",
        "0.00318479",
        "24.30872451"
      ],
      [
        "7639.80899999",
        "0.00131284",
        "10.02984684"
      ],
Когда вы выставляете ордер, вы не покупаете из стакана, вы просто изъявляете желание купить такой-то объем такой-то валюты по такому-то курсу. Если в стакане есть желающий продать на тех же условиях, то ваши взаимные ордера удовлетворяются биржей. Если сейчас нет таких желающих, то ваше предложение падает в стакан, и висит там, пока не появится противоположный желающий.
26.08.2018 11:25
Подскажите как прописать прописать эти данные чтоб можно было получать такую информацию ???
15.11.2017 18:12
Андрей здравствуйте. Думал ещё обождать вторые, третьи сутки, но нет, не выдержал, практически сразу с запуском первого Бота появляется вот такая информация:
"!!!! [WinError 10060] Попытка установить соединение была безуспешной, т.к. от другого компьютера за требуемое время не получен нужный отклик, или было разорвано уже установленное соединение из-за неверного отклика уже подключенного компьютера".

Что-то на сервере биржи? Через некоторое время Бот продолжает работать, торгует, и потом опять вот такие сообщения, сейчас работают три Бота (то есть на трех парах по Ботьян Боту Ботовичу :-D ), решил, что проблема в этом ограничении на 180 обращений в минуту, закрыл (все) четыре страницы биржи, открытых в браузере, но сообщение все равно остается... :-( Уверен связано с тех работами биржи, на ввод исчезли Киви и Яндекс Money, видимо чинят. Посмотрел по "навару" по паре LTC_RUR на один ордер берет 100руб, с частично исполненными ордерами не ошибается, кстати, как было ранее, позже увеличу сумму до 200руб. В общем в Итоге получилось +0,2% за сутки, я предполагаю, если бы этого сообщения не было и Бот работал бы стабильно, то профит был бы больше, 0,8% я думаю на пахал бы, посмотрим завтрашние сутки. На других парах "навар" не смотрел, позже :-) :-) :-) сюприз будет...
с Уважением Сергей К.
17.11.2017 12:32
Добрый день.
Все правильно, нестабильная связь. Проблемы с сервером или сетью
18.11.2017 10:21
Да вот :-( что-то это сообщение постоянно висит, Андрей?
P.S. Bonjour.
18.11.2017 10:22
Vous possédez le français ?
18.11.2017 14:00
Ну тогда нужно попробовать сменить exmo.com на exmo.me, https на http (примеры выше в комментариях), провайдера и т.п.
19.11.2017 10:22
да, я об этом читал, в комментариях, и всё думаю именно так и поступить, как освобожусь поменяю .com на .me со всеми причитающимися, я Вам отпишусь...
Доброго часа.
19.11.2017 16:45
слушайте, Андрей, а другой причина не может быть, Бот то ведь работает, ну в смысле покупает, продает, а потом (часто) выскакивает это сообщение, о котором я писал, или ладно, сейчас попробую изменить на .me
19.11.2017 17:16
ну всё, исправил, Андрей, сообщение перестало поступать, но, кроме того, еще появилось сообщение nonce, я сбросил API и записал новые, перезапустил Бота, но сообщение nonce периодически появляется, работает три Бота, думаю дело в этом, это сообщение ведь не мешает работе Бота, забить на сообщение?
Вот это ограничение в 180 обращений в минуту - это ограничение на аккаунт или на IP?
И еще один вопросик, что если CURRENCY_2 у меня будет одна и та же допустим у двух Ботов на двух парах, ну к примеру BTC_USD и ETH_USD, Боты запутаются? Вообще я думаю не должны, и в V2 можно разрешить этот вопрос, верно?
20.11.2017 00:20
Количество API вызовов ограничено 180 запросами в минуту с одного IP адреса либо от одного пользователя. Вот так вот)
Ну и не раз замечал, именно у них, что они на nonce ругаются не по делу. Думаю, там что-то с балансировщиком нагрузки, ну или еще с чем то.. Ну да, остается только забить
На смежные пары лучше не играть, один бот начнет скупать, а другой продавать)
19.11.2017 15:09
Андрей, здравствуйте!
Спасибо за открытый код бота!
Для биржи битрекс Вы выложили код со следующей стратегией - "Таким образом, он будет стараться купить дешевле, но продать как можно дороже, а если курс вырастет недостаточно и пойдет на спад, то будет выставлять по минимально допустимой цене (с учетом комиссии при покупке, при продаже и требуемого навара)."
Немогли бы Вы для эксмо заложить продажу так же не по заложенному изначально проценту, а плавающий на увеличение в зависимости от macd + возможность скинуть ордер если тренд развернулся как в битрексе, а не ждать до упора продажи как сейчас.
Заранее спасибо.
И если бы Вы открыли страницу с донат кошельками, многие могли бы Вас отблагодарить.
19.11.2017 17:18
а я тыкаю на эту иконку https://blockchain.info/Resources/buttons/donate_64.png , а она что-то ни в какую не поддается, думаю видимо надо по дольше потыкать :-D
19.11.2017 22:48
Опа только после Вашего поста обратил внимание на кнопки, они так вставлены что воспринимаются как реклама и соответственно просто пролистываются.
19.11.2017 22:59
Кто пользуется ботом на эксмо посмотрите пожалуйста. У меня сегодня к вечеру 19.10.2017 он перестал определять что есть открытые ордера, которые он сам и открыл. Т.е. после открытия он их так и начинает плодить, открывая один за одним. Пробывал заново запускать оригинальный файл с сайта, тоже самое. Может что в апи поменяли и проверка на открытые ордера перестала проходить?
20.11.2017 17:18
интересное определение "открытые ордера", открытые ордера на что на покупку или на продажу? Я думаю у Вас вот что произошло, цена валюту пошла вниз, Бот легко скупает по интересной цене валюту и выставляет на продажу, таким образом у Вас много Sell и максимум один Buy, верно? Раньше Бот ждал когда продаст выкупленный объем, сейчас нет, выставил на продажу и помчался дальше скупать по выгодной цене, так гораздо интереснее.
Все верно Дмитрий, у Вас именно эта проблема?
20.11.2017 19:48
Нет. Такой логики как я понимаю не заложено в боте, он не может скупать дальше пока не продаст имеющееся, поэтому и закладывается лимит суммы покупки.

Изначально как стал использовать бот было так: например пара ETH_RUB при этом ETH=0 RUB=1000 на счету, соответственно в настройке стоит CAN_SPEND = 100 (торговать на 100 руб.) При запуске бот раньше если MACD давал добро создавал ордер на покупку эфира (на 100 руб. например 0,005 eth) и все дальше бот покупал эфир. Далее бот смотрит есть ли у нас эфир

if float(balances[CURRENCY_1]) >= CURRENCY_1_MIN_QUANTITY: # Есть ли в наличии CURRENCY_1, которую можно продать?

и соответственно создавал ордер на продажу, далее продавал и потом все повторялось (снова покупал и продавал). Но это все было в пределах одного ордера, т.е. один ордер на покупку  CURRENCY_1, покупка, далее один ордер на продажу  CURRENCY_1.

А сейчас именно после запуска бота создаются ордера на покупку  CURRENCY_1 при чем, бот создал ордер1 на покупку, далее цикл в боте повторяется и похоже не срабатывает вот эта проверка (в логе пишется что - Открытых ордеров нет)
        # Получаем список активных ордеров
        try:
            opened_orders = call_api('user_open_orders')[CURRENCY_1 + '_' + CURRENCY_2]
        except KeyError:
            if DEBUG:
                print('Открытых ордеров нет')
            opened_orders = []

т.е. несмотря на то что ордер1 на покупку CURRENCY_1 уже создан, бот создает еще один ордер2 на покупку (беря при этом из кассы еще 100 руб.) и так далее.

Пример лога

======================= RESTART: D:\Downloads\exmo.py =======================
Открытых ордеров нет

Warning (from warnings module):
  File "D:\Downloads\exmo.py", line 93
    idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0
RuntimeWarning: invalid value encountered in sign
Выход, по MACD рынок падает
Открытых ордеров нет
Выход, по MACD рынок падает
Открытых ордеров нет
Выход, по MACD рынок падает
Открытых ордеров нет
Выход, по MACD рынок падает
Открытых ордеров нет
Выход, по MACD рынок падает
Открытых ордеров нет
buy 0.0052302330130544975 19119.607052000003
{'result': True, 'error': '', 'order_id': 355891385}
Создан ордер на покупку 355891385
Проверяем, что происходит с отложенным ордером 355891385
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло 3.7050793170928955 секунд
Открытых ордеров нет
buy 0.0052302330130544975 19119.607052000003
{'result': True, 'error': '', 'order_id': 355891494}
Создан ордер на покупку 355891494
Проверяем, что происходит с отложенным ордером 355891494
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло 3.2111592292785645 секунд
Открытых ордеров нет
buy 0.005266103900709809 18989.370867999998
{'result': True, 'error': '', 'order_id': 355891587}
Создан ордер на покупку 355891587
Проверяем, что происходит с отложенным ордером 355891587
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло 5.809226036071777 секунд
Открытых ордеров нет
Выход, по MACD рынок падает
Открытых ордеров нет
Выход, по MACD рынок падает
Проверяем, что происходит с отложенным ордером 355891587
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло 20.484038829803467 секунд
Проверяем, что происходит с отложенным ордером 355891587
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло 23.049363136291504 секунд
Проверяем, что происходит с отложенным ордером 355891587
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло 25.54434323310852 секунд
Проверяем, что происходит с отложенным ордером 355891587
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло 28.513219356536865 секунд
Проверяем, что происходит с отложенным ордером 355891587
Частично исполненных ордеров нет
Отменяем ордер -за 0.5 минут не удалось купить ETH
Проверяем, что происходит с отложенным ордером 355891494
Частично исполненных ордеров нет
Отменяем ордер -за 0.5 минут не удалось купить ETH
Открытых ордеров нет
20.11.2017 23:35
Сейчас запускаю тот-же файл, он уже работает нормально. В чем причина сбоя была не понятно.
21.11.2017 05:21
а, ну вот это я х.з. :-)
25.11.2017 00:25
Я правильно понимаю, что запустить двух ботов на пары например ETH/USD и ETH/RUB нельзя, т.к. при выставлении ордера на продажу в расчете используем balances[CURRENCY_1] соответственно при пополнений баланса CURRENCY_1 со сделок и по долларам и по рублям мы будем получать некорректную переменную - price=wanna_get/float(balances[CURRENCY_1])
Как то можно это обойти?
Кто нибудь знает алгоритм как торговать на 2-х парах одновременно?
25.11.2017 21:04
Добрый день.
Да, так лучше не запускать, будут чудеса.
Не думаю, что есть какой то алгоритм кроме изменения кода - лучше играть на непересекающиеся пары
25.11.2017 23:18
Здравствуйте, Андрей. Подскажите, пожалуйста, что нужно изменить в коде, чтобы бот Poloniex не отслеживал ордера на SELL. а выставлял следом на BUY ? Так сказать, получится сетка ордеров на SELL. Спасибо за бота. На EXMO вы мне помогли.Очень доволен. Еще раз спасибо. Знаю,что не та ветка, но на "Купи-продай-навари - бот для биржи Poloniex" Вы давно не появлялись :)
26.11.2017 15:09
Вылазит !!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777)
api.exmo.com на api.exmo.me менял - результат тот же.
26.11.2017 15:14
Решил посредством смены протокола на http, поменяв строку:
conn = http.client.HTTPSConnection(API_URL, timeout=60)
На:
conn = http.client.HTTPConnection(API_URL, timeout=60)
28.11.2017 21:52
Здравствуйте! У меня вопрос такой. Переделал боты на другую валюту, все сделал внимательно. При запуске ботов, они выставляют ордер на покупку по той средней цене, которая была несколько свечей назад. Не могу догнать в чем причина. В строке STOCK_TIME_OFFSET = 0 ставил разные значения, а именно 0, +3 и -3 ( так как время расхождения времени сервера и моего часового пояса составляет 3 часа). При значении +3 бот вообще не получал данные по цене. Так в чем же дело, почему бот не получает реальных значений средней цены?
28.11.2017 21:52
Здравствуйте! У меня вопрос такой. Переделал боты на другую валюту, все сделал внимательно. При запуске ботов, они выставляют ордер на покупку по той средней цене, которая была несколько свечей назад. Не могу догнать в чем причина. В строке STOCK_TIME_OFFSET = 0 ставил разные значения, а именно 0, +3 и -3 ( так как время расхождения времени сервера и моего часового пояса составляет 3 часа). При значении +3 бот вообще не получал данные по цене. Так в чем же дело, почему бот не получает реальных значений средней цены?
29.11.2017 11:51
AVG_PRICE_PERIOD = 90 # За какой период брать среднюю цену.
Цена зависит от этого значения.
29.11.2017 21:33
AVG_PRICE_PERIOD =15. И все равно среднюю цену выставляет не совсем реальную, как будто несколько свечей назад
03.12.2017 12:19
Нужно оставить 0, вы будете работать по времени биржи, UTC.
Плюс, после получения цены к ней подмешивается комиссия, так что итоговая цена покупки/продажи отличается от расчетной.
А как вы проверяете, что не совпадает, она выходит за границы high/low последних свечей?
29.11.2017 19:57
Zdravstvujte! Napisal kod kak ukazano, a poluchaju -SyntaxError: multiple statements found while compiling a single statement
Chto eto znachit? Gde oshibka?
03.12.2017 12:09
Код нужно сохранить в файле, потом запускать.
Нажмите File -> New File, сохраните, потом F5
02.12.2017 12:10
при запуске выдает ошибку !!!! Name 'urllib' is not defines
03.12.2017 12:10
Питон версии 2 видимо у вас. Нужно поставить 3.6+, скачайте c оф. сайта https://www.python.org/
03.12.2017 22:33
Добрый вечер!
запустил бота, вроде сделал продаж потом пишет:

Открытых ордеров нет
sell 18.17258492 5.06 0.2784414007294676
Error 50189: Pair was not found 'USD_BTC'
Открытых ордеров нет.

Как я понимаю продажа все же не прошла, пары нет и он циклит!! как исправить???
03.12.2017 22:56
Исправил!!!!
04.12.2017 21:19
Здравствуйте, Андрей. Подскажите, пожалуйста, что нужно изменить в коде, чтобы бот Poloniex не отслеживал ордера на SELL. а выставлял следом на BUY ? Так сказать, получится сетка ордеров на SELL. Спасибо за бота. На EXMO вы мне помогли.Очень доволен. Еще раз спасибо. Знаю,что не та ветка, но на "Купи-продай-навари - бот для биржи Poloniex" Вы давно не появлялись :)
06.12.2017 00:24
Здравствуйте, нужна небольшая помощь\консультация. Попытался настроить бота на торговлю между ETC и USD, что бы пот покупал Ефир классик за доллары. на балансе для теста было 9$, can spend поставил на 5. При старте скрипта пишет "Выход. Не хватает денег на создание ордера"
Вот какие данные я указал

CURRENCY_1 = 'ETC'
CURRENCY_2 = 'USD'

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

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

STOCK_TIME_OFFSET = -2 # Если расходится время биржи с текущим
06.12.2017 16:09
Добрый день,Андрей!!  Нужна помощь. Попытался настроить бота на торговлю USD-RUB  На балансе 5,3 $. при старте пишет Открытых ордеров нет
sell 5.36361614 5.015 0.9350035254387163
Error 50189: Pair was not found 'USD_0.01RUB'  Вот какие данные я указал 

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

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

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

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

# базовые настройки
API_URL = 'api.exmo.me'
31.12.2017 20:04
У меня USD RUB работает вроде нормально.Я указываю рубль а не доллар.примерно так. # Тонкая настройка
CURRENCY_1 = 'USD' 
CURRENCY_2 = 'RUB'

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

ORDER_LIFE_TIME = 15 # через сколько минут отменять неисполненный ордер на покупку CURRENCY_1
STOCK_FEE = 0.002 # Комиссия, которую берет биржа (0.002 = 0.2%)
AVG_PRICE_PERIOD = 30 # За какой период брать среднюю цену (мин)
CAN_SPEND = 7338 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1
PROFIT_MARKUP = 0.002 # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
DEBUG = False # True - выводить отладочную информацию, False - писать как можно меньше
06.12.2017 19:17
Андрей! На валютных парах ETH-USD бот работает нормально, только на паре USD-RUB такое пишет.
06.12.2017 19:17
Андрей! На валютных парах ETH-USD бот работает нормально, только на паре USD-RUB такое пишет.
06.12.2017 19:43
CURRENCY_1_MIN_QUANTITY = 0.01 # минимальная сумма ставки
CURRENCY_1_MIN_QUANTITY = 3(как минимум)
06.12.2017 19:50
CAN_SPEND = 5 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1 Вместо 5-ки поставить сумму как минимум 3 бакса в пересчете на рубли . Я ставлю 200 (для примера)
07.12.2017 09:16
Большое спасибо, все понял, буду тестировать.
07.12.2017 16:17
Андрей, здравствуйте, запускаю код с минимальными изменениями (exmo.com --> exmo.me; HTTPSConnection --> HTTPConnection) под Mac OS, версия программы 3.6, получаю ошибку ImportError: No module named http.client

С чем может быть связано? 

Заранее спасибо.
08.12.2017 06:12
оказалось несмотря на версию 3.6, httplib надо ставить

остальные стандартные правки как и у других комментаторов
13.12.2017 16:54
В чем у Вас заключалась проблема ? Сижу сутки калупаю!
18.12.2017 16:00
Python должен быть версии 3.6.+
08.12.2017 06:37
Уважаемый Андрей, есть ли возможность поковырять API Livecoin? Уж очень хочется бота.
13.12.2017 11:28
Скопировал код в окно питона, при компиляции f5 пишет ошибку - invalid syntax? В чем может быть проблема?
18.12.2017 16:01
File -> New File -> Save -> F5
13.12.2017 16:15
Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> 
====================== RESTART: D:/питон бот/botexmo.py ======================

Traceback (most recent call last):
  File "D:/питон бот/botexmo.py", line 1, in <module>
    import urllib, http.client
ImportError: No module named http.client
>>> 

По паре BTC\USD
По паре  LTC\RUB  тоже самое.</module>
18.12.2017 16:03
Поставьте Python последней версии (3.6.+)
14.12.2017 12:30
Все! Разобрался с проблемой сам. Вообщем что еще хотелось сказать по поводу работы бота. Вроде торгует, в минуса не уходит. Но можно влететь в долгое инвестирование, когда бот создает заявку на покупку при максимальной цене пампа. Есть у меня очень полезная идея, которая сможет оградить от сидения месяцами с не исполненным ордером на продажу. Было бы неплохо, если бы бот получал информацию с сервера о самой высокой курсовой цене на валюту за определенный период, а потом от этой цены можно было бы указать в % отношении вручную, когда бы он тормозил с созданием ордера на покупку. Можно даже не получать инфу с сервака автоматом, а просто вписывать максимальное значение где-нибудь в самом коде.
18.12.2017 16:05
Так а если курс растет, как сейчас - он неделями ничего покупать не будет) Попробуйте версию с macd - там бот толерантнее - https://bablofil.ru/macd-python-stock-bot/
14.12.2017 20:49
Ну чё тут скажешь. Огромное тебе человеческое спасибо за идею. Нифига не шарю в программировании поэтому буду реализовывать это на зеннопостере
15.12.2017 13:33
Добрый день!
Чего-то у меня не работает бот...
Last login: Fri Dec 15 16:23:29 on ttys001
JOKER-MacBook:~ JOKER$ cd '/Users/JOKER/Desktop/' && '/usr/bin/pythonw'  '/Users/JOKER/Desktop/exmo.py'  && echo Exit status: $? && exit 1
  File "/Users/JOKER/Desktop/exmo.py", line 67
SyntaxError: Non-ASCII character '\xd0' in file /Users/JOKER/Desktop/exmo.py on line 67, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details


Строка 67:
       raise ScriptError('Ошибка анализа возвращаемых данных, получена строка, response')
18.12.2017 16:14
Не пойму, что за версия питона.. 
Попробуйте в начале указать
# -*- coding: utf-8 -*- 
или в какой кодировке вы сохранили файл. 
Если питон версии 2.7+, установите версию 3.6+
15.12.2017 21:08
Бот действительно отлично помогает справиться с рутинными моментами! Хотелось бы поточнее узнать, как бот для exmo можно сделать на несколько пар сразу, например на 3. Приходится запускать сразу 3 бота отдельно, еще из-за этого часто пишет  "The nonce parameter is less or equal than what was used before",  в одно время поступают одинаковые запросы с разных ботов. Пробовал тупо копировать код в конец и изменять во вставленном коде пары, но он торгует, почему-то, все равно 1 парой.
16.12.2017 22:43
Здравствуйте!
Нужна помощь. Заранее благодарен.
При запуске бота выдает следующее:

!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:748)
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:748)
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:748)
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:748)
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:748)
!!!! [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:748)
^CTraceback (most recent call last):
  File "EXMO_Bot1.py", line 203, in <module>
    main_flow()
  File "EXMO_Bot1.py", line 76, in main_flow
    opened_orders = call_api('user_open_orders')[CURRENCY_1 + '_' + CURRENCY_2]
  File "EXMO_Bot1.py", line 56, in call_api
    conn.request(http_method, "/"+API_VERSION + "/" + api_method, 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 1392, in connect
    super().connect()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 936, in connect
    (self.host,self.port), self.timeout, self.source_address)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 713, in create_connection
    sock.connect(sa)
KeyboardInterrupt</module>
18.12.2017 16:18
У некоторых провайдеров так бывает, посмотрите второй комментарий сверху, вам возможно нужно будет немного изменить код
20.12.2017 13:40
Здравствуйте, в боте битрикса используется параметр growing, можно ли его прикрутить сюда? Стоит ли?
20.12.2017 15:37
Вообще есть такой эксперимент, и код написан, почитайте тут
https://bablofil.ru/macd-python-stock-bot/
По мне так стоит, так он будет реже ошибаться
20.12.2017 16:03
Спасибо, что ответили. Я качал версию с macd для exmo биржы, там я так понял идет анализ по разнице кривых, а в боте битрикса помимо разницы есть еще параметр роста? Правильно я понимаю? Могли бы вы встроить его в код бота exmo? Или вы поможете мне это сделать, если я свой код сюда напишу?
20.12.2017 19:12
Нет, другого параметра нет, код для точки входа (анализ MACD) по сути один и тот же, оформлен чуть-чуть по другому только.
21.12.2017 01:31
ДА так и есть, только там логика продажи другая: ордер на продажу не создается, пока идет рост по macd, перенес код из битрикса в эксмо, сейчас тестирую.
21.12.2017 07:19
Подскажите пожалуйста, где скачать ta-lib?
Скачал две версии. Одна при установке пишет, что не та платформа (Виндоус 10).
Другая, которую нужно поместить C:\ta-lib, не содержит папки Python. Или она там не нужна?
21.12.2017 10:37
Папки python там не должно быть, более подробная инструкция тут - https://bablofil.ru/python-indicators/
И еще посмотрите там комментарии, есть полезная инфа
21.12.2017 11:28
Запускаю pip install xxxxxxxxxxx.whl
Все whl файлы вот такое сообщение выдают
TA_Lib-0.4.10-cp27-cp27m-win32.whl is not a supported wheel on this platform.
21.12.2017 14:06
pip3 install ta-lib
22.12.2017 16:55
TA_Lib-0.4.10-cp27-cp27m-win32.whl  означает:
cp27 -