Обновленный бот для Exmo

Добрый день.

Пытаюсь разобраться в чем различие в логике между ботом для Bittrex и Exmo (оба с подключенным MACD).

Первый упрощенный, но пока есть возможность потесить только его. На Битрексе закрыта регистрация. 

Первое, что заметил, это разница в проверке момента выхода на продажу, для первого бота (Эксмо)

BEAR_PERC = 70
BULL_PERC = 30

для второго бота (Битрекс)

BEAR_PERC = 70
BULL_PERC = 98

Но я так понял, что есть еще вторая часть изменений, когда берется минимальная цена покупки?

Или для обоих ботов алгоритм выбора цены покупки одинаков?

И еще вопрос, во втором боте (Битрекс) берется минимальный профит (0,1%) и, если есть такая возможность, продажа по максимальной цене, верно?

Можно ли эту часть кода прикрутить к первому боту?

Ну и вопрос по доп модификациям.

Прочитал вашу статью по стоп-лоссам. Понял, что при работе с криптовалютой вы к ним не очень хорошо относитесь.

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

Может изобретаю велосипед.. и это и так реализовано в вашем механизме при использовании МАСД, но тем не менее вопрос заинтересовал.

Спасибо за бота, что уже выложен.

 

 

 

16.01.2018 13:42:49

Добрый день!

Алгоритм покупки у всех местных ботов с macd одинаковый, но алгоритм выхода из торгов отличается. У того бота для эксмо, что выкладывал я, ордер выставляется после покупки с наценкой, и на этом всё.

Но умельцы на сайте сделали бота который как для биттрекса, но для Эксмо - т.е. прикрутили торговлю по нескольким парам, выход при цене побольше, и т.п. Спасибо им за это)

Вот код:

import time
import json
import requests
import urllib, http.client
import hmac, hashlib
 
# Если нет нужных пакетов - читаем тут: https://bablofil.ru/python-indicators/
import numpy 
import talib 
 
from datetime import datetime
 
# ключи API, которые предоставила exmo
API_KEY = 'K-            кей'
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b'S-секрет'
 
# Список пар, на которые торгуем
MARKETS = [
    'BCH_USD', 'ETC_USD', 'ETH_USD',
    'ZEC_USD', 'DASH_USD' 
]
 
CAN_SPEND = 20 # Сколько 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.9  # % что считаем поворотом при быке
 
#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']
                    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)
            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)

Стоп-лосс, о котором вы говорите, вещь хорошая, называется trailng stop, но тут его нет. В принципе все можно прикрутить, было бы время)
 

ПроголосоватьПроголосовать
3 0
17.01.2018 11:44:11

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

ПроголосоватьПроголосовать
0 0
18.01.2018 11:50:58

Добрый день. Еще вопрос. По выложенному скрипту. Переделала его на пары работающие с рублем, поменял только два параметра, собствено сами пары и увеличил спред до 1200 руб. (примерно 20$). Почему-то за 5 дней не было ни одной сделки. Или он настолько осторозный? или это такая редкая комбинация при торгах?

ПроголосоватьПроголосовать
1 0
22.01.2018 08:48:05
Всем привет, СПАСИБО за скрипт, если не сложно, растолкуйте эти значения 
BEAR_PERC = 70 
BULL_PERC = 99.9

СПАСИБО

ПроголосоватьПроголосовать
0 0
24.01.2018 04:04:00

Тут, бот торгует с тех пор, кока линии тренда долгосрочного и краткосрочного пересеклись и начался подьем тренда вверх, именно поэтому выставлено 99,9 процента (т.е. сразу после точки пересечения трентовых линий большего и меньшего периодов). А вот первая переменная говорит о том, что можешь держать ордер до тех пор, пока тренд снижения не скатился более чем на семдесят процентов от максимум (100). 

По идее все верно. Он покупает ордер в первое мгновение (торитически мин цена) и продает его в тот момент, когда проскочили максимум (так же теоретически цена ордера близка к максимальной).

 

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

import numpy
import talib
import requests
import json
import time

from matplotlib.finance import candlestick2_ohlc
import matplotlib.animation as animation

import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from datetime import datetime

BEAR_PERC = 70
BULL_PERC = 98

PERIOD = 5 # Период в минутах для построения свечей

# Список пар, на которые торгуем

       
PAIR = 'BTC_RUB'
#PAIR = 'BCH_RUB'
#PAIR = 'ETC_RUB'
#PAIR = 'ETH_RUB'
#PAIR = 'ZEC_RUB'
#PAIR = 'DASH_RUB'
#PAIR = 'XRP_RUB'
#PAIR = 'WAVES_RUB'
#PAIR = 'LTC_RUB'
#PAIR = 'USD_RUB'

fig, ax = plt.subplots(3, sharex=True)
fig.comment = plt.figtext(.7,.05, '')


def update_graph(interval):


    resource = requests.get('https://api.exmo.com/v1/trades/?pair=%s&limit=10000' % PAIR)
    data = json.loads(resource.text)

    chart_data = {} # сформируем словарь с ценой закрытия по PERIOD минут
    
    for item in reversed(data[PAIR]):
        d = int(float(item['date'])/(PERIOD*60))*(PERIOD*60) # Округляем время сделки до PERIOD минут
        if not d in chart_data:
            chart_data[d] = {'open':0, 'close':0, 'high':0, 'low':0}

        chart_data[d]['close'] = float(item['price'])

        if not chart_data[d]['open']:
            chart_data[d]['open'] = float(item['price'])

        if not chart_data[d]['high'] or chart_data[d]['high'] < float(item['price']):
            chart_data[d]['high'] = float(item['price'])

        if not chart_data[d]['low'] or chart_data[d]['low'] > float(item['price']):
            chart_data[d]['low'] = float(item['price'])
        

    quotes = {}
    quotes['open']=numpy.asarray([chart_data[item]['open'] for item in sorted(chart_data)])
    quotes['close']=numpy.asarray([chart_data[item]['close'] for item in sorted(chart_data)])
    quotes['high']=numpy.asarray([chart_data[item]['high'] for item in sorted(chart_data)])
    quotes['low']=numpy.asarray([chart_data[item]['low'] for item in sorted(chart_data)])

    xdate=[datetime.fromtimestamp(item) for item in sorted(chart_data)]

    ax[0].xaxis.set_major_locator(ticker.MaxNLocator(6))

    def chart_date(x,pos):
        try:
            return xdate[int(x)]
        except IndexError:
            return ''
        
    ax[0].clear()
    ax[0].xaxis.set_major_formatter(ticker.FuncFormatter(chart_date))
    
    candlestick2_ohlc(ax[0], quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6)
    
    fig.autofmt_xdate()
    fig.tight_layout()

    macd, macdsignal, macdhist = talib.MACD(quotes['close'], fastperiod=12, slowperiod=26, signalperiod=9)
    ax[1].clear()
    ax[1].plot(macd, color="y")
    ax[1].plot(macdsignal)

    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)
    ax[1].plot(inters, 'ro')

    max_v = 0

    for offset, elem in enumerate(macdhist):
        activity_time = 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
            activity_time = True
        else:
            v = 0
            
        if offset in idx and not numpy.isnan(elem):
            # тренд изменился
            max_v = curr_v = 0 # обнуляем пик спреда между линиями

    ax[2].fill_between([x for x in range(len(macdhist))], 0,macdhist,  facecolor='gray', interpolate=True)
    plt.gcf().texts.remove(fig.comment)
    fig.comment = plt.figtext(.6,.05, '%s %s%s' % (PAIR, time.ctime(), ' ТОРГУЕМ!!!! ' if activity_time else ''), style='italic', bbox={'facecolor':'red' if activity_time else 'green', 'alpha':0.5, 'pad':10})
    
ani = animation.FuncAnimation(fig, update_graph, interval=1000)
plt.show()

 

Возможно, просто еще что-то не учитывается? Или в выложенный скрипт закралась ошибка?

 

ПроголосоватьПроголосовать
1 0
24.01.2018 10:26:36

Его проверяли в работе?

ПроголосоватьПроголосовать
0 0
24.01.2018 10:28:08

Да, и простите за ошибки в тексте. Отвлекают.

ПроголосоватьПроголосовать
1 0
24.01.2018 10:28:31

Благодарю за ответ!

 

А скрипт или не работает или одно из двух...) Уже 4ый день " Продавать нельзя, т.к. ситуация на рынке неподходящая: Трэнд BEAR; Рост False"

может есть какие нить мысли?

ПроголосоватьПроголосовать
0 0
25.01.2018 03:28:05

Согласен, не работает бот. "Условия рынка не подходят для торговли {'trand': 'BEAR', 'growing': False}", постоянно, на любой паре.

ПроголосоватьПроголосовать
0 0
25.01.2018 03:59:13

Хотя вот на этом участке тренд явно не медвежий. 

ПроголосоватьПроголосовать
0 0
25.01.2018 04:01:28

Похоже, что не работает... хотя должен был по идее... где-то в теле ошибка, которая не дает правильно оценить рынок... и всегда выходит условие - ложь...

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

ПроголосоватьПроголосовать
0 0
25.01.2018 04:32:16

Ой вей, одна опечатка при выгрузке кода, а какие последствия )

Обновил код в своем ответе выше, сейчас тестирую - покупка прошла, проверю заодно продажу.

И обратите внимание на этот параметр:

PERIOD = 5 - значит брать сделки в свече за 5 минут, а на графиках Эксмо - 30. 

С одной стороны, это добавляет боту гибкости, а с другой - MACD рассчитан на более длительные периоды,  так что может чаще ошибаться. Думаю, для пар, у которых одна сделка в две минуты (типа DOGE) стоит ставить интервал немного подольше

ПроголосоватьПроголосовать
0 0
25.01.2018 11:20:35
Всем привет, СПАСИБО за скрипт, если не сложно, растолкуйте эти значения 
BEAR_PERC = 70 
BULL_PERC = 99.9

Добрый день. В этой статье я расписывал эти параметры с картинками. Если вкратце, то первый отвечает за покупку на медвежьем рынке (в конце падения и начале подъема), а второй за продажу на бычьем (в процессе роста, до начала падения)

ПроголосоватьПроголосовать
0 0
25.01.2018 12:14:26

Андрей, спасибо большое. А не могли бы вы показать и объяснить, в чем была ошибка? Как тест продажи прошёл? 

ПроголосоватьПроголосовать
1 0
25.01.2018 14:31:16

"'

Ой вей, одна опечатка при выгрузке кода, а какие последствия )

Обновил код в своем ответе выше, сейчас тестирую - покупка прошла, проверю заодно продажу.

"

а в каком именно ответе?

Спасибо

ПроголосоватьПроголосовать
0 0
26.01.2018 04:33:51

а в каком именно ответе?

Спасибо

Во втором сверху, где код выложен)

Ошибка была в строке 

resource = requests.get('https://api.exmo.me/v1/trades/?pair=%s&limit=10000' % pair)

был лишний символ в адресе.

По итогам теста бот покупает и продает, сделок мало, но и рынок в целом падает

На всякий случай, напоминаю, что есть и другие боты для эксмо, попроще - один и два

 

ПроголосоватьПроголосовать
1 0
26.01.2018 08:24:35

stranno vrode takaya je stroka

 

ПроголосоватьПроголосовать
0 0
26.01.2018 13:53:38

Prishol s raBOTI, nashol raznicu!))) Spasibo eshe raz Андрей К.!!, Pishem otzivi o rabote!!!!

ПроголосоватьПроголосовать
0 0
27.01.2018 05:07:45

Продавать нельзя, т.к. ситуация на рынке неподходящая: Трэнд BEAR; Рост True

2018-01-26 23:11:04.274217   BTC_USD  Обработка...

Продавать нельзя, т.к. ситуация на рынке неподходящая: Трэнд BULL; Рост True

2018-01-26 23:12:11.776627   BCH_USD  Обработка...

 

Chtoto MEnya eti PREDUPREJDENIYA kak to zaputali.. . a kogdaj situaciya pothodyashaya!?

ПроголосоватьПроголосовать
0 0
27.01.2018 05:13:48

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

ПроголосоватьПроголосовать
0 0
27.01.2018 09:36:28

Пошоркал программу своим напильником, для выставления ордера на покупку нужно было в 159 строке написать bid вместо ask, а для того чтобы он выставлял самую выгодную цену в стакане, вместо взятия средней цены из 3х первых беру самое выгодное предложение и перебиваю его прибавлением 0,0000001. Вот что вышло:

current_rate = sum([float(item[0]) for item in offers['bid'][:1]])+0.0000001 # покупка по самой выгодной цене в стакане

Кроме этого в алгоритме на отмену ордера покупки, при истечении времени была ошибка, стояла не заданная ничем переменная  STOCK_TIME_OFFSET. Строка 264, исправил на:

time_passed = time.time() - int(order['created'])

 

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

 

ПроголосоватьПроголосовать
1 0
27.01.2018 19:20:34

Продавать нельзя, т.к. ситуация на рынке неподходящая: Трэнд BEAR; Рост True

2018-01-26 23:11:04.274217   BTC_USD  Обработка...

Продавать нельзя, т.к. ситуация на рынке неподходящая: Трэнд BULL; Рост True

2018-01-26 23:12:11.776627   BCH_USD  Обработка...

Chtoto MEnya eti PREDUPREJDENIYA kak to zaputali.. . a kogdaj situaciya pothodyashaya!?

Продавать нельзя, т.к. рынок еще в медвежьей фазе, но растет - так что выгоднее продать позже.

Продавать нельзя, т.к. рынок в бычьей фазе, и все еще растет, но пока что не достиг пика, бот попробует продать позже. 

ПроголосоватьПроголосовать
0 0
29.01.2018 14:48:48

Здравствуйте Андрей.

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

Спасибо Вам за труд и затраченное время на просвещение непросвещенных.

Смотрел коды простых ботов для EXMO и WEX. В первом случае Вы при создании ордера на покупку берете среднюю цену по последним совершенным сделкам, а во втором - берете записи из стакана (как я понял "Ордера на покупку"). Если параметр OFFERS_AMOUNT = 1, то берется текущая лучшая цена (видимо первая строка в стакане, или я не прав?). Если это так, то я хочу попробовать изменить код простого бота EXMO как у бота WEX, то есть чтобы на EXMO бот тоже брал данные из верхней строки стакана "Ордера на покупку". Скорее всего не смогу, но хочу попробовать.

Если Вы планируете нечто подобное, то было бы хорошо.

Смотрел предложения Ильи Ч. по обновленному боту для EXMO. Попробовал модифицировать код по его предложениям, но ничего не вышло. В чем у него ошибки? Было бы интересно узнать Ваше мнение.

Спасибо. С уважением, Валерий.

P.S. Обращаюсь к Илье Ч. Илья если не трудно выложи исправленный тобой код, если можно с пояснениями. Интересно. Спасибо.

ПроголосоватьПроголосовать
0 0
29.01.2018 22:58:16

Вот мой код, потестировал на двух парах BTC_USD и ETH_USD, работает. Все пояснения в предпоследнем посте.

 

import time
import json
import requests
import urllib, http.client
import hmac, hashlib
 
# Если нет нужных пакетов - читаем тут: https://bablofil.ru/python-indicators/
import numpy 
import talib 
 
from datetime import datetime
 
# ключи API, которые предоставила exmo
API_KEY = 'K-'
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b'S-'
 
# Список пар, на которые торгуем
MARKETS = [
    'BTC_USD', 'ETH_USD'
]
 
CAN_SPEND = 25 # Сколько 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.9  # % что считаем поворотом при быке
 
#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['bid'][0][0]) # покупка по лучшей цене
        current_rate = sum([float(item[0]) for item in offers['bid'][:1]])+0.0000001 # покупка по самой выгодной цене в стакане
        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() - 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']
                    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)
            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)

 

ПроголосоватьПроголосовать
2 0
30.01.2018 07:59:46

Последний, это какой?

ПроголосоватьПроголосовать
0 0
30.01.2018 18:31:31

Здравствуй, Илья.

Инфа из лога:

2018-02-01 01:31:06.995040 LTC_BTC 
    Итого на этот ордер было потрачено 0.05017500 L, получено 0.06839205 T
    Что бы выйти в плюс, необходимо продать купленную валюту по курсу 0.73510812
    Тогда, после вычета комиссии 0.0020 останется сумма 0.05017500 L
    Итоговая прибыль составит 0.00000000 L
    Текущий курс продажи 0.01593250
    Создаю ордер на продажу по курсу 0.73510812

Не знаю как здесь скрин exmo прикрепить но откуда такой курс?

 

ПроголосоватьПроголосовать
0 0
31.01.2018 22:54:06

Добрый день. Андрей, а можете прикрутить к боту такую функцию, чтобы он продавал с прибылью в 0 при простое лота более, ну, скажем получаса- часа или указанного времени?

Вот зачем это надо

Бот был запущен в ночь и получилась такая картина (USD_RUB):

1. он поставил в левый стакан по 1-й строке и продал всё что всё было из USD (стоимость 54,53)

2.. он подождал, видимо начала роста и, поставив в правый стакан, купил USD (стоимость 54,88)

3. бот купил по указанной стоимости USD и выставил продавать по 55,26

минимальный суточный курс при начале торгов 24,02, максимальный 55,2.

Это всё произошло достаточно быстро, но после последней ставки прошло уже более 8 часов. 

Странным мне кажется то, что он пытался продать по курсу выше суточного. Этого не должно быть.

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

Огромное СПАСИБО Андрею и Илье за проделанную работу ребята - вы молодцы.  

ПроголосоватьПроголосовать
1 0
10.02.2018 07:26:43

здравствуйте. бот для битрикса перестал совершать операции. хотя на счету 18 криптодолларов. уже 2 дня висит просто так. пишет что условия рынка не подходят. или пишет по английски. что минимальные требования не соблюдены. как решить проблему?

ПроголосоватьПроголосовать
0 0
14.02.2018 06:30:35

Скажите, а нет ли случайно бота с такой логикой для полоникса? Может кто то уже реализовал?

 

ПроголосоватьПроголосовать
0 0
14.02.2018 19:18:56

Есть, вот тут подробнее https://bablofil.ru/macd-python-stock-bot/

Прямая ссылка https://bablofil.ru/static/macd_bots/poloniex_macd.py

ПроголосоватьПроголосовать
0 0
15.02.2018 08:18:47

Андрей, интересен бот с плавающей ценой при продаже на бирже полоникс.

Может есть?

ПроголосоватьПроголосовать
0 0
15.02.2018 14:23:51

Всего доброго всем!

Будьте внимательны!!!! Скрипт Илья Ч. 30.01.2018 07:59:46 содержит опасный код, который всю вашу криптовалюту спустит в одну секунду, когда он доберется до: "Для выполненного ордера на покупку выставляем ордер на продажу" . Сколько и по какой цене отработает:   create_sell(pair=pair). Код в сдудию!!!!!

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('Продавать нельзя, т.к. ситуация на рынке неподходящая: Трэнд '+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)

ПроголосоватьПроголосовать
0 0
17.02.2018 17:07:15

Если торугете LTC_USD,  например, то LTC на старте не должно быть на балансе. Бот сам купит сколько надо LTC и потом продаст все монетки, в ноль. В данном случае, как я понимаю, у вас уже были какие-то монетки на балансе, и бот их продал, полагая что это он их и купил.

ПроголосоватьПроголосовать
0 0
18.02.2018 07:14:52

" Илья Ч. 30.01.2018 07:59:46 содержит опасный код " - c чего вы взяли?

ПроголосоватьПроголосовать
0 0
18.02.2018 14:57:09
import time
import json
import requests
import urllib, http.client
import hmac, hashlib

# Если нет нужных пакетов - читаем тут: https://bablofil.ru/python-indicators/
import numpy
import talib

from datetime import datetime

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

# Список пар, на которые торгуем
MARKETS = [
    'BTC_USD', 'ETH_USD', 'ETC_USD'
]

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

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

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

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

# 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['bid'][0][0]) # покупка по лучшей цене
        current_rate = sum(
            [float(item[0]) for item in offers['bid'][:1]]) + 0.0000001  # покупка по самой выгодной цене в стакане
        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() - 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']
                    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)
            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)

 

кто -нибудь нашел какие либо косяки обоснованные ? Запустил его, вроде работает, покупает и продает, только вот очень долго он это делает.

ПроголосоватьПроголосовать
0 0
18.02.2018 14:59:54

очень странная продажа

Итого на этот ордер было потрачено 40.12000000 B, получено 0.00445490 T
    Что бы выйти в плюс, необходимо продать купленную валюту по курсу 9023.86154607
    Тогда, после вычета комиссии 0.0020 останется сумма 40.12000000 B
    Итоговая прибыль составит 0.00000000 B
    Текущий курс продажи 10975.00000000
    Создаю ордер на продажу по курсу 10975.00000000

т.е.. в результате прибыль 0.00000000

ПроголосоватьПроголосовать
2 0
18.02.2018 15:15:43

доброго дня!

тестировал бота из второго поста.

сегодня купил ниже минимальной в паре BTC-USD= 0.00099879

ПроголосоватьПроголосовать
0 0
21.02.2018 03:31:29

Скажите пожалуйста, а "CAN_SPEND = 25 # Сколько USD готовы вложить в бай" это значит, что он будет вкладывать 25 USD  в каждую пару или во все пары вместе взятые?

И ещё, как можно сделать, чтобы он делал не 1 ставку на указанную сумму в указанной паре, а больше?

ПроголосоватьПроголосовать
0 0
21.02.2018 15:31:35

Мальчики, всех с праздником ;)

ПроголосоватьПроголосовать
0 0
23.02.2018 07:16:22

спасибо! сопозданием слегка прочитано

ПроголосоватьПроголосовать
0 0
24.02.2018 16:46:40

Девочки, любите мальчиков! Тут что то как то?

ПроголосоватьПроголосовать
0 0
26.02.2018 06:03:16
#работает import time import json import requests import urllib, http.client import hmac, hashlib # Если нет нужных пакетов - читаем тут: https://bablofil.ru/python-indicators/ import numpy import talib from datetime import datetime # ключи API, которые предоставила exmo API_KEY = '' # обратите внимание, что добавлена 'b' перед строкой API_SECRET = b'' # Список пар, на которые торгуем MARKETS = [ #'ETC_USD' , 'LTC_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.9 # % что считаем поворотом при быке #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 USE_LOG=True # Выводит всякую информацию на экран, самое важное скидывает в Файл 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) # все обращения к 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 # покупка по средней цене из трех лучших в стакане current_rate = sum([float(item[0]) for item in offers['bid'][:1]])+0.0000001 # покупка по самой выгодной цене в стакане (покупки) 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): current_rate = 0 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['ask'][0][0]) # Берем верхнюю цену, по которой кто-то покупает (изменил на ask) 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']) time_passed = time.time() - 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'] 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) 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)
ПроголосоватьПроголосовать
0 0
26.02.2018 06:08:45

А если за неделю загрузить?

ПроголосоватьПроголосовать
0 0
26.02.2018 06:11:34

Тут можно прицепить файлик?

ПроголосоватьПроголосовать
0 0
26.02.2018 08:04:54

Немного о stop loss, здесь не форекс а криптовалютная биржа т.е по какой цене бот выставил ордер на продажу по такой он и будет  висеть пока не сработает, а с stop  loss он будет торговать заведомо с убытком. Я предлагаю другой вариант развития событий, если ордер не исполнился то при сигнале macd на sell ордер отменяется, а при сигнале на bay бот по новому закупается и выстовляет новый ордер на продажу

ПроголосоватьПроголосовать
0 0
26.02.2018 08:11:17

Может быть соберемся на канале дружно и будет создавать вместе рабочий бот? Предлагать идеи и пробовать их реализовать. Создать я предлагаю этот канал "Андрей К" - создателю этого бота, и организовывать и вносить изменения то же ем. Сделать в телеграмме прикрепленный файл .py и обновлять его по мере обновления. Так будет проще и удобней, думаю все были бы в этом заинтересованы. Это лучше чем каждый раз обновлять форум. Мне интересна эта тема, думаю что можно всетаки придумать что то рабочее и прибыльное вместе. 

ПроголосоватьПроголосовать
2 0
26.02.2018 12:02:42

А рассказать народу о новом?

ПроголосоватьПроголосовать
0 0
26.02.2018 12:32:46

Ловим LTC

ПроголосоватьПроголосовать
0 0
26.02.2018 12:33:47
import httplib
  import urllib
  import json
  import hashlib
  import hmac
  import time
   
  api_key = "your_key"
  api_secret = "your_secret"
   
  nonce = int(round(time.time()*1000))
   
  params = {"nonce": nonce}
  params = urllib.urlencode(params)
   
  H = hmac.new(api_secret, digestmod=hashlib.sha512)
  H.update(params)
  sign = H.hexdigest()
   
  headers = {"Content-type": "application/x-www-form-urlencoded",
  "Key":api_key,
  "Sign":sign}
  conn = httplib.HTTPSConnection("api.exmo.com")
  conn.request("POST", "/v1/user_info", params, headers)
  response = conn.getresponse()
   
  print response.status, response.reason
  print json.load(response)
   
  conn.close()
ПроголосоватьПроголосовать
0 0
26.02.2018 12:36:27

А как в телеграмме?

ПроголосоватьПроголосовать
0 0
26.02.2018 12:38:11

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

ПроголосоватьПроголосовать
0 0
26.02.2018 18:41:46

https://t.me/bablofil_gr01 и так, вот и группа. Заходим и не стесняемся.

ПроголосоватьПроголосовать
0 0
26.02.2018 21:05:06

Анжелика, извиняюсь, но правильнее было бы еслиб создал группу Андрей, ведь "Баблофил" его идея

ПроголосоватьПроголосовать
0 0
27.02.2018 18:00:18

о увидел. там есть сам Андрей)

ПроголосоватьПроголосовать
0 0
27.02.2018 18:17:28

А кто-нибудь уже прикрутил бот к битфинексу? можете поделиться кодом авторизации?

ПроголосоватьПроголосовать
0 0
27.02.2018 21:02:20

Александр С., а что это за группа в телеграме? Не могли бы Вы поделиться? Буду Вам очень признателен!

ПроголосоватьПроголосовать
0 0
01.03.2018 10:45:12

Доброго времени суток, всем! Меня заинтересовал данный форум. К сожалению я, так же, как и один из участников форума, 0 в программировании. У меня вопрос, можно ли установить этот бот, с учетом всех доработок, какие внесли участники форума, дистанционно? 

ПроголосоватьПроголосовать
0 0
01.03.2018 13:38:38

Влад М. выше на несколько сток написано. Анжелика писала

ПроголосоватьПроголосовать
0 0
01.03.2018 19:27:15

Александр С., вы говорили про некую группу, которая состоит из 600 человек и занимается доработкой бота для бинанса. Меня она интересовала..

ПроголосоватьПроголосовать
0 0
02.03.2018 10:35:07

Здравствуйте! Андрей К. Дайте пожалуйста рабочий код со всеми исправлениями плиз!!! Я не програмист. Ну очень это все интересно.!!! Максимум моих познаний это изменить значения торговые и протестить. Тоесть допилить с точки зрения торговли. Ну вот беда с программирыванием. Все скачал установил Пейтон. код вставил только не поиму работает или нет.!? Или что то исправить надо. За ранее спасибо!

ПроголосоватьПроголосовать
0 0
27.03.2018 15:39:25

Андрей, добрый день!

Спасибо за блог!

Не подскажите, а на криптобиржах не запрещен внутрибиржевый синт. арбитраж? Заблокировать могут за это?

ПроголосоватьПроголосовать
0 0
20.04.2018 09:47:21

На работу не влияет (хоть горшком обозвать). Но как то не красиво  и на будущее будет путаница, если покупать то buy:

                    opened_orders = []
                sell_orders buy_orders = []
................................................................
.................................................................
                # Запоминаем ордера на покупку CURRENCY_1
                        sell_ordersbuy_orders.append(order)
                # Проверяем, есть ли открытые ордера на покупку CURRENCY_1
                if sell_orders buy_orders:  # открытые ордера есть
                    for order in sell_orders buy_orders:

И еще некоторые вещи из области мометум индикаторов (MACD  в том числе). Обратите внимание на

PERIOD = ???  # Период в минутах для построения свечей

Чтоб с ним поиграть поробуйте это

import time
import json
import requests
import urllib, http.client
import hmac, hashlib

# Если нет нужных пакетов - читаем тут: https://bablofil.ru/python-indicators/
import numpy
import talib

from datetime import datetime

# ключи API, которые предоставила exmo
API_KEY =  'K-'
API_SECRET = b('S-')

# Список пар, на которые торгуем
MARKETS = [
    'ETH_USD',
]
#'BTC_USD','ETC_USD'
CAN_SPEND = 14  # Сколько USD готовы вложить в бай
MARKUP = 0.0045  # 0.001 = 0.1% - Какой навар со сделки хотим получать

STOCK_FEE = 0.002  # Какую комиссию берет биржа
PERIOD = 5  # Период в минутах для построения свечей. Меняем на 10, 15, 30, 60... 240, смотрим результат и график на https://bitcoinwisdom.io/markets/bitfinex/ethusd с нашим индикатором
ORDER_LIFE_TIME = 3  # Через сколько минут отменять неисполненный ордер на покупку 0.5 = 30 сек.

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

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

# 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['bid'][0][0]) # покупка по лучшей цене
        current_rate = sum([float(item[0]) for item in offers['bid'][:1]])+0.0000001 # покупка по самой выгодной цене в стакане
        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 = []
                buy_orders = []
                # Есть ли неисполненные ордера на продажу CURRENCY_1?
                log(pair, " Обработка...")
                for order in opened_orders:
                    if order['type'] == 'sell':
                        # Есть неисполненные ордера на продажу CURRENCY_1, выход
                        raise ScriptQuitCondition('Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)')
                        # пропуск продажи
                        # pass
                    else:
                        # Запоминаем ордера на покупку CURRENCY_1
                        buy_orders.append(order)
                # Проверяем, есть ли открытые ордера на покупку CURRENCY_1
                if buy_orders: # открытые ордера есть
                    for order in buy_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() - 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']
                    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)
            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:
    

 

ПроголосоватьПроголосовать
0 0
12.05.2018 14:02:51

Ужас прицепил не тот код

Замените эту часть 

# Список пар, на которые торгуем
MARKETS = [
'ETH_USD','BTC_USD','ETC_USD',
]
#,'BTC_USD','ETC_USD'
CAN_SPEND = 12  # Сколько USD готовы вложить в бай
MARKUP = 0.0045  # 0.001 = 0.1% - Какой навар со сделки хотим получать

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

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

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

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

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

USE_LOG = True
DEBUG = True  # 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['bid'][0][0]) # покупка по лучшей цене
        current_rate = sum([float(item[0]) for item in offers['bid'][:1]])+0.0000001 # покупка по самой выгодной цене в стакане
        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:
                opened_orders = []
                sell_orders = []

            # Получаем список активных ордеров
                try:
                    time.sleep(1)
                    #print('Получаем список активных ордеров')
                    log('Получаем список активных ордеров')
                    opened_orders = call_api('user_open_orders')[pair]
                except KeyError:
                    if DEBUG:
                        #print(pair, 'Открытых ордеров нет')
                        log(pair, "Открытых ордеров нет")
                # Есть ли неисполненные ордера на продажу CURRENCY_1?
                log(pair, " Обработка...")
                for order in opened_orders:
                    if order['type'] == 'sell':
                        #print('Есть неисполненные ордера на продажу CURRENCY_1, выход')
                        raise ScriptQuitCondition('Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)')
                        # пропуск продажи
                        #break
                    else:
                        # Запоминаем ордера на покупку CURRENCY_1
                        sell_orders.append(order)
            '''
            try:
                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(pair,'_Точка№1_Продавать нельзя, т.к. ситуация на рынке неподходящая: Трэнд :'+str(macd_advice['trand'])+'; Рост '+str(macd_advice['growing']))
                    log(pair,'_Точка№1_Продавать нельзя, т.к. ситуация на рынке неподходящая: Трэнд :'+str(macd_advice['trand'])+'; Рост '+str(macd_advice['growing']))
#                log(pair, '_Точка№1_Для ордера %s не создаем ордер на продажу, т.к. ситуация на рынке неподходящая' % order['oreder_id'] )

                else:
                    #print(pair,'_Точка№2_Выставляем ордер на продажу, т.к ситуация подходящая:Трэнд :'+str(macd_advice['trand'])+'; Рост '+str(macd_advice['growing']))
                    log(pair,'_Точка№2_Выставляем ордер на продажу, т.к ситуация подходящая: Трэнд :'+str(macd_advice['trand'])+'; Рост '+str(macd_advice['growing']))
                if macd_advice['trand'] == 'BEAR' and macd_advice['growing']:
                   #print(pair, "_Точка№3_Создаем ордер на покупку")
                   log(pair, "_Точка№3_Создаем ордер на покупку")

            except ScriptError as e:
                    print(e)
            except ScriptQuitCondition as e:
                print(e)
            except Exception as e:
                print("!!!!",e)

    except Exception as e:
        print(e)

ПроголосоватьПроголосовать
0 0
12.05.2018 14:09:08

Всем доброго времени суток. Подскажите ответ на этот вопрос ???? при запеске бота выдет вот такую ошибку....

 

Traceback (most recent call last):
  File "C:/Users/___/___/Local/Programs/Python/Python37-32/EXMO_bot_etc2.py", line 8, in <module>
    import numpy
ModuleNotFoundError: No module named 'numpy'

как её исправить, что нужно добавить ????

ПроголосоватьПроголосовать
0 0
21.08.2018 22:28:15

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

 

def myfloat(float_string):
    """It takes a float string ("1,23" or "1,234.567.890") and
converts it to floating point number (1.23 or 1.234567890).
"""
    float_string = str(float_string)
    errormsg = "ValueError: Input must be decimal or integer string"
    try:
        if float_string.count(".") == 1 and float_string.count(",") == 0:
            return float(float_string)
        else:
            midle_string = list(float_string)
            while midle_string.count(".") != 0:
                midle_string.remove(".")
            out_string = str.replace("".join(midle_string), ",", ".")
        return float(out_string)
    except ValueError, error:
        print "%s\n%s" %(errormsg, error)
        return None
ПроголосоватьПроголосовать
0 0
24.08.2018 18:07:04

pip install numpy
 

ПроголосоватьПроголосовать
0 0
04.09.2018 19:01:18

В интернете очень много плохих озывов о Exmo . Народкак рабоатаетет есть проблеммы с выводом денег?

ПроголосоватьПроголосовать
0 0
06.10.2018 12:48:54

Доброго времени суток! Собрал эго бота, сейчас отлаживаю . Хочу спросить можно ли его залить на DigitalOcean?

Простого бата залил по этой ссылке https://bablofil.ru/kak-zapustit-bota-na-servere/ , все получилось, работает. По такой же аналогии можно ?  Если не сложно обьясните пожалуйста.

ПроголосоватьПроголосовать
0 0
08.10.2018 17:17:31
Пожалуйста, авторизуйтесь, что бы ответить на вопрос