Пишем торгового робота для биржи 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 - для Питона версии 2.7
win32 - для 32-разрядной системы

У вас, как я понимаю по ошибкам, система 64х разрядная, и питон нужен ветки 3.6, так что вам подойдет файл TA_Lib0.4.10cp36cp36mwin_amd64.whl
Тем не менее у вас питон 3.5 насколько я вижу, так что нужен файл
TA_Lib0.4.10cp35cp35mwin_amd64.whl

Но лучше установить питон последней версии, поставив все галочки, и еще при установке выбрать Advanced и там поставить большинство галочек...
21.12.2017 20:22
Тоже ошибку выдает
build\lib.win-amd64-3.5\talib\common.cp35-win_amd64.pyd : fatal error LNK1120: 5 unresolved externals
    error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\x86_amd64\\link.exe' failed with exit status 1120

    ----------------------------------------
Command "c:\users\borodad\appdata\local\programs\python\python35\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\borodad\\AppData\\Local\\Temp\\pip-build-zfk5hbnr\\ta-lib\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\borodad\AppData\Local\Temp\pip-dpmb6_6j-record\install-record.txt --single-version-externally-managed --compile" failed with error code 1 in C:\Users\borodad\AppData\Local\Temp\pip-build-zfk5hbnr\ta-lib\
22.12.2017 23:34
Ура! TA_Lib0.4.10cp35cp35mwin_amd64.whl встал. Большое спасибо!
22.12.2017 11:24
попробуйте пройти по этой ссылке и запустить файл в консоли там выдаст ошибку... C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\x86_amd64\\link.exe
21.12.2017 16:03
Было бы круто прикрутить еще какой-нибудь индикатор типа RSI.
PS: портировал бот от битрикса на эксмо, торгуется по всем парам. Но хочется чтобы быстрее реагировал.
22.12.2017 11:37
а можно глянут на портированный кусок кода?
22.12.2017 16:00
Можно посмотреть код?
22.12.2017 17:21
# Список пар, на которые торгуем
MARKETS = [
    'BTC_USD', 'BCH_USD', 'ETC_USD','ETH_USD',
    'XRP_USD', 'LTC_USD', 'ZEC_USD', 'XMR_USD', 'DASH_USD'
]

CAN_SPEND = 15 # Сколько USD готовы вложить в бай
MARKUP = 0.001 # 0.001 = 0.1% - Какой навар со сделки хотим получать

STOCK_FEE = 0.002 # Какую комиссию берет биржа
PERIOD = 5 # Период в минутах для построения свечей
ORDER_LIFE_TIME = 0.5 # Через сколько минут отменять неисполненный ордер на покупку 0.5 = 30 сек.

USE_MACD = True # True - оценивать тренд по MACD, False - покупать и продавать невзирая ни на что

BEAR_PERC = 70  # % что считаем поворотом при медведе (подробности - https://bablofil.ru/macd-python-stock-bot/
BULL_PERC = 99.5  # % что считаем поворотом при быке

#BEAR_PERC = 70  # % что считаем поворотом при медведе
#BULL_PERC = 100  # Так он будет продавать по минималке, как только курс пойдет вверх

API_URL = 'api.exmo.me'
API_VERSION = 'v1'

USE_LOG = False
DEBUG = False # True - выводить отладочную информацию, False - писать как можно меньше

numpy.seterr(all='ignore')



curr_pair = None

# Свой класс исключений
class ScriptError(Exception):
    pass
class ScriptQuitCondition(Exception):
    pass
    
# все обращения к 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=90)
    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 get_ticks(pair):
    resource = requests.get('https://api.exmo.me/v1/trades/?pair=%s&limit=10000' % pair)
    data = json.loads(resource.text)
    
    chart_data = {} # сформируем словарь с ценой закрытия по 5 минут
    for item in reversed(data[pair]):
        d = int(float(item['date'])/(PERIOD*60))*(PERIOD*60) # Округляем время сделки до PERIOD минут
        chart_data[d] = float(item['price']) 
    return chart_data

# С помощью MACD делаем вывод о целесообразности торговли в данный момент (https://bablofil.ru/macd-python-stock-bot/)
def get_macd_advice(chart_data):   
    
    macd, macdsignal, macdhist = talib.MACD(numpy.asarray([chart_data[item] for item in sorted(chart_data)]), fastperiod=12, slowperiod=26, signalperiod=9)
    
    idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0
    inters = []

    for offset, elem in enumerate(macd):
        if offset in idx:
            inters.append(elem)
        else:
            inters.append(numpy.nan)
    trand = 'BULL' if macd[-1] > macdsignal[-1] else 'BEAR'
    hist_data = []
    max_v = 0
    growing = False
    for offset, elem in enumerate(macdhist):
        growing = False        
        curr_v = macd[offset] - macdsignal[offset]
        if abs(curr_v) > abs(max_v):
            max_v = curr_v
        perc = curr_v/max_v
        
        if       (   (macd[offset] > macdsignal[offset] and perc*100 > BULL_PERC) # восходящий тренд
                     or      (
                                 macd[offset] < macdsignal[offset] and perc*100 < (100-BEAR_PERC)
                            )

                ):
            v = 1
            growing = True
        else:
            v = 0
            
        if offset in idx and not numpy.isnan(elem):
            # тренд изменился
            max_v = curr_v = 0 # обнуляем пик спреда между линиями
        hist_data.append(v*1000)
 
    return ({'trand':trand, 'growing':growing})

# Выводит всякую информацию на экран, самое важное скидывает в Файл log.txt
def log(*args):
    
    if USE_LOG:
        l = open("./log.txt", 'a', encoding='utf-8')
        print(datetime.now(), *args, file=l)
        l.close()
    print(datetime.now(),' ', *args)

# Ф-ция для создания ордера на покупку 
def create_buy(pair):
    global USE_LOG
    USE_LOG = True
    log(pair, 'Создаем ордер на покупку')
    log(pair, 'Получаем текущие курсы')
    
    offers = call_api('order_book', pair=pair)[pair]
    try:
        #current_rate =  float(offers['ask'][0][0]) # покупка по лучшей цене
        current_rate = sum([float(item[0]) for item in offers['ask'][:3]])/3 # покупка по средней цене из трех лучших в стакане
        can_buy = CAN_SPEND/current_rate
        print('buy', can_buy, current_rate)                            
        log(pair, """
            Текущая цена - %0.8f
            На сумму %0.8f %s можно купить %0.8f %s
            Создаю ордер на покупку
            """ % (current_rate, CAN_SPEND, pair[0], can_buy, pair[1])
        )       
        new_order = call_api(
            'order_create',
            pair = pair,
            quantity = can_buy,
            price = current_rate,
            type = 'buy'
            )                
        log("Создан ордер на покупку %s" % new_order['order_id'] )
    except ZeroDivisionError:
        print('Не удается вычислить цену', prices)
    USE_LOG = False    
    
# Ф-ция для создания ордера на продажу
def create_sell(pair):
    global USE_LOG
    USE_LOG = True
    balances = call_api('user_info')['balances']
    #if float(balances[pair[:-4]]) >= CURRENCY_1_MIN_QUANTITY: # Есть ли в наличии CURRENCY_1, которую можно продать?
    wanna_get = CAN_SPEND + CAN_SPEND * (STOCK_FEE + MARKUP)
    order_amount = float(balances[pair[:-4]])
    new_rate = wanna_get/order_amount
    new_rate_fee = new_rate/(1-STOCK_FEE)   
    offers = call_api('order_book', pair=pair)[pair]       
    current_rate = float(offers['bid'][0][0]) # Берем верхнюю цену, по которой кто-то покупает
    choosen_rate = current_rate if current_rate > new_rate_fee else new_rate_fee        
    print('sell', balances[pair[:-4]], wanna_get, choosen_rate)
    log(pair, """
    Итого на этот ордер было потрачено %0.8f %s, получено %0.8f %s
    Что бы выйти в плюс, необходимо продать купленную валюту по курсу %0.8f
    Тогда, после вычета комиссии %0.4f останется сумма %0.8f %s
    Итоговая прибыль составит %0.8f %s
    Текущий курс продажи %0.8f
    Создаю ордер на продажу по курсу %0.8f
    """
    % (
        wanna_get, pair[0], order_amount, pair[1],
        new_rate_fee,
        STOCK_FEE, (new_rate_fee*order_amount - new_rate_fee * order_amount * STOCK_FEE), pair[0],
        (new_rate_fee*order_amount - new_rate_fee*order_amount * STOCK_FEE)-wanna_get, pair[0],
        current_rate,
        choosen_rate,
        )
    )
    new_order = call_api(
        'order_create',
        pair=pair,
        quantity = balances[pair[:-4]],
        price= choosen_rate,
        type='sell'
    )
    log(pair, "Создан ордер на продажу %s" % new_order['order_id'])
    print(new_order)
    if DEBUG:
        print('Создан ордер на продажу', pair[:-4], new_order['order_id']) 
    USE_LOG = False

# Бесконечный цикл процесса - основная логика
while True:
    try:
        for pair in MARKETS: # Проходим по каждой паре из списка в начале            
            try:
            # Получаем список активных ордеров
                try:
                    opened_orders = call_api('user_open_orders')[pair]
                except KeyError:
                    if DEBUG:
                        print('Открытых ордеров нет')
                        log(pair, "Открытых ордеров нет")    
                    opened_orders = []
                sell_orders = []
                # Есть ли неисполненные ордера на продажу CURRENCY_1?
                log(pair, " Обработка...")
                for order in opened_orders:
                    if order['type'] == 'sell':
                        # Есть неисполненные ордера на продажу CURRENCY_1, выход
                    #raise ScriptQuitCondition('Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)')
                    # пропуск продажи
                        pass
                    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:
                                    log('Пора отменять ордер %s' % order)
                                    # Ордер уже давно висит, никому не нужен, отменяем
                                    call_api('order_cancel', order_id=order['order_id'])  
                                    log('Ордер %s отменен' % order)
                                    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']
                    min_quantity = call_api('pair_settings',pair=pair)[pair]
                    CURRENCY_1_MIN_QUANTITY = float(min_quantity['min_quantity'])
                    if float(balances[pair[:-4]]) >= CURRENCY_1_MIN_QUANTITY: # Есть ли в наличии CURRENCY_1, которую можно продать? 
                        print('Баланс: '+str(float(balances[pair[:-4]]))+' '+str(pair[:-4]))
                        if USE_MACD:
                                macd_advice = get_macd_advice(chart_data=get_ticks(pair)) # проверяем, можно ли создать sell
                                if macd_advice['trand'] == 'BEAR' or (macd_advice['trand'] == 'BULL' and macd_advice['growing']):
                                    print('Продавать нельзя, т.к. ситуация на рынке неподходящая: Трэнд '+str(macd_advice['trand'])+'; Рост '+str(macd_advice['growing']))
                                    #log(pair, 'Для ордера %s не создаем ордер на продажу, т.к. ситуация на рынке неподходящая' % order['oreder_id'] )
                                else:
                                    print('Выставляем ордер на продажу, т.к ситуация подходящая: '+str(macd_advice['trand'])+' '+str(macd_advice['growing']))
                                    log(pair, "Для выполненного ордера на покупку выставляем ордер на продажу")
                                    create_sell(pair=pair)
                        else: # создаем sell если тенденция рынка позволяет
                            log(pair, "Для выполненного ордера на покупку выставляем ордер на продажу")
                            create_sell(pair=pair)
                    else:                    
                        if float(balances[pair[-3:]]) >= CAN_SPEND: 
                            #log(pair, "Неисполненных ордеров нет, пора ли создать новый?")
                            # Проверяем MACD, если рынок в нужном состоянии, выставляем ордер на покупку
                            if USE_MACD:
                                macd_advice = get_macd_advice(chart_data=get_ticks(pair))
                                if macd_advice['trand'] == 'BEAR' and macd_advice['growing']:
                                    log(pair, "Создаем ордер на покупку")
                                    create_buy(pair=pair)
                                else:
                                    log(pair, "Условия рынка не подходят для торговли", macd_advice)
                            else:
                                log(pair, "Создаем ордер на покупку")
                                create_buy(pair=pair)
                        else:
                            raise ScriptQuitCondition('Не хватает денег для торговли: баланс ' + str(round(float(balances[pair[-3:]]))) + ' ' + str(pair[-3:]))
            except ScriptError as e:
                    print(e)
            except ScriptQuitCondition as e:
                print(e)
            except Exception as e:
                print("!!!!",e)
        time.sleep(1)
    except Exception as e:
        print(e)

Спасибо за исходники, без них даже бы не пытался что-то сделать.
Код без шапки, проверяем, могут быть скрытые баги. Создание логов лучше не включать... цена продажи с ним бывает без учета комиссии (бот может торгануть в минус).
Бот торгует только USD!
Логика: бот смотрит на кривые macd, если идет медвежий тренд и резкий разворот, то покупает, пока идет рост и тренд перешел в бычий бот не продает. Если опять произошел разворот, бот ставит ордер на продажу по самой верхней цене в стакане, причем не прибавляет комиссию, если плюс перекрывает комиссию, чтобы шансов на продажу ордера было больше, если наоборот то ордер ставится с учетом комиссии.
+ Исправил неправильные расчеты комиссии в изначальном коде бота битрикса, ИМХО.
+ Увеличена чувствительность поворота при "быке".
+ Есть выбор периода для построения графика.
+ Покупка идет по средней цене из трех наименьших цен в стакане.
+ Торговля по всем парам в массиве Markets, по порядку.
+ Добавил запрос минимальной  суммы ставки с exmo по текущей паре.
В планах добавить еще какой-нибудь индикатор.

Пишите свои замечания, вместе мы сделаем идеального бота!!!
22.12.2017 17:27
Забыл добавить!!!! Бот не ждет исполнения ордера на продажу по купленной паре, пока на счету есть USD и условия подходящие для покупки другой криптовалюты, он идет торговать дальше.
07.01.2018 12:05
Stepan, Большое спасибо за интересное дополнение к боту! Однако создается ощущение, что при покупке валюты создается ощущение, что оно все же проходит по очень высокому курсу. Через пару секунд проверяю - он уже существенно меньше, и в итоге долго приходится ждать для продажи. Подскажите, пожалуйста, а можно в вашем боте курс покупки как-то задать, как минимальный за последние N минут? Сам, к сожалению, в программировании ничего не понимаю толком.
08.02.2018 17:13
Добрый вечер Ошибка здесь numpy.seterr(all='ignore')
08.02.2018 17:31
ура пошло!
09.02.2018 07:04
У меня на  счету 4,91 д. Вписываю в скрипт. Могу вложить 4 (или 2,3) . При запуске ответ скрипта по любой паре "!!!! name 'requests' is not defined". Если вписываю больше 5 (больше вложенной суммы, то ответ по русски Недостаточно средств на счету. Как сделать так, чтоб запустилось с моей вложенной суммой?
23.12.2017 10:33
Я тоже решил вступить в секту свидетелей Биткоина. Начал ковырять уголк никрофила - в ящиками со старыми жесткими дисками, которые остались из прошлого - занимался ремонтом дисков и восстановлением информации.... Нашел затаренные 200 баксов. Вот такой мой первый опыт добычи биткоина.

Всем здрасьте :)
И спасибо за скрипты, начинаю разбираться.
23.12.2017 10:35
Вопрос, какую нагрузку дает скрипт на питоне на VDS? VDS имеется с моими сайтами и сайтами клиентов, хотелось бы, после того, как отлажу скрипт, поставить именно туда.
Спасибо!
24.12.2017 07:10
Конкретно этот - в единицу времени потребляет около 15Мб оперативки, 0.5% времени ядра. На хостинге за 5$ от DigitalOcean прекрасно себя чувствует
23.12.2017 10:57
Stepan ., при запуске скрипта он ругается
Traceback (most recent call last):
  File "D:\Python\exmo-from-stepan.py", line 54, in <module>
    numpy.seterr(all='ignore') 
NameError: name 'numpy' is not defined

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

Шапку естетсвоенно добавил

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

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

Что может быть?</module>
23.12.2017 11:15
import time
import json
import requests
import urllib, http.client
import hmac, hashlib

import numpy 
import talib 

from datetime import datetime

# ключи API, которые предоставила exmo
API_KEY = 'K-32a62....'
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b'S-10f7...'
23.12.2017 12:34
вот оно что, numpy установить нужно, спасибо, придется еще разбираться
23.12.2017 16:07
ага, возникли проблемы с установкой талиба, но разобрался

Талиба берем здесь https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib качаем, кидаем в папку, и при установке указываем путь к нему

python -m pip install e:\python\TA_Lib-0.4.10-cp36-cp36m-win_amd64.whl
23.12.2017 11:12
Еще. Пробовал оригинальный скрипт, почему то если падение валюты, он ставит завышенную цену, и все... она зависает. через 3 минуты ничего не отменяется.

Пока с алгоритмами не разобрался, да и в питона первый раз вижу,
Но мысль такая - почему нам не использовать за базу встречные ордера на покупку/продажу
смотрим, максимальный ордер - хватаем его... конечно же учитывать при покупке/продаже комисию биржи и какой то процент прибыли... будет мало - но наверняка
или баян баянистый?
23.12.2017 11:17
потому что оригинальный скрипт в 90% предсказать падение не может, поэтому покупает на верху
23.12.2017 15:55
>она зависает. через 3 минуты ничего не отменяется.

уберите время смещения с сервером
23.12.2017 11:51
Добавил вывод информации об активных ордерах 
заменить часть прошлого кода этим
else: # Открытых ордеров нет
                    balances = call_api('user_info')['balances']
                    reserved = call_api('user_info')['reserved']
                    min_quantityy = call_api('pair_settings',pair=pair)[pair]
                    CURRENCY_1_MIN_QUANTITY = float(min_quantityy['min_quantity'])                    
                    if float(balances[pair[:-4]]) >= CURRENCY_1_MIN_QUANTITY: # Есть ли в наличии CURRENCY_1, которую можно продать? 
                        print('Баланс: '+str(float(balances[pair[:-4]]))+' '+str(pair[:-4]))
                        if USE_MACD:
                                macd_advice = get_macd_advice(chart_data=get_ticks(pair)) # проверяем, можно ли создать sell
                                if macd_advice['trand'] == 'BEAR' or (macd_advice['trand'] == 'BULL' and macd_advice['growing']):
                                    print('Продавать нельзя, т.к. ситуация на рынке неподходящая: Трэнд '+str(macd_advice['trand'])+'; Рост '+str(macd_advice['growing']))
                                    #log(pair, 'Для ордера %s не создаем ордер на продажу, т.к. ситуация на рынке неподходящая' % order['oreder_id'] )
                                else:
                                    print('Выставляем ордер на продажу, т.к ситуация подходящая: '+str(macd_advice['trand'])+' '+str(macd_advice['growing']))
                                    log(pair, "Для выполненного ордера на покупку выставляем ордер на продажу")
                                    create_sell(pair=pair)
                        else: # создаем sell если тенденция рынка позволяет
                            log(pair, "Для выполненного ордера на покупку выставляем ордер на продажу")
                            create_sell(pair=pair)
                    else:                    
                        if float(balances[pair[-3:]]) >= CAN_SPEND: 
                            #log(pair, "Неисполненных ордеров нет, пора ли создать новый?")
                            # Проверяем MACD, если рынок в нужном состоянии, выставляем ордер на покупку
                            if USE_MACD:
                                macd_advice = get_macd_advice(chart_data=get_ticks(pair))
                                if macd_advice['trand'] == 'BEAR' and macd_advice['growing']:
                                    log(pair, "Создаем ордер на покупку")
                                    create_buy(pair=pair)
                                else:
                                    log(pair, "Условия рынка не подходят для торговли", macd_advice)
                            else:
                                log(pair, "Создаем ордер на покупку")
                                create_buy(pair=pair)
                        else:
                            order = str(' В ордере :' + str(float(reserved[pair[:-4]])) + '. ' + str(pair[:-4])) if float(reserved[pair[:-4]]) > 0.0 else ''
                            raise ScriptQuitCondition('Не хватает денег для торговли: баланс ' + str(round(float(balances[pair[-3:]]))) + ' ' + str(pair[-3:]) + order)
23.12.2017 17:00
Пробую и с этим дополнением и без...
И вверх курс идет и в низ

постоянно получаю
Открытых ордеров нет
2017-12-23 22:55:35.551364 BTC_USD Открытых ордеров нет
2017-12-23 22:55:35.562107 BTC_USD Обработка...
Открытых ордеров нет

Что в начале должно на счету быть? BTC или USD ? у меня USD сейчас
Или при запуске BTC должны быть?
23.12.2017 17:00
Пробую и с этим дополнением и без...
И вверх курс идет и в низ

постоянно получаю
Открытых ордеров нет
2017-12-23 22:55:35.551364 BTC_USD Открытых ордеров нет
2017-12-23 22:55:35.562107 BTC_USD Обработка...
Открытых ордеров нет

Что в начале должно на счету быть? BTC или USD ? у меня USD сейчас
Или при запуске BTC должны быть?
23.12.2017 17:57
пишется пара по которой цикл работает... BTC_USD, бот расплачивается USD, задайте сумму для операций CAN_SPEND = 15 (15$)
если есть ордера он так и напишет, если нет ордеров и денег на счету (USD) идет дальше по другим парам
23.12.2017 18:25
Что то запутался, деньги сейчас и на BTC и на USD, и так и по другому хватить должно
Без Вашего дополнения пробую, все равно пишет "Открытых ордеров нет", и все. Хоть убейся. Ничего больше не делает!
Ордера обязательно должны быть? Какие вообще условия старта?

Пробую с дополнением, замучился с ошибками "unexpected indent" и "unindent does not match any outer indentation level"

Как я понял это связано с отступами. Может Вы выложите целый рабочий код, чтобы с отступами все правильно было? 
Большое спасибо!
23.12.2017 18:47
https://www.dropbox.com/s/iudrm1fwijxgnxd/exmo_many_pairs.py?dl=0
23.12.2017 19:28
Сделал побайтное сравнение, вижу ошибку. Скрипт зашуршал. Спасибо !
23.12.2017 20:34
Оставил для пробы 4 еденицы
MARKETS = [
'BTC_USD', 'BCH_USD',
'ETC_USD', 'ETH_USD',
]

Вижу по графикам, что курсы валюты поднимаются, но неизменно скрипт пишет, что условия рынка не подходят для торговли...
что можно подкрутить?

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

Биржа Exmo присутствует. Можно для каждой биржи указать ключь API, тогда можно далать ордера прям из телефона, и получать оповещания по ордерам..

Но одновременно со скриптом один и тот же ключ к сожалению использовать нельзя. В документации написано, что можно в поддержке запросить второй АПИ ключ

Но даже и без подключения АПИ удобно мониторить курсы валют и бирж
23.12.2017 20:50
Поставил USE_MACD = False  и скрипт весело заторговал без MACD 
что то как то нужно с настройками делать

Еще, мне кажется что навар MARKUP = 0.001 нужно для каждой валюты свой делать.
Для BTC_USD он сильно большой ставит, и ордер долго висит, тогда как остальные пары работают
24.12.2017 03:46
крутите чувствительность BEAR
23.12.2017 20:53
и кстати, мне кажется что вот это условие ORDER_LIFE_TIME = 0.5 не выполняется.
скрипт не отменяет ордера. Или это тоже из за часового пояса? здесь тоже нужно что то думать
24.12.2017 05:11
30 секунд, все выполняется если время с биржей совпадает.
24.12.2017 06:03
Как это проверить?
Я так понимаю, нужно добавить STOCK_TIME_OFFSET, внутри кода он присутствует, в настройках нету
У меня разница с временем сервера 6 часов
Тоесть, время сервера - 06:02, у меня 12:02
сколько должно быть в STOCK_TIME_OFFSET ?

Спасибо!
24.12.2017 06:50
Сотрите счетчик отмены ордера, должно тикать 1.0 2.0 3.0 ... (это секунды) как дойдет до 30 так отменит, если другие числа делите на 3600 поймете разница какая часовая.
24.12.2017 07:01
в том то и дело, что счетчика и в помине нету
24.12.2017 07:02
и соответственно ничего не отменяется... что то не так у меня
23.12.2017 22:24
Подскажите что делаю не так? уже пересмотрел все и все равно выдает ошибку синтаксиса.

Python 3.6.4 (v3.6.4 d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>>
import urllib, http.client
import time
import json
import hmac, hashlib

API_KEY = 'прописан ключ'
API_SECRET = b'прописан ключ'

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

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 = 0.00019649 # Сколько тратить 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 '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=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: # мы можем купить слишком мало на нашу сумму
                            raise 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)
23.12.2017 22:26
причем выделяет цифру 6 в номере программы красным цветом!
24.12.2017 07:13
File->New file->Save->F5
24.12.2017 07:51
Это в стандартном редакторе питона? Ато я тоже мучился, пока все нашел
24.12.2017 21:19
Stepan ., по Вашему коду,
> + Добавил запрос минимальной суммы ставки с exmo по текущей паре.

Может имеет смысл минимальные суммы для каждой валюты руками прописать? Ведь они почти не меняются! Это позволит уменьшить количество запросов к API, которое хоть и большое но ограниченное.

Ну и как я и писал, может имеет смысл сделать навар ( MARKUP ) отдельно для каждой валюты?
Ведь например, у BTC в отличии от других валют курс к доллару намного больше. Сделав для каждой валюты свой навар, мы могли бы уменьшить риски пролета для валют с большим курсом...

Ну и CAN_SPEND лучше бы сделать отдельно для каждой валюты. Было бы для экспериментов с небольшими суммами удобнее

Что нибудь еще нового сделали ? :)

Эх, был бы код на Perl :)
25.12.2017 09:17
>> Эх, был бы код на Perl :)
Так вперед :)
25.12.2017 09:56
Увы не разработчик. Хоть с перлом раньше возился, делал скрипты по поиску свободных доменов с ПР и ТИЦ,
Да и первый сайт на перле был еще в 1998 году :)

Сейчас не потяну переделывать

Вопрос такой, не пойму лили баян или что...

Что если для торговли за базу брать готовые, существующие ордера на покупку продажу? Сейчас считаю, вроде с учетом комисии биржи доля малая все равно есть... Мало но есть. Зато гарантировано сечет волны... или в чем то ошибаюсь?


25.12.2017 10:01
И второе, хоть убей не отменяет зависшие ордера, не показывает время до конца ордера вообще.

К примеру время биржи 10:00, мое время - 16:00, разница 6 часов. Ставлю -6, но ничего не происходит.
25.12.2017 10:32
ставте 0
25.12.2017 10:39
По разному ставлю, и 0, ничего не вижу. Не отменяет поставленные ордера
25.12.2017 13:43
Блииинн... получается что отменяются только ордера buy, а shell не отменяются? Так?
26.12.2017 06:08
да, sell не отменяется, смысл его отменять если при другой цене вы получите убыток?
27.12.2017 07:49
Ни у кого сегодня глюков нет?
У меня через раз !!!! [WinError 10060] Попытка установить соединение была безуспешной, т.к. от другого компьютера за требуемое время не получен нужный отклик, или было разорвано уже установленное соединение из-за неверного отклика уже подключенного компьютера

то пытается купить, то говорит денег нет, хотя на балансе большая сумма чем указано, то опять лезет ошибка WinError 10060

Хотя при доступе из браузера например к https://api.exmo.me/v1/order_book/?pair=BTC_USD&limit=1 ошибки нет, постоянно открывается...
27.12.2017 07:50
думается ли АПИ шалит, или провайдер...
27.12.2017 07:50
думается ли АПИ шалит, или провайдер...
27.12.2017 08:41
Добрый день. Подскажите как сделать так чтобы зависшие ордера на продажу отменялись скажем через час и продавались по текущей цене?
Я понимаю что такая торговля будет в минус... но все же как это сделать?
27.12.2017 22:02
Добрый день, подскажите, пожалуйста, что не так: запустил скрипт, поменял пару на BTC/UAH он работает без ошибок:
buy 0.00022904723409398076 436591.1703564551
buy 0.00022904723409398076 436591.1703564551
и тд.
но я не вижу в активных ордерах на сайт чтоб создавались ордера на покупку, так и должно быть?
28.12.2017 07:29
разобрался))
28.12.2017 11:44
Как думаете, что лучше увеличение к-ва торгуемых пар или увеличение ставки на одной паре?
30.12.2017 14:48
Когда как )
29.12.2017 05:11
Такое впечатление, что бан поймал

!!!! HTTPSConnectionPool(host='api.exmo.me', port=443): Max retries exceeded with url: /v1/trades/?pair=BTC_USD&limit=10000 (Caused by NewConnectionError('<urllib3.connection.verifiedhttpsconnection 0x000001edb8766cf8="" at="" object="">: Failed to establish a new connection: [WinError 10060] Попытка установить соединение была безуспешной, т.к. от другого компьютера за требуемое время не получен нужный отклик, или было разорвано уже установленное соединение из-за неверного отклика уже подключенного компьютера',))
Выход, по MACD рынок падает
!!!! [WinError 10060] Попытка установить соединение была безуспешной, т.к. от другого компьютера за требуемое время не получен нужный отклик, или было разорвано уже установленное соединение из-за неверного отклика уже подключенного компьютера


Все же не льзя наверное двух ботов параллельно пускать. 
Имеется ли у кого способ снятия порчи? :)
Ключ API менял, пробовал вместо HTTPS ставить HTTP, не помогает

В то же время доступ из браузера к запросу https://api.exmo.me/v1/trades/?pair=BTC_USD&limit=10000 вполне выполняется

А как юзер агента задать в питоне? и как правильно вставить в скрипт? чтобы на ихнем конце провода думали что запрос из браузера</urllib3.connection.verifiedhttpsconnection>
30.12.2017 14:53
Как то так

headers = requests.utils.default_headers()
headers.update(
    {
        'User-Agent': '....',
    }
)
response = requests.get(url, headers=headers)
29.12.2017 05:16
Еще https://api.exmo.me/v1/trades/?pair=BTC_USD&limit;=10000

Это 10000 строк, мегабайт с хвостом, который постоянно обновляется.
Не много ли? Имеет ли смысл может уменьшить?
29.12.2017 07:30
Добрый день!С наступающим новым годом Вас!Можно запустить бота на двух биржах одновременно?На EXMO и YOBIT!
30.12.2017 15:01
И вас тоже!)
Конечно, почему нет.
Просто придется запускать через командную строку
открываете cmd, пишете python путь_к_боту_1.py
открываете еще одно cmd, пишете python путь_к_боту_2.py

31.12.2017 22:47
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> 
 RESTART: C:/Users/Олег/AppData/Local/Programs/Python/Python36-32/exmo_macd.py 
Traceback (most recent call last):
  File "C:/Users/Олег/AppData/Local/Programs/Python/Python36-32/exmo_macd.py", line 1, in <module>
    import numpy
ModuleNotFoundError: No module named 'numpy'
>>> что делать с этим</module>
01.01.2018 10:32
Нужно установить модули.
Вот тут пошагово расписано
https://bablofil.ru/python-indicators/
01.01.2018 11:37
я не пойму что я не правильно делаю!
01.01.2018 11:45
вот что у меня получается в командной строке Microsoft Windows [Version 6.3.9600]
(c) Корпорация Майкрософт (Microsoft Corporation), 2013. Все права защищены.

C:\Users\Олег>pip install ta-lib
Collecting ta-lib
  Using cached TA-Lib-0.4.10.tar.gz
Installing collected packages: ta-lib
  Running setup.py install for ta-lib ... error
    Complete output from command c:\users\олег\appdata\local\programs\python\pyt
hon36-32\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\08A4
~1\\AppData\\Local\\Temp\\pip-build-06zhz5bk\\ta-lib\\setup.py';f=getattr(tokeni
ze, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(c
ompile(code, __file__, 'exec'))" install --record C:\Users\08A4~1\AppData\Local\
Temp\pip-1sysdjhx-record\install-record.txt --single-version-externally-managed
--compile:
    running install
    running build
    running build_py
    creating build
    creating build\lib.win32-3.6
    creating build\lib.win32-3.6\talib
    copying talib\deprecated.py -> build\lib.win32-3.6\talib
    copying talib\test_abstract.py -> build\lib.win32-3.6\talib
    copying talib\test_data.py -> build\lib.win32-3.6\talib
    copying talib\test_func.py -> build\lib.win32-3.6\talib
    copying talib\test_stream.py -> build\lib.win32-3.6\talib
    copying talib\__init__.py -> build\lib.win32-3.6\talib
    running build_ext
    building 'talib.common' extension
    error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual
C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools

    ----------------------------------------
Command "c:\users\олег\appdata\local\programs\python\python36-32\python.exe -u -
c "import setuptools, tokenize;__file__='C:\\Users\\08A4~1\\AppData\\Local\\Temp
\\pip-build-06zhz5bk\\ta-lib\\setup.py';f=getattr(tokenize, 'open', open)(__file
__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, '
exec'))" install --record C:\Users\08A4~1\AppData\Local\Temp\pip-1sysdjhx-record
\install-record.txt --single-version-externally-managed --compile" failed with e
rror code 1 in C:\Users\08A4~1\AppData\Local\Temp\pip-build-06zhz5bk\ta-lib\

C:\Users\Олег>
01.01.2018 13:39
Скачайте со страницы  http://www.lfd.uci.edu/%7Egohlke/pythonlibs/ нужный whl файл (у меня это TA_Lib0.4.10cp36cp36mwin_amd64.whl) 

Откройте cmd

напишите pip install полный_путь_к_скачанному_файлу

После этого запускайте бота
02.01.2018 21:20
здравствуйте андрей!скачал я этот файл TA_Lib0.4.10cp36cp36mwin_amd64.whl)  что с ним дальше делать кроме того что открыть в cmd?ни как не могу запустить бот!
02.01.2018 21:34
вот что у меня получается  RESTART: C:/Users/Олег/AppData/Local/Programs/Python/Python36-32/exmo_macd (1).py 
Traceback (most recent call last):
  File "C:/Users/Олег/AppData/Local/Programs/Python/Python36-32/exmo_macd (1).py", line 9, in <module>
    import talib
ModuleNotFoundError: No module named 'talib'</module>
03.01.2018 06:47
Во первых, нужно его установить 
pip install TA_Lib0.4.10cp36cp36mwin_amd64.whl
При установке внимательно читать что пишется, нужно убедиться что он у вас установился.
Если он установился, но не работает, то отдельно еще выполните команду
pip install ta-lib
29.12.2017 22:26
что может быть не так? сгенерировал ключи, вставил, выдало error 40017 wrong api key
30.12.2017 15:03
Местами перепутали?
30.12.2017 17:11
местами не путал, пробовал и так и сяк и с кавычками и без, и букву б убирал, и ключи другие генерировал, без толку
31.12.2017 11:30
Спасибо! Работает просто заглядение :)
Для изучения самое то. Респект программисту!
01.01.2018 10:59
а мне кто нибудь поможет?не запускается бот вот что пишет!            Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> 
 RESTART: C:/Users/Олег/AppData/Local/Programs/Python/Python36-32/exmo_macd.py 
Traceback (most recent call last):
  File "C:/Users/Олег/AppData/Local/Programs/Python/Python36-32/exmo_macd.py", line 1, in <module>
    import numpy
ModuleNotFoundError: No module named 'numpy'
>>> что делать с этим</module>
01.01.2018 15:22
PROFIT_MARKUP

Кто сколько ставит навара себе с сделки? 0.1% так и оставляете?
03.01.2018 17:20
Где взять самую свежую версию бота ??
03.01.2018 19:33
# Тонкая настройка
CURRENCY_1 = 'XRP' 
CURRENCY_2 = 'RUB'

CURRENCY_1_MIN_QUANTITY = 15 # минимальная сумма ставки - берется из 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 = 3000 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1
PROFIT_MARKUP = 0.001 # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
DEBUG = True # True - выводить отладочную информацию, False - писать как можно меньше

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

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

========================================================================================
денег на счету нет ответ получаю

Открытых ордеров нет
Выход, не хватает денег
Открытых ордеров нет
Выход, не хватает денег
Открытых ордеров нет
...
с деньгами понятно, ордеров нет из-за неправильного смещения времени??

и второй вопрос:

CURRENCY_1_MIN_QUANTITY = 15 
и
CAN_SPEND = 3000         должны быть связаны через текущий курс??  CURRENCY_1_MIN_QUANTITY = 15 - это же минимальное количество покупаемой валюты и если ее средняя стоимость * 15 будет больше 3000, то купить ничего не получится??
04.01.2018 06:35
Просто нет открытых ордеров (вами), видимо потому что нет денег.
CURRENCY_1_MIN_QUANTITY устанавливает биржа (https://api.exmo.com/v1/pair_settings/), это объем, ниже которого вам просто не дадут сделать ставку. Они сами привязывают к курсу. 
Взять BTC_RUB

"BTC_RUB":{"min_quantity":"0.001","max_quantity":"100","min_price":"1","max_price":"2000000","max_amount":"12000000","min_amount":"10"}
Вам не дадут сыграть, если BTC меньше чем min_quantity либо рублей меньше чем min_amount. Это касается и вашей изначальной суммы, с которой входите в торги, и итоговой, которая получится в результате перемножения
04.01.2018 11:01
Спасибо, Андрей, теперь вроде порядок
05.01.2018 05:59
Приветы, кто-нить сравнивал производительность/качество ботов с MACD и ver.1 ??
05.01.2018 19:11
люди добрые помогите установить бота по шагово что надо делать правильно!выходит ошибка и всё тут!первый бот установился нормально а бот MACD не могу установить!
05.01.2018 22:06
Попробовал запустить бота на андроид-смартфоне. Но при запуске он якобы не может рассчитать среднюю цену, есть ли в таком случае какое-то решение или на смартфоне никак не получится запустить. Использовал программу QPython3, заранее спасибо)
21.01.2018 11:40
Попробуйте с часовыми поясами поиграться
06.01.2018 12:02
ВСЕ ТАКИ ЗАПУСТИЛ Я ЕГО!ТОЛЬКО ВОПРОС КАК ДЕЛИТЬСЯ БАЛАНС НА НЕСКОЛЬКО ПАР К ПРИМЕРУ ETH-BTC,ETH-USD?
06.01.2018 15:41
выше писали, что пары не должны пересекаться, вторая валюта вроде норм, которую торгуешь уникальная должна быть
18.01.2018 10:04
Привет, как решил проблему?
06.01.2018 15:45
module object has no attribute jsondecodeerror - кто знает как решить ??
07.01.2018 13:11
Замените json.decoder.JSONDecodeError на ValueError
06.01.2018 19:41
у меня таких ошибок не было!
07.01.2018 04:44
У меня питон 3.4 максиму на XP встал, возможно из за этого такие ошибки
07.01.2018 08:49
всех с праздником.что мне вписывать если у меня две пары ETH-BTC LTC-USD CAN_SPEND =
12.01.2018 16:35
Создайте два файла, в каждом свои настройки, запускайте параллельно
11.01.2018 07:57
Долго тестировал бота. Всегда почти всегда закупается на хаях при пампе, когда тренд уже пошел вниз. В итоге у меня штук 5 ордеров висит по разным парам и я теперь инвестор.)
Пробовал крутить настройки bull\bear, но точно понять как будут пересекаться линии относительно графика в своей голове сложно, собственно как и будет ли нормально торговать бот. Тестировать мелкими суммами для оптимальной настройки можно тупо месяцами, особенно когда "условия рынка не подходят для торговли". Назрел вопрос: а можно ли как-то визуально на каком-нибудь эмуляторе посмотреть изменчивость настроек bull\bear, что бы наглядно видеть что будет происходить? А то я реально не врубаюсь чем он там руководствуется. Еще долго тестировал при настройках BEAR_PERC = 70 BULL_PERC = 99.5, покупает редко, на все равно закупается на вершине пампа и не может потом ничего продать.
12.01.2018 16:41
Вот тут подробно расписан алгоритм https://bablofil.ru/macd-python-stock-bot/ и есть скрипт, который рисует графики и онлайн говорит - покупать или нет. По сути бот делает то же самое.
Вы можете запустить скрипт, сидеть, смотреть на графики и пересечения, и понимать где бот покупал бы, а где нет.
11.01.2018 11:24
У меня такой вопрос.По какому графику идет торговля?На бирже одна свеча равна 30минут.PERIOD = 5 # Период в минутах для построения свечей Это значение правильно или не имеет значения?
12.01.2018 16:45
Если выставите 5, то ваша свеча будет 5 минут. Если поставить 30, то будет как на бирже.
Правильно или нет, зависит от вашей точки зрения. С одной стороны, свечами по 5 минут вы получаете более тонкий контроль над изменением тренда, и оперативно реагируете на изменения. С другой стороны, чем меньше этот период, тем чаще будет ошибаться индикатор - большинство индикаторов заточены на часовые, дневные и недельные периоды - т.е. средний и долгий срок.
12.01.2018 11:52
Андрей, все же, сколько не тестировал, и тот бот, который работает по MACD, одна проблема, как уже нираз писали выше - бот закупает на макушке графика, и если график в низ, то мы сидим ждем нисчем....

Я думаю все же, бот должен работать по следующему алгоритму:

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

Если спад устаканился, снова торгуем...

Если курс резко начал подниматься, закупаем BTC, и ждем, курим табак. Закупаться так же нужно без оглядки на невыгодность с точки зрения последних торгов, ибо в итоге окажемся в выгоде...

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

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

Заранее спасибо если все же выложите такой бот.
12.01.2018 17:01
Насчет настоящего и прошлого - на днях смотрел, что на самом деле творится в стаканах на эксмо - то, что нам не показывают. Там же покупки и продажи +- от текущей цены, по 200 строк кажется, хотя суммарно предложений намного больше.
Так вот.
В стаканах покупок есть куча оптимистов, которые готовы купить BTC по 100 долларов за штуку, например. Они находятся в конце списка, поэтому вряд ли вы из когда увидите на сайте, хотя можно выцепить через API.
Так же немало оптимистов, желающих продать BTC по 20-30 000 $ при текущей цене в 15 000. Ордера есть, они висят, и могут висеть еще много месяцев.
Если посчитать суммарный объем в долларах, то объем на продажу как правило в два раза больше объемов на покупку, а средневзвешенная цена что там что там расходится процентов на 70 от текущей - каждая в свою сторону. Так что брать из стакана информацию, конечно, можно, а вот доверять ей, учитывая что каждый выставляет ЛЮБУЮ цену, порой оторванную от реальности - думаю, не самая лучшая идея.
Ну а насчет продавать при спаде - имеется в виду продавать с убытком, идти на перезакуп, покупать в расчете на то, что пойдет вверх? А закупать при росте? Это и будет зачастую покупка на пике... В общем не совсем я понял алгоритм (
12.01.2018 17:37
По поводу алгоритма - мне показалось, Вы не поняли о чем я говорю, ну сами посудите - крутится скрипт, крутится, и тут раз на пике купил BTC а график на спад пошел... и все, двое трое суток мы сидим, курим табак, ждем пока курс вырастет или не вырастит... 
Но если в начале спада мы BTC продадим, то останемся в большем выигрыше оставшись с долларом, потому как волны ой какие а до пиков редко дотягивают!... у меня последний раз было куплено за 17733, хорошо руками продать успел когда курс в низ пошел :) но у меня тестовые 33 бакса крутились, на пробу.
но ведь руками не уследишь, а скриптом по заданному алгоритму вполне!
То же самое и про низ графика...


Про прошлого и будущего - Мы же имеем возможность брать лучшие и необходимые для нас значения... 
https://api.exmo.com/v1/order_book/?pair=BTC_USD

ask_top - минимальная цена продажи
bid_top - максимальная цена покупки

от сюда и плясать... смотреть... но да, все же Ваш опыт лучше моего, возможно где то я блужу в своих измышлениях :)
Главный смысл поста выше - в алгоритме
13.01.2018 07:31
А ведь правильно выше человек сказал - эмулятор нужно. Чтобы не на живых деньгах алгоритм отлаживать.
Может кто то в сети видел, может демо версия какая то эмулирующая работу...

Отладили бы мы дружно все вместе алгоритм, выбрали бы лучший... а по нему уже и скрипт настроить...
Кто что думает?
13.01.2018 09:12
да, конечно не абы какой эмулятор, а чтобы мы сами могли изменять, добавлять / пробовать алгоритмы конечно же
13.01.2018 09:14
И да, не просто графики / сигналы, а чтобы лог вел, показывал теоретически возможные покупки продажи и считал теоретически возможную прибыль...

14.01.2018 19:52
Пошустрил по интернету и вроде нашел то, что нужно. Пойдет или не пойдет под задачу я точно сказать не могу, но по описанию похоже на это. Briar Navigator прога называется.
15.01.2018 16:12
From $22.5/month
15.01.2018 16:13
не имеет смысла для отладки
18.01.2018 13:53
Там бесплатный период на 15 дней. Прога производит расчет в несколько раз быстрее, чем аналоги, естественно график нужно мониторить не онлайн, а загружать архивный
12.01.2018 13:40
Андрей, спасибо за бот. С установкой, настройкой и запуском не возникло проблем.Тестирую пока на BTC / USD. Хороший познавательный сайт для начинающих трейдеров как я. Успехов процветания, новых статей.
12.01.2018 17:02
Спасибо, статьи будут)
14.01.2018 19:47
за сутки ни одной сделки.у кого работает поделитесь настройками?
15.01.2018 06:58
# Тонкая настройка
CURRENCY_1 = 'USD' 
CURRENCY_2 = 'RUB'

BEAR_PERC = 70
BULL_PERC = 30

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

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

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

напишите свои настройки, с данными 3-4 сделки за сутки, надо ускоряться
15.01.2018 18:34
а у меня другой бот.# Список пар, на которые торгуем
MARKETS = ['BTC_USD']

CAN_SPEND = 150 # Сколько USD готовы вложить в бай
MARKUP = 0.001 # 0.001 = 0.1% - Какой навар со сделки хотим получать

STOCK_FEE = 0.002 # Какую комиссию берет биржа
PERIOD = 5 # Период в минутах для построения свечей
ORDER_LIFE_TIME = 0.5 # Через сколько минут отменять неисполненный ордер на покупку 0.5 = 30 сек.

USE_MACD = True # True - оценивать тренд по MACD, False - покупать и продавать невзирая ни на что

BEAR_PERC = 70  # % что считаем поворотом при медведе (подробности - https://bablofil.ru/macd-python-stock-bot/
BULL_PERC = 99.5  # % что считаем поворотом при быке

#BEAR_PERC = 70  # % что считаем поворотом при медведе
#BULL_PERC = 100  # Так он будет продавать по минималке, как только курс пойдет вверх

API_URL = 'api.exmo.me'
API_VERSION = 'v1'

USE_LOG = False
DEBUG = False # True - выводить отладочную информацию, False - писать как можно меньше

numpy.seterr(all='ignore')
15.01.2018 07:01
Самая беда это когда при росте частично ордер на BUY исполняется и скрипт ждет подходящую цену докупить. Получается и рост есть можно торговать, а он ждет падения, докупает и снова ждет подъема.
16.01.2018 09:26
Андрей а на BINANSE можно запустить бот?
16.01.2018 17:17
Да!
Постараюсь поскорее выложить пример
16.01.2018 13:03
Андрей, добрый день!

Можете посоветовать, как бороться с этим (периодически выскакивает):
***
  File "C:\Users\Mutant\YandexDisk\COINS\Python то-се\готовое\exmo_v_5.py", line 47, in call_api
    response = conn.getresponse().read()
  File "D:\lib\http\client.py", line 1331, in getresponse
    response.begin()
  File "D:\lib\http\client.py", line 297, in begin
    version, status, reason = self._read_status()
  File "D:\lib\http\client.py", line 258, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "D:\lib\socket.py", line 586, in readinto
    return self._sock.recv_into(b)
  File "D:\lib\ssl.py", line 1009, in recv_into
    return self.read(nbytes, buffer)
  File "D:\lib\ssl.py", line 871, in read
    return self._sslobj.read(len, buffer)
  File "D:\lib\ssl.py", line 631, in read
    v = self._sslobj.read(len, buffer)
socket.timeout: The read operation timed out
16.01.2018 17:18
У вас интернет-канал пропадает (может вай-фай нагружен).
Для начала проверьте, не запущен ли торрент :) Потом уже надо разбираться.
На крайний случай арендуйте VPS/VDS и запустите бота на нём
17.01.2018 20:59
Андрей, спасибо за сайт и информацию...очень интересно и полезно....
вопрос по запуску нескольких ботов, я сделал всё как Вы писали ранее и гуглил этот вопрос но чё то не получилось
Вот чего пишет:

Microsoft Windows [Version 10.0.16299.192]
(c) Корпорация Майкрософт (Microsoft Corporation), 2017. Все права защищены.

C:\Windows\System32>
C:\Windows\System32>python
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.ру
  File "<stdin>", line 1
    D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.ру
                                                           ^
SyntaxError: unexpected character after line continuation character
>>> python D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.py
  File "<stdin>", line 1
    python D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.py
           ^
SyntaxError: invalid syntax
>>> python D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.py
  File "<stdin>", line 1
    python D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.py
           ^
SyntaxError: invalid syntax
>>>

ПОДСКАЖИТЕ КАК ПОПРАВИТЬ СИТУАЦИЮ???</stdin></stdin></stdin>
21.01.2018 11:42
Запускайте сразу вот так:
C:\Windows\System32>python   D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.ру
07.02.2018 16:14
Добрый вечер,  Андрей. у меня с запуском файла такая песня (ничего не правила в коде, кроме ключа и секрета)
C:\Users\Наташа>python D:\programmir\exmo.py
  File "D:\programmir\exmo.py", line 226
    using System;
               ^
SyntaxError: invalid syntax
17.01.2018 20:59
Андрей, спасибо за сайт и информацию...очень интересно и полезно....
вопрос по запуску нескольких ботов, я сделал всё как Вы писали ранее и гуглил этот вопрос но чё то не получилось
Вот чего пишет:

Microsoft Windows [Version 10.0.16299.192]
(c) Корпорация Майкрософт (Microsoft Corporation), 2017. Все права защищены.

C:\Windows\System32>
C:\Windows\System32>python
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.ру
  File "<stdin>", line 1
    D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.ру
                                                           ^
SyntaxError: unexpected character after line continuation character
>>> python D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.py
  File "<stdin>", line 1
    python D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.py
           ^
SyntaxError: invalid syntax
>>> python D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.py
  File "<stdin>", line 1
    python D:\проект_БИТКОИН\Lessons_Python\bot1_RippleRub\exmo.py
           ^
SyntaxError: invalid syntax
>>>

ПОДСКАЖИТЕ КАК ПОПРАВИТЬ СИТУАЦИЮ???</stdin></stdin></stdin>
18.01.2018 15:54
Открытых ордеров нет
2018-01-18 20:53:22.337262   XRP_USD Открытых ордеров нет
2018-01-18 20:53:22.366263   XRP_USD  Обработка...
2018-01-18 20:53:25.474441   XRP_USD Условия рынка не подходят для торговли {'trand': 'BULL', 'growing': True}
Открытых ордеров нет
2018-01-18 20:53:35.954040   XRP_USD Открытых ордеров нет
2018-01-18 20:53:35.983042   XRP_USD  Обработка...
2018-01-18 20:53:39.159224   XRP_USD Условия рынка не подходят для торговли {'trand': 'BULL', 'growing': True}

почему он не покупает?
21.01.2018 11:43
Потому что видимо уже пик, на пике покупать плохо.
19.01.2018 11:41
Хочу знать, как сделать автоматическую отмену ордера на продажу, если цена вдруг падает, чтобы не уйти в минус.
19.01.2018 23:10
доброго времени суток такая проблема 

================== RESTART: C:/Users/BILAL/Desktop/ghju.py ==================
Проверяем, что происходит с отложенным ордером 496460959
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло -10415.956767082214 секунд
Проверяем, что происходит с отложенным ордером 496460959
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло -10413.911649942398 секунд
Проверяем, что происходит с отложенным ордером 496460959
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло -10411.8535323143 секунд
Проверяем, что происходит с отложенным ордером 496460959
Traceback (most recent call last):
  File "C:/Users/BILAL/Desktop/ghju.py", line 203, in <module>
    main_flow()
  File "C:/Users/BILAL/Desktop/ghju.py", line 99, in main_flow
    order_history = call_api('order_trades', order_id=order['order_id'])
  File "C:/Users/BILAL/Desktop/ghju.py", line 57, in call_api
    response = conn.getresponse().read()
  File "C:\Users\BILAL\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1331, in getresponse
    response.begin()
  File "C:\Users\BILAL\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 297, in begin
    version, status, reason = self._read_status()
  File "C:\Users\BILAL\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 258, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
  File "C:\Users\BILAL\AppData\Local\Programs\Python\Python36\lib\socket.py", line 586, in readinto
    return self._sock.recv_into(b)
  File "C:\Users\BILAL\AppData\Local\Programs\Python\Python36\lib\ssl.py", line 1009, in recv_into
    return self.read(nbytes, buffer)
  File "C:\Users\BILAL\AppData\Local\Programs\Python\Python36\lib\ssl.py", line 871, in read
    return self._sslobj.read(len, buffer)
  File "C:\Users\BILAL\AppData\Local\Programs\Python\Python36\lib\ssl.py", line 631, in read
    v = self._sslobj.read(len, buffer)
KeyboardInterrupt
>>> 

на бирже ордер висит но не идет дальше и нет возврата.
</module>
19.01.2018 23:30
import urllib, http.client
import time
import json
# эти модули нужны для генерации подписи API
import hmac, hashlib

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

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

CURRENCY_1_MIN_QUANTITY = 3 # минимальная сумма ставки - берется из 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 = 180 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1
PROFIT_MARKUP = 0.001 # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
DEBUG = True # True - выводить отладочную информацию, False - писать как можно меньше

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

# базовые настройки
API_URL = 'api.exmo.me'
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.HTTPConnection(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 '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=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: # мы можем купить слишком мало на нашу сумму
                            raise 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)

вот код. когда поменял время на 0. то секунды стали так
Проверяем, что происходит с отложенным ордером 496532539
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло 38.1987030506134 секунд
Проверяем, что происходит с отложенным ордером 496532539
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло 39.71078968048096 секунд
Проверяем, что происходит с отложенным ордером 496532539
Частично исполненных ордеров нет
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло 41.2988805770874 секунд
 а дальше не идет
19.01.2018 23:43
ордер прошел) теперь пишет это на несколько и исполняться частями)
Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)
Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)
Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)
Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)
Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)
Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)
Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)
Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)

это нормально?
20.01.2018 03:10
нормально, ждет пока все продаст
19.01.2018 23:41
с запуском ботов одновременно разобрался, спс.
токо талиб не ставится...((
20.01.2018 10:44
бот заработал. после пару продаж и покупок поставил на продажу. ордер с ценой на 1000 у.е выше стоимости на бирже в чем проблема?
21.01.2018 11:54
Что кто-то подщипывает монетки.

Например:

Бот играл ltc_usd, купил за 400$ 2 ltc.
Бот собирается их продать и получить 1% прибыли - значит нужно получить 404$. Курс составит 202$ за штуку.
В это время кто-то (другой бот или человек) взял и перевел полтора лайткойна. Или продал. Или еще чего.
В итоге бот, что бы выручить 404$ за продажу 0.5 оставшихся LTC выставляет ордер по курсу 808$.
20.01.2018 13:29
Скажите пожалуйста.
У меня у одного бот пытается купить по цене выше, чем продал?
пробовал на разных парах, но если он скажем продал за 100 баксов, то покупает на 100+
Реально сейчас продал за 11200, а покупать хочет за 11278... Чт за фигня? Разъясните пожалуйста.
20.01.2018 13:36
Пишет вот такую фигню:
Открытых ордеров нет
buy 0.0001772479413943368 11283.6289339488
Выход, не хватает денег на создание ордера
Открытых ордеров нет
buy 0.0001772479413943368 11283.6289339488
Выход, не хватает денег на создание ордера
Открытых ордеров нет
buy 0.0001772479413943368 11283.6289339488
Выход, не хватает денег на создание ордера
Открытых ордеров нет

Что это значит?
Сейчас вот такие настройки:
# Тонкая настройка
CURRENCY_1 = 'BTC' 
CURRENCY_2 = 'EUR'

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 = 15 # За какой период брать среднюю цену (мин)
CAN_SPEND = 2 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1
PROFIT_MARKUP = 0.002 # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
DEBUG = True # True - выводить отладочную информацию, False - писать как можно меньше

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

# базовые настройки
API_URL = 'api.exmo.me'
API_VERSION = 'v1'
20.01.2018 14:03
Я же не дурак и понимаю, что бот пытается создать ордер на сумму 0.0001772479413943368 BTC, по цене 11283.6289339488 EUR, сумарно это получается 2 евро. Бот пишет, что не хватает денег для создания, но блин, на балансе у меня 35 евро...

объясните пожалуйста, что не так?
20.01.2018 14:11
Дорогие друзья.
Сам себе отвечу.

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

Спасибо.
20.01.2018 21:33
Привет! Сразу извиняюсь за оффтоп.
Применил данного бота на бирже wex.nz, заменив методы (они почти не отличаются)
Код работает, но, видимо, не так, как должен. Пока не выставляю ордер вручную, постоянно выдаются сообщения
no orders
no orders
no orders

Если выставить ордер вручную  через сайт, то бот пишет 
!!!! string indices must be integers
!!!! string indices must be integers
!!!! string indices must be integers
пока все ордера не сработают. далее снова no orders

Пожалуйста, помогите! Возможно, эти типичная ситуация?
21.01.2018 11:39
Немного все же отличаются..
Добавил на сайт рабочего бота для wex.nz - https://bablofil.ru/bot-dlya-birgi-wex/
21.01.2018 14:53
Скажите, пожалуйста,нет ли у вас фрагментов кода для STOP LOSS и TAKE PROFIT к вашему боту для EXMO?
22.01.2018 07:03
Здравствуйте, нет, таких фрагментов нет
24.01.2018 17:52
Подскажите пожалуйста что за ошибка такая?

Открытых ордеров нет
buy 10.5049351485447 1.4279002952320008
Error 50277: Quantity by order is less than permissible minimum for this pair
Открытых ордеров нет
buy 10.5049351485447 1.4279002952320008
Error 50277: Quantity by order is less than permissible minimum for this pair
Открытых ордеров нет
buy 10.5049351485447 1.4279002952320008
Error 50277: Quantity by order is less than permissible minimum for this pair
Открытых ордеров нет
buy 10.5049351485447 1.4279002952320008
Error 50277: Quantity by order is less than permissible minimum for this pair
Открытых ордеров нет
buy 10.5049351485447 1.4279002952320008
Error 50277: Quantity by order is less than permissible minimum for this pair
Открытых ордеров нет
buy 10.5049351485447 1.4279002952320008
Error 50277: Quantity by order is less than permissible minimum for this pair
Открытых ордеров нет
buy 10.5049351485447 1.4279002952320008
Error 50277: Quantity by order is less than permissible minimum for this pair
Открытых ордеров нет
buy 10.5049351485447 1.4279002952320008
Error 50277: Quantity by order is less than permissible minimum for this pair
Открытых ордеров нет
24.01.2018 18:14
Сорри разобрался
16.02.2018 08:36
В чём была проблема? У меня такое же. Не могу понять.
16.02.2018 09:10
Объем лота меньше, чем минимально допустимый на бирже. Увеличьте сумму торгов
27.01.2018 06:23
Здравствуйте Андрей! Расскажите пожалуйста по подробней о методе:

 <<<<<<<=============   def call_api(api_method, http_method="POST", **kwargs):  ====================>>>>>>>> 

Не могу понять логики его работы. 
(Ну и было бы не плохо если бы вы еще рассказали про аргумент в методе **kwargs? Для чего он?)

Заранее очень благодарен!!!
27.01.2018 09:14
Добрый день
Добавил комментарии в код статьи
**kwargs - означает, что в программу можно передавать любое количество параметров в формате ключ-значение, и все они будут помещены в словарь kwargs который можно использовать внутри функции
27.01.2018 12:49
Спасибо огромное за такую оперативность и качество ответа. Очень благодарен, при возможности отблагодарю материально!!!
27.01.2018 17:31
Здравствуйте подскажите, выдает вот такую ошибку
!!!! key: expected bytes or bytearray, but got 'str'
28.01.2018 07:23
Букву b забыли

# ключи API, которые предоставила exmo
API_KEY = 'YOUR API KEY'
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b'YOUR API SECRET'
28.01.2018 17:26
если бот купит на пике и идет спад, есть ли возможность строить так что бы он продал не уходя в большой минус?
28.01.2018 19:13
или есть возможность сделать так что бы он смотрел на сам график, а не от сделок?
30.01.2018 17:06
Добрый день! Запустил бота
всевремя пишет так , ордера не открывает что о не правильно может? Открытых ордеров нет
!!!! 'BTC_XRP'
Открытых ордеров нет
!!!! 'BTC_XRP'
Открытых ордеров нет
...
30.01.2018 17:49
Добрый день!
Скорее всего, что то со связью, посмотрите комментарии выше, тут много случаев разобрано
30.01.2018 18:53
Ни чего не пойму , либо в коде ошибка либо я тугой 
Специально сделал так чтобы были USD на счете BTC нет 0 на счету как написано в инструкции в настройках стоит оригинальный код 
USD на счету есть .
Открытых ордеров нет
buy 0.0009217295269398218 10849.16964003572
Выход, не хватает денег на создание ордера
Открытых ордеров нет
buy 0.0009217295269398218 10849.16964003572
Выход, не хватает денег на создание ордера
меня местами в коде USD и BTC
Начинает писать это :
Открытых ордеров нет
sell 18.8065483 10.03 0.5333248738685343
Error 50189: Pair was not found 'USD_BTC'
Открытых ордеров нет
sell 18.8065483 10.03 0.5333248738685343
Error 50189: Pair was not found 'USD_BTC'
Открытых ордеров нет
sell 18.8065483 10.03 0.5333248738685343
Error 50189: Pair was not found 'USD_BTC'
30.01.2018 19:18
Возможно, сумма слишком мала? Когда я писал статью, 5$ было много, т.к. биткоин стоил 300. Сейчас 15-20 нужно что бы минимальный лот купить
01.02.2018 18:31
Открытых ордеров нет
sell 3.78218005 78.0 20.623026658923866
{'result': True, 'error': '', 'order_id': 530046373}
Создан ордер на продажу USD 530046373
Открытых ордеров нет
!!!! float division by zero
Открытых ордеров нет
!!!! float division by zero
Открытых ордеров нет
!!!! float division by zero
Открытых ордеров нет
!!!! float division by zero
Открытых ордеров нет
!!!! float division by zero
продал мои 3 доллара и дальше пишет это. для любой пары
05.02.2018 08:03
Ошибка деления на ноль.. Если не вносили изменения в код, проверьте настройки, в частности STOCK_FEE и PROFIT_MARKUP.
04.02.2018 17:36
Здравствуйте! Спасибо за бота! Можно ли остановить бота нажатием клавиши или комбинаций клавиш на клавиатуре? Или нужно только закрывать файл exmo.ру?
05.02.2018 07:57
Добрый день!
Ctrl+C подойдет
08.02.2018 07:07
Здравствуйте,  Андрей. у меня с запуском файла такая песня (ничего не правила в коде, кроме ключа и секрета)
C:\Users\Наташа>python D:\programmir\exmo.py
  File "D:\programmir\exmo.py", line 226
    using System;
               ^
SyntaxError: invalid syntax
09.02.2018 05:52
using System;
это что-то из чужого кода)
08.02.2018 10:54
Добрый день! Помогите пожалуйста новичку. Не могу запустить скрипт. Пишет:
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import exmo.py
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\Elektrik\AppData\Local\Programs\Python\Python36-32\exmo.py", line 88
SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0xce in position 0: invalid continuation byte.
Заранее спасибо.</module></stdin>
08.02.2018 13:17
из командной строки
C:\Users\Наташа>python D:\programmir\exmo.py
  File "D:\programmir\exmo.py", line 226
    using System;
               ^
SyntaxError: invalid syntax
08.02.2018 13:17
из командной строки
C:\Users\Наташа>python D:\programmir\exmo.py
  File "D:\programmir\exmo.py", line 226
    using System;
               ^
SyntaxError: invalid syntax
08.02.2018 16:24
Я заново скопировала код, вставила в файл, вписала ключ и секрет. Вывод
C:\Users\Наташа>python D:\programmir\exmo1.py
!!!! [WinError 10060] Попытка установить соединение была безуспешной, т.к. от другого компьютера за требуемое время не получен нужный отклик, или было разорвано уже установленное соединение из-за неверного отклика уже подключенного компьютера
09.02.2018 05:54
Не смог подключиться к бирже. Наверное роскомнадзор, смотрите комментарии в самом верху о том, как обойти ограничения
09.02.2018 07:32
получилось. спасибо
09.02.2018 09:00
День добрый!

Вот как настроил:
CURRENCY_1 = 'BTC' 
CURRENCY_2 = 'USD'

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

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

И что пишет:

Открытых ордеров нет
Не удается вычислить среднюю цену []
Открытых ордеров нет
Не удается вычислить среднюю цену []
Открытых ордеров нет
Не удается вычислить среднюю цену []
Открытых ордеров нет

В чем может быть проблема?
09.02.2018 14:14
выставила шапку как у вас. Запуск тот же. Как то смогли решить?
C:\Users\Наташа>python D:\programmir\exmo1.py
Открытых ордеров нет
Не удается вычислить среднюю цену []
Traceback (most recent call last):
  File "D:\programmir\exmo1.py", line 225, in <module>
    print(e)
NameError: name 'e' is not defined</module>
10.02.2018 12:41
Добрый день!
Все-таки, верните STOCK_TIME_OFFSET в 0
Биржа живет по времени UTC и питон берет время по UTC, так что все должно совпадать. Менять этот параметр практически никогда не требуется.
12.02.2018 08:09
Два дня поработал, потом задрал цену относительно рынка (а не цена просела) и теперь ждет роста курса))))
Пытаюсь ордер отменить - ставит точно такую же высокую цену.....
09.02.2018 09:22
ДОБРЫЙ день. почти та же проблема. на счету 6 usd. При запуске выдает:
C:\Users\Наташа>python D:\programmir\exmo1.py
Открытых ордеров нет
buy 0.0005944230521367807 8411.517659058529
Выход, не хватает денег на создание ордера
Traceback (most recent call last):
  File "D:\programmir\exmo1.py", line 225, in <module>
    print(e)
NameError: name 'e' is not defined
</module>
10.02.2018 12:42
Это вы, видимо, что-то поправили в коде, может быть пробелы с табуляциями куда-то съехали. Скачайте заново код с сайта
10.02.2018 18:26
спасибо это поправилось. Теперь пишет
Выход. не хватает средств для открытия ордера
хотя на usd 13 долларов
Часть шапки:
# Тонкая настройка
CURRENCY_1 = 'BTC' 
CURRENCY_2 = 'USD'

CURRENCY_1_MIN_QUANTITY = 0.003 # минимальная сумма ставки - берется из 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 = 10 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1
PROFIT_MARKUP = 0.001 # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
DEBUG = True # True - выводить отладочную информацию, False - писать как можно меньше

STOCK_TIME_OFFSET = 0 # Если расходится время биржи с текущим
10.02.2018 20:44
Потому что вы зачем то поставили
CURRENCY_1_MIN_QUANTITY = 0.003
У вас стоит 10 долларов на покупку
Если брать курс 9000$, то ваших денег хватит на покупку 0.00111... А это меньше чем 0.003!
Вы указали, что 0.003 это минимальная ставка, которую принимает биржа. Отсюда и последствия
11.02.2018 06:54
Благодарю Вас . получилось!
12.02.2018 08:49
Здравствуйте. Почему то ночью по парам BTC/USD и BTН/USD не было сделок. хотя бот оставался включенным на компе. Нужно ли чтоб еще был открыт мой аккаунт в браузере или это неважно?
15.02.2018 07:50
Добрый день.
Аккаунт держать открытым не нужно, бот авторизуется независимо от человека
12.02.2018 13:39
Это почему появляется:
40009: The nonce parameter is less or equal than what was used before "1518440188707"
15.02.2018 07:51
Либо несколько ботов работают параллельно, либо сеть медленная, поздние пакеты приходят позже ранних, либо на бирже сбои - бывает, в общем.
13.02.2018 11:14
Здравствуйте, я скачала Вашего бота, он работает, только медленно. Бывает ордера по 3-4 часа висят. Подскажите, как усовершенствовать бота, чтобы он работал быстрее и лучше? И по какой максимальной сумме он может работать? Заранее спасибо
15.02.2018 08:00
Здравствуйте.
Для того, что бы ордер исполнился, нужно, что бы кто-то его купил. Если общий курс биржи падает, то и покупать никто не хочет - отсюда 3-4 часа. Тут проблема не совсем в боте - если бы вы руками выставляли такие же ордера, они бы так же ждали исполнения. 
Усовершенствовать можно в любую сторону, например ребята с сайта сделали отдельную версию - https://bablofil.ru/forum/7, попробуйте её.
Вообще ограничения по сумме нет, но нужно иметь в виду, что маленькую сумму раскупят быстро другие трейдеры, а большую могут и не осилить - купят, скажем, 70% по текущему курсу, а 30% останутся висеть и курс за это время уйдет..
15.02.2018 19:19
Добрый день, подскажите как купить или продать по API по верхней строке. Не выставить ордер, а сразу?
16.02.2018 09:16
Технически, с точки зрения биржи это все равно будет ордер, даже когда покупаете через обмен.
Но вы можете покупать по рынку, в таком случае ордер должен исполниться практически сразу по рыночной цене.
Ставите цену 0, указываете пару, кол-во к покупке и тип - market_buy
new_order = call_api(
                                'order_create',
                                pair=CURRENT_PAIR,
                                quantity = my_amount,
                                price=0,
                                type='market_buy'
                            )
03.09.2018 18:50
Подскажите... нужно так прописать
'order_create',
                                pair=USD_USDT,
                                quantity = 3,
                                price=0,
                                type='market_buy'
                            )

'order_create',
                                pair=USDT_USD,
                                quantity = 3,
                                price=0,
                                type='market_sell'
                            )
а то выходит что покупает  по минимальной цене продажи (коинов) а на а на продажу не может выставить пишет my_amount и нужно продавать в ручную....
16.02.2018 10:47
Ну в принципе можно сделать ордер с такой-же ценой, только в соседнем столбике, но есть такой момент, что первой строкой идёт ордер, размером ниже минимума-не до конца исполненный, а на второй строке уже сидит наглый тип и хочет слишком много. Соответственно купить через браузер лот я могу, а выставлением встречного лота - нет. Кроме того через браузер, как я поняла купить-продать существующие лоты я могу без оглядки на минимальную сумму ордера, лишь бы сделка прошла, а там можно и 0 на выходе получить
16.02.2018 17:57
Вам разве через браузер даст выставить на небольшую сумму? Обычно же выдается что-то вроде
Ошибка 10464: Кол-во по ордеру меньше минимально допустимого по этой валютной паре (0.001 BTC).
Вы можете, что через апи, что через браузер выставить ордер по той цене, по которой продают остаток (но на минимально разрешенный объем), скупить мелочь и отменить свой частично исполненный ордер. Тогда вы не купите у наглого типа, и получите желаемое.
17.02.2018 13:51
Именно так, но... можно выбрать лот, выставвить в количестве меньше, чем разрешённый минимальный и нажать купить.
А по поводу идеи по API скупиnm мелочь и отменить идея интересна, спасибо.
17.02.2018 20:21
Я так поняла, что, если я выставляю встречный лот по цене более выгодной, чем в 1-й строке, то эксмо всё-равно сначала закроет по наилучшей цене, а потом, если не хватит, то будет закрывать по строкам ниже пока не закроет весь лот или пока не дойдёт до строки, в которой цена выше указанной, правильно?
18.02.2018 06:09
Да, я проверила это утверждение, всё так и есть. Эксмо даёт лучшую цену, если это возможно.
18.02.2018 06:40
Да, всё так и для покупки, и для продажи
21.02.2018 17:32
Андрей такой вопрос.Пробовал торговать на BTC -USD на сумму 1200$ то при продаже обычно не все продается.Оставшееся суума к примеру половина уходит ниже и висит в стакане .поскольку постоянно сбивают цену.Можно ли как то разбитть сумму скажем по 120$ штук 10 ордеров.как это сделать.пробовал один и тот же код но сохранял под разные файлы к примеру exmo1 потом exmo 2.....до 10 . Однако ничего не получается.Запускает первый файл на 120 и все.Что делать как разбить ордер с 1200 до 120.Спасибо.
21.02.2018 17:42
Имел ввиду как распределить всю сумму по ордерам по 120 или 240.Воощем на балансе 1200$.
25.02.2018 07:33
Добрый день.
Как вариант, можно играть по разным парам, на каждую пару свою сумму.
21.02.2018 18:23
Уважаемые писатели кода, а сможет кто к эксмо припаять трейлинг-стоп, чтоб ценну на продажу по МАСD не продавал сразу по фиксированному проценту, а подтягивал до мах. в определенном таймфрейме от 60 мин.?
04.03.2018 20:31
Здравствуйте) Как устранить ошибку?
Открытых ордеров нет
buy 0.013975590084450078 214.65998801281
Error 50277: Quantity by order is less than permissible minimum for this pair
04.03.2018 20:37
Вроде выставил всё правильно
# Тонкая настройка
CURRENCY_1 = 'LTC' 
CURRENCY_2 = 'USD'
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 = 3 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1
PROFIT_MARKUP = 0.001 # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
DEBUG = True # True - выводить отладочную информацию, False - писать как можно меньше

STOCK_TIME_OFFSET = 0 # Если расходится время биржи с текущим
09.03.2018 08:17
В марте все стало уходить в минус. хотя в феврале с теми же параметрами был немного плюс. Пробовала на разных парах
11.03.2018 17:27
Столкнулся с проблемами:

1. Торгую на паре XRP/USD. на балансе 0.4 рипла было. Ставлю бота на торговлю 100 баксами, получаю следующее:
Error 50321: Price by order is more than permissible maximum for this pair
Открытых ордеров нет
sell 0.04 100.3 2507.5

Он думает что нужно продать остаток, а его продать нельзя  - минимум 15 риплов.  Тупик. Я их тоже продать не могу ))

2. При выставлении ордера на покупку он в стакане как правило занимает 5-6 место и выкупается когда тренд начинает падать и смысла уже нет.
19.03.2018 20:41
Здравствуйте, Андрей К. Подскажите что нужно добавить, чтобы покупка осуществлялась раз в 30мин. Сейчас бот покупает не жожидаясь продажи.
Заменил
 raise ScriptQuitCondition('Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)')
заменить на вот это:
pass
На падении рынка очень быстро сливает депо
13.04.2018 02:20
рома подскажи! поменял raise  на pass  у меня бот перестаёт работать(((   не могу понять почему
18.04.2018 13:38
Добрый день! 
Подскажите что сделано не так при попытке запустить робота , выдает надпись( invalid syntax)
18.04.2018 13:38
Добрый день! 
Подскажите что сделано не так при попытке запустить робота , выдает надпись( invalid syntax)
25.04.2018 19:01
Доброго времени суток!
Спасибо за интересную информацию, ответ на свой вопрос нашёлся в переписке .
05.05.2018 12:12
Доброго времен дня  вопрос следующий зачем в боте строчка      order_history = call_api('order_trades', order_id=order['order_id'])
она же не где не используется или я не прав????
16.05.2018 08:59
Используется

try:
        order_history = call_api('order_trades', order_id=order['order_id'])
         # по ордеру уже есть частичное выполнение, выход
         raise ScriptQuitCondition('Выход, продолжаем надеяться докупить валюту по тому курсу, по которому уже купили часть')
except ScriptError as e:

Тут устроено так, что если торгов по ордеру нет, то вылетит исключение ScriptError и процесс пойдет  в блоке except ScriptError as e:
Если торги есть, то исключения не будет, но создастся своё, ScriptQuitCondition и весь дальнейший блок исполняться не будет
15.05.2018 16:49
Здравствуйте!
Подскажите, в Вашем боте предусмотрена средняя цена, которая берется из истории сделок.
А можно сделать среднюю цену которая будет браться из открытых ордеров?
Как это сделать?
16.05.2018 09:01
Добрый день,
Можно, посмотрите комментарии на этой странице, содержащие order_book
08.06.2018 10:27
Здравствуйте
а вы почту читаете )))  orders@bablofil.ru или она не ваша! написал туда второй день ни ответа ни привета
08.06.2018 10:30
А вы можете его подправить или какой участок кода на что поменять, что бы сравнивал цену покупки и если покупка < цены хая - какойто процент то покупать
17.06.2018 10:41
добрый день.
При установке на digitalocean через ssl такая ошибка возникает 
Traceback (most recent call last):
  File "exmo.py", line 4, in <module>
    import urllib, http.client
ImportError: No module named http.client

как ее пофиксить? </module>
17.06.2018 11:51
python третий
18.06.2018 07:51
У вас, возможно, третий питон установлен, но код выполняется во втором
Попробуйте запускать по другому, например python3.5 ./exmo.py
18.06.2018 19:06
спасибо! Да, снес когда все и с нуля поставил на машину 3 питон, все заработало
20.06.2018 11:32
Доброго времени суток!

Поставил плагин PyDev на Eclipse(4.7.3a).
Python - версия 3.6

В строке
conn = http.client.HTTPSConnection(API_URL, timeout=60)
метод "HTTPSConnection" подчеркнут красным: "Undefined variable from import: HTTPSConnection"
Без "S" - без изменений.

Пожалуйста, подскажите в чем причина?
Спасибо.
21.06.2018 08:00
Что то с путями, наверное
Можно попробовать поменять настройки https://stackoverflow.com/questions/2112715/how-do-i-fix-pydev-undefined-variable-from-import-errors
29.07.2018 14:01
а как будет выглядеть скрипт на отмену ордера на эксмо?если номер ордера тут orid = int(orderid[0]) , пробовал так ExmoAPI_instance.api_query("order_cancel"("order_id" == orid)), не получается
01.08.2018 10:04
Добрый день:
Полагаю, как-то так
ExmoAPI_instance.api_query("order_cancel", {"order_id": orid})
29.07.2018 16:14
Подскажите пожалуйста, торгую на нескольких парах. По одной из пар (XMR/USD) заметил, что бот иногда торгует в минус.
Запись об этом отмечена воскл.знаком. Что может быть не так?

26.07 20:50 buy 140.75072725 0.07104759 9.99999996
26.07 19:51 sell 140.65253802 0.07131048 10.02999999
26.07 19:45 buy 139.9513825 0.07145338 9.99999931
! 26.07 19:25 sell 139.71629109 0.03519237 4.91694741
! 26.07 05:17 buy 141.79208884 0.03526289 4.99999883
26.07 05:12 sell 142.45702144 0.00880577 1.25444376
26.07 05:03 sell 142.45702144 0.02639783 3.76055623
26.07 04:45 buy 141.74687785 0.03527414 4.99999921
26.07 03:56 sell 141.97343355 0.03532351 5.01499999
01.08.2018 10:07
Добрый день
Полагаю, речь не про бота из этой статьи?
Этот бот в таком замечен не был)
01.08.2018 17:18
а как узнать запросом что исполнился ордер на покупку или был отменён?на другой бирже там запрос OrderInfo и статус "status: 0 - активен, 1 - исполненный ордер, 2 - отмененный, 3 - отмененный, но был частично исполнен.". А на эксмо чтот не нашёл
07.08.2018 10:53
Кстати да, тут неудобно.
Если он есть в open_orders то соответствено открыт, если есть в cancelled_orders то отменен (при этом всем он может быть исполнен частично)
Ну а если нет ни там ни там то наверное исполнен, можно посмотреть записи в order_trades
02.08.2018 13:02
а это как понимать Error 50049: Parameter is not a number 'quantity'?
запрос так отправляю  orderbuy = ExmoAPI_instance.api_query('order_create', {'pair':'USD_RUB','quantity':str('quantity'),'price':'52','type':'buy'})
02.08.2018 14:21
разобрался, так получилось orderbuy = ExmoAPI_instance.api_query('order_create', {'pair':'USD_RUB','quantity': quantity,'price':'52','type':'buy'})
17.08.2018 08:35
Доброго времени суток! Спасибо за ваш труд, очень помогаете начинающим. Подскажите, не могу понять, а как брать суммы с других стаканов биржи? Смотрел здесь, https://exmo.com/ru/api, но мой уровень познаний программирования слишком низок, помогите примером кода. Спасибо!
17.08.2018 19:25
Извините, не заметил, этот вопрос уже поднимался. Вопрос снят. В любом случае, спасибо!
18.08.2018 16:25
Добрый вечер Андрей.
Попробовал запустить вашего бота под работу на бирже Livecoin. 
При проверке obj - Выдает ошибку анализа возвращаемых данных, полученная строка
В чем может быть причина, подскажите пожалуйста.
19.08.2018 09:08
Добрый день.
Это разные биржи, у них разное api, под livecoin нужно писать свой код.
Вообще почти каждая биржа по своему делает механизмы взаимодействия с ней, есть универсальный протокол fix, но его практически никто не поддерживает, так что код в этой статье работает только с биржей Эксмо, в соседних статьях есть код для йобита, бинанса, векса, ликви, биттрекса и т.п. Для ливкойна не делал, может быть когда нибудь, не знаю)
21.08.2018 13:25
Спасибо за ответ. Надеюсь что и для Livecoina будет выложен торговый бот. Буду пробовать разобраться самостоятельно.
26.08.2018 08:02
Добрый день, немного пробую изменить код.... при запуске выдает такую ошибку !!!! string indices must be integers (Строковые индексы должны быть целыми числами) - как это можно исправить, либо разробраться где что изменить
29.08.2018 10:27
Доброго времени суток всем! Обращаюсь ко всем с вопросом, не могу победить вывод одного метода, а именно "user_trades", люди, помогите разобраться, как правильно записать строки кода?
Что я сделал, взял часть кода из этого бота, отвечающую за обращение к бирже:
"
 import urllib, http.client
import time
import json
# эти модули нужны для генерации подписи API
import hmac, hashlib

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

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

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

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

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

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

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

CURRENT_PAIR = CURRENCY_1 + '_' + CURRENCY_2

# все обращения к API проходят через эту функцию
def call_api(api_method, http_method="POST", **kwargs):
    # Составляем словарь {ключ:значение} для отправки на биржу
    # пока что в нём {'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)
"
вписал свои ключи, обозначил валютную пару и дописал то, что как я понял, есть образцом обращения к данному методу согласно API Exmo.

last_order = call_api('user_trades' (pair=CURRENT_PAIR, limit=1, offset=0))

Но на выходе ничего, кроме ошибок.
Хочу привести к такому виду:

last_order = call_api('user_trades', (pair=CURRENT_PAIR, limit=1, offset=0))
last = float(last_order ,,,,,)
print(last)

Требуется получать данные "price" и "amount" данного метода.
Ребята, помогите понять принцип вызова таких методов, я совсем запутался.
Спасибо!
Всем удачи!
30.08.2018 09:59
Доброго дня!
Получил ответ биржи при записи такой строчки кода:
last_order = call_api('user_trades', pair=CURRENT_PAIR, limit=1, offset=1) 
print(last_order )
ответ биржи:
{'BTC_UAH': [{'trade_id': 87767833, 'date': 1535564950, 'type': 'sell', 'pair': 'BTC_UAH', 'order_id': 3353366220, 'quantity': '0.00499', 'price': '197955.55', 'amount': '987.7981945'}]}
но это массив данных, люди, как из этого массива данных выделить только "amount" и  "price"?
Помогите, пожалуйста!
Спасибо!
03.09.2018 14:41
Добрый день! Все сделал по инструкции, но вот незадача, при запуске выдает ошибку " error 40005: Authorization error, Incorrect signature ", подскажите, что я сделал неправильно?
03.09.2018 16:09
Спасибо всем, сам разобрался.
Удачи всем!
04.09.2018 09:35
Соррян, была ошибка в секретном ключе. Исправил все заработало.
07.09.2018 19:45
Доброго времени суток!
Этот вопрос уже поднимался выше, но ответа не последовало. Подскажите, как и где изменить код данного бота, что бы отменялись ордера на продажу.
Спасибо!
19.09.2018 12:36
У меня ошибка - "Не удается вычислить среднюю цену", "prices" - пусто. Что подскажете? Пока смотрю код. К бирже подключается, ордера закрывает, открывает, которые были до него.
19.09.2018 16:05
посылаю запрос  cancelorder = ExmoAPI_instance.api_query("order_cancel",{'order_id':orid}) с определённым ордером, а в ответ может такое прилететь  Error 50173: Order was not found '#1220442961' и скрипт останавливается в питоне ( >>> ),  на бирже пишет ответ такой должен 
 {
  "result": true,
  "error": ""
}
но думается это не то, как перехватить эту ошибку и дальше её обработать(на перезапуск скрипта)?
19.09.2018 16:05
Читаю комментарии, упоминается: "Валюта CURRENT_1 то есть - доллар, должна быть сведена к нулю, а в описании и алгоритме упор делается на первую валюту. Кто ошибся?

Когда запускаю бота - он спокойно переводит весь депозит из долларов в рубли, и потом начинает считать среднюю цэну по доллару, которого ноль. Возможного - из-за этого не может посчитать?

Дополнение: Полезно вести какой-то лог, а то вообще бота не изучить.
20.09.2018 18:04
У меня московская зона, и там смещение по времени надо ставить не "-3" а "3".
07.11.2018 05:15
Здравствуйте, Андрей, подскажите пожалуйста почему бот не пересчитывает ордер. Вроде все работало, но в какой-то момент создается ордер и не анализирует дальше рынок, просто ордер висит созданный прошлым днем??? В чем может быть причина?
17.12.2018 15:28
Вроде работает но сообщения стали странные:
условия рынка не подходяять для торговли {'trand',  'BEAR', 'growong',  'False' }
раньше было без фигурных скобок, поменял только валютные пары
17.12.2018 15:33
Ошибка не туда написал!. Андрей сделай нормальное меню списком справа, а то навигация на сайте ужасная.
29.03.2019 10:57
Почему при расчете средней суммы по истории торгов нет деления sell и buy? а просто общая средняя
02.04.2019 12:34
Почему нет?
Но Вы всегда можете изменить бота под себя так, как сочтете нужным ;)
26.04.2019 15:47
Здравствуйте!
Просьба помочь, при выборе пары USD_RUB ботом сразу продается весь баланс USD (то есть накопление баланса идет в RUB).
Есть ли способ сменить приоритет в накопление USD (чтобы основной баланс оставался в USD)?
27.04.2019 07:55
Боюсь, простого способа нет, нужно всё переделывать
09.06.2019 07:32
Андрей, я новичок! Попробую создать бота с парой BTC - RUB - нужно ли перевести все биткоины в рубли в начале торговли?
16.06.2019 15:21
Общий подход такой, у вас должна быть валюта, которую планируете потратить на покупку, но не должно быть валюты, которую планируете купить. В разных парах это разные валюты
16.06.2019 15:21
Общий подход такой, у вас должна быть валюта, которую планируете потратить на покупку, но не должно быть валюты, которую планируете купить. В разных парах это разные валюты
19.06.2019 11:02
Здравствуйте!
Запросив
order_history= {'type': 'buy', 'in_currency': 'TRX', 'in_amount': '2', 'out_currency': 'USD', 'out_amount': '0.0653175', 'trades': [{'trade_id': 92685080, 'date': 1560930402, 'type': 'buy', 'pair': 'TRX_USD', 'order_id': 2583213206, 'quantity': '2', 'price': '0.03265875', 'amount': '0.0653175'}]}
Как получить из этого в др. переменные значения price и amount?
Спасибо.
19.06.2019 12:07
У одного ордера могут исполнения по нескольким сделкам - разными кусками и разными ценами.
Что бы посмотреть все значения, нужен цикл, например

for trade in order_history['trades']:
    amount, price = trade['amount'], trade['price']
    print(amount, price)

Либо вы можете прямо обратиться к первой сделке, например
amount = order_history['trades'][0]['amount']
что бы обратиться ко второй (если она есть) поменяйте 0 на 1 и тп

Если вы хотите посчитать, во сколько в итоге обошлась покупка/продажа по ордеру, надо из сделок считать средневзвешенную цену (объем потраченного делить на объем полученного).
19.06.2019 19:18
Спасибо за подсказку, задуманное выполнено. :)
06.08.2019 08:40
Добрый день! Спасибо за ваши статьи!
Тоже решил попробовать использовать бота.
Но у меня тоже вылетает ошибка, как уже писали выше:

Открытых ордеров нет
buy 0.0004143517715461355 12067.041444863911
Выход, не хватает денег на создание ордера
Открытых ордеров нет
buy 0.0004143517715461355 12067.041444863911
Выход, не хватает денег на создание ордера
Открытых ордеров нет
buy 0.0004143656202697933 12066.638146148567
Выход, не хватает денег на создание ордера
Открытых ордеров нет
buy 0.0004143656202697933 12066.638146148567
Выход, не хватает денег на создание ордера
Открытых ордеров нет
buy 0.0004143656202697933 12066.638146148567
Выход, не хватает денег на создание ордера
Открытых ордеров нет
buy 0.0004143656202697933 12066.638146148567
Выход, не хватает денег на создание ордера
Открытых ордеров нет
buy 0.0004144073919492026 12065.421846077717
Выход, не хватает денег на создание ордера
Открытых ордеров нет
buy 0.00041442417133474987 12064.933336046332
Выход, не хватает денег на создание ордера
Открытых ордеров нет
buy 0.00041444095207915246 12064.444826014851
Выход, не хватает денег на создание ордера

но на счету 58$ этого по идее более чем.
Бот же хочет открывать ордера на ~5$
В ручную на бирже я без проблем купил: 0.00041444095207915246 btc
Код не изменял (кроме API_KEY и API_SECRET) все 58$ лежат в USD.
Подскажите что я делаю не так?
05.09.2019 16:54
Нужно в боте заменить CAN_SPEND с 5 долларов на то другое :)
23.10.2019 13:06
Здравствуйте, Андрей. Начал тестировать бота на паре ETH/USD ( CURRENCY_1 = 'ETH' CURRENCY_2 = 'USD' ) . Выставил CAN_SPEND = 10 . Бот сделал закупку ETH на 10$ . А на продажу выставил ETH на ~3$ . Подскажите пожалуйста, как сделать, чтобы бот после закупки, выставлял на продажу весь закупленный ETH (весь баланс ETH) ?
10.11.2019 09:30
Он так и должен делать, возможно между покупкой и продажей произошли какие-то события, которые изменили баланс ETH? Может там лишние монеты были или что-то в этом роде?
20.11.2019 17:30
Привет Андрей .Бот работает. Спасибо. Играю на паре Волны/Рубль
Один вопрос
Если комиссия биржи со зделки
STOCK_FEE = 0.002 # Комиссия, которую берет биржа (0.002 = 0.2%)
То профит стоит такой
PROFIT_MARKUP = 0.001 # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
Это получается в минус идем?
25.11.2019 07:54
Нет, это значит что при покупке и продаже комиссии будут добавляться к цене или исключаться из неё, и итоговый профит после вычета всех комиссий биржи составит 0.1%
22.11.2019 08:29
Здравствуйте!
Тоже вот решил попробовать бота. Для начала самого Вашего простого.
Что-то ругается у меня на все комментарии.
Удалил их.
Теперь начал ругаться на любой русский текст.
Приходится на английский переводить.
Из за чего это?
25.11.2019 07:56
Что то вы как то не так запускаете.
Создайте просто новый файл, откройте в блокноте.
Скопируйте туда весь код со статьи, с комментариями и т.п.
Сохраните.
Теперь в Idle откройте этот файл File->Open и запустите (F5)
22.11.2019 08:45
Версия питона у меня 3.8.0 64 разрядная. Это нормально?
25.11.2019 07:56
Вполне
26.11.2019 12:24
Просто у меня бот был не в кодировке UTF-8 записан.
Скопировал, вставил текст в блокнот, запустил, всё заработало.
Спасибо.
18.12.2019 12:11
Спасибо, за Вашего бота! Правда, не могу понять почему, но он всегда торгует в минус( Возможно, сказывается крайняя степень фин.безграмотности, но при паре ETH/USD, в итоге с каждым "кругом" покупка-продажа, баланс USD только тает) Играюсь с 5ю USD.
18.12.2019 12:14
Пробовал различные варианты, ставки профита, использование не среднего по сделкам, а первого или последнего. Как-то не идёть) Полагаю, есть нюансы, которые я не вижу/упускаю. Был бы очень благодарен, если у вас найдется время указать ошибку, если она очевидна, разумеется)
19.12.2019 10:07
Пардон, ошибка. Я вашего бота переписал на другую платформу и это мой результат был отрицательным. Ваш работает как надо. Буду искать у себя ошибку. Извиняюсь.
27.04.2020 20:27
Здравствуйте, после обновления апи на бирже, бот перестал торговать, очень прошу помогите исправить код бота
sell 0.47904 5.04507 10.531625751503006
Error 50381: More than 8 decimal places are not permitted for pair USDT_UAH
Открытых ордеров нет
28.04.2020 10:28
такая же проблема.

Открытых ордеров нет
buy 0.0019379970915108 7739.949696367441
Error 50381: More than 8 decimal places are not permitted for pair BTC_USD
30.04.2020 09:32
Здравствуйте Андрей. Ваш бот работает хорошо, большое спасибо! Но exmo.com с 13 мая вводит новые правила : Начиная с 13 мая 2020 года на бирже EXMO будет действовать новое правило ценообразования для ордеров, размещаемых по некоторым парам с биткоином: BTC / USD, BTC / EUR, BTC / RUB, BTC / UAH, BTC / PLN, BTC / KZT, BTC / USDT. Теперь трейдеры могут использовать в цене не более 2 знаков после запятой.


Чтобы протестировать обновление, мы уже ввели ограничение на 2 пары: BTC / GBP и BTC / TRY.


Следующее обновление необходимо для пользователей, которые работают с exchange через API. При размещении заказа с более чем 2 символами будет выведена ошибка:

Ошибка 50381: более 2 десятичных знаков не допускаются для пары BTC_USD , подскажите пожалуйста куда и как внести поправки в скрипт бота? Большое спасибо!!!
01.05.2020 17:06
разобрался с ошибкой 50381 по поводу 8 знаков после запятой, нужно добавить пару строк в этот кусок кода:
# купить больше, потому что биржа потом заберет кусок
                        my_need_price = avg_price - avg_price * (STOCK_FEE+PROFIT_MARKUP)
                        my_need_price = round(my_need_price, 8)

                        my_amount = CAN_SPEND/my_need_price
                        my_amount = round(my_amount, 8)

и немного изменить вот здесь:
 print('sell', balances[CURRENCY_1],  wanna_get, (round((wanna_get/float (balances[CURRENCY_1])),8)))
                
                new_order = call_api(
                                        
                    'order_create',
                
                    pair=CURRENT_PAIR,
                     quantity = balances[CURRENCY_1],
                     
                    price=(round((wanna_get/float (balances[CURRENCY_1])),8)),
                    

                       
                               type='sell',

восьмерки это сколько знаков после запятой, думаю что после 13 мая тоже будет работать если поменять на 2.
PS. в программировании я 0, две бесоные ночи провел чтоб победить эту ошибку)))
27.06.2020 12:30
В код бота внесены изменения, что бы работать с кол-вом знаков после запятой, а так же проверка на выставление ордера при первом запуске бота.
Можно скачивать новую версию и пользоваться.
20.07.2020 14:47
Добрый день, Андрей

Реально ли и насколько сложно будет самому переписать вашего бота для торговли на другой бирже?
И если реально, то на что стоит обратить внимание.
Заранее спасибо
28.07.2020 14:27
Добрый день,

Конечно реально, посмотрите ссылки под статьей на другие статьи цикла, там есть и другие боты для других бирж, можете взять за основу. На каждой бирже все по разному, везде будут свои тонкости
23.02.2021 10:00
можно ли сделать отмену ордера не по времени а допустим по удалению цены от ордера???
27.03.2021 12:35
появилась ошибка "Expecting value: line 1 column 1 (char 0), код не менялся, в интернете нашёл что возможно что тоо с кодировкой utf-8, что это может быть? на эксмо недавно техработы были
Пожалуйста, Авторизуйтесь что бы оставить свой комментарий