Прикручиваем индикатор к боту

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

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

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

Строим MACD и ставим задачу

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

import numpy
import talib
import requests
import json
import time

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

PAIR = 'BTC_ETH' # Пара, по которой работаем

start_time = time.time() - 15*60*60 # за какой период брать данные - 15 часов в данном случае

resource = requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999&period=300" % (PAIR, start_time))
data = json.loads(resource.text)

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

xdate=[datetime.datetime.fromtimestamp(item['date']) for item in data]

fig, ax = plt.subplots(3, sharex=True)

candlestick2_ohlc(ax[0], quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6)

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

def chart_date(x,pos):
    try:
        return xdate[int(x)]
    except IndexError:
        return ''

ax[0].xaxis.set_major_formatter(ticker.FuncFormatter(chart_date))

fig.autofmt_xdate()
fig.tight_layout()

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

plt.show()

После запуска получим примерно такую картину:

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

Обычно сигналом «Покупать» считают, когда скользящая с меньшим периодом (на рисунке синяя линия) в нижней зоне пересекает снизу вверх скользящую с бо́льшим периодом (красная линия). Сигналом «Продавать» считают, когда скользящая с меньшим периодом в верхней зоне пересекает сверху вниз скользящую с бо́льшим периодом.

Конечно, в жизни не все так просто – и сам по себе индикатор предназначен для недельных и месячных периодов, и объем влияет на принятие решений, и, по хорошему, надо заодно проверить еще пяток индикаторов… Но не будем заморачиваться! Мы хотим научиться понимать тенденцию рынка – давайте научимся.

Значит, первое, что нам нужно сделать, это найти пересечение линий на графике. Можно вспомнить курс математики, а можно воспользоваться возможностями библиотеки numpy – там уже кто-то всё вспомнил, запрограммировал и оптимизировал. Нам, по сути, нужно добавить в код пару строчек:

import numpy
import talib
import requests
import json
import time

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

PAIR = 'BTC_ETH' # Пара, по которой работаем

start_time = time.time() - 15*60*60 # за какой период брать данные - 15 часов в данном случае

resource = requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999&period=300" % (PAIR, start_time))
data = json.loads(resource.text)

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

xdate=[datetime.datetime.fromtimestamp(item['date']) for item in data]

fig, ax = plt.subplots(3, sharex=True)

candlestick2_ohlc(ax[0], quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6)

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

def chart_date(x,pos):
    try:
        return xdate[int(x)]
    except IndexError:
        return ''

ax[0].xaxis.set_major_formatter(ticker.FuncFormatter(chart_date))

fig.autofmt_xdate()
fig.tight_layout()

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

idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0
print(idx)

plt.show()

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

Эти цифры обозначают положение по оси X, в которых произошли пересечения. Давайте наложим их на график?

Еще немного меняем код:

import numpy
import talib
import requests
import json
import time

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

PAIR = 'BTC_ETH' # Пара, по которой работаем

start_time = time.time() - 15*60*60 # за какой период брать данные - 15 часов в данном случае

resource = requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999&period=300" % (PAIR, start_time))
data = json.loads(resource.text)

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

xdate=[datetime.datetime.fromtimestamp(item['date']) for item in data]

fig, ax = plt.subplots(3, sharex=True)

candlestick2_ohlc(ax[0], quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6)

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

def chart_date(x,pos):
    try:
        return xdate[int(x)]
    except IndexError:
        return ''

ax[0].xaxis.set_major_formatter(ticker.FuncFormatter(chart_date))

fig.autofmt_xdate()
fig.tight_layout()

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

idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0
print(idx)

inters = []

for offset, elem in enumerate(macd):
    if offset in idx:
        inters.append(elem)
    else:
        inters.append(numpy.nan)
ax[1].plot(inters, 'ro')

plt.show()

Запускаем, и видим, как на графике отображаются точки пересечения:

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

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

Как это работает?

Уберем (временно) все, что связано с кодом, и пристально взглянем на то, с чем работаем.

import numpy
import talib
import requests
import json
import time

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

PAIR = 'BTC_ETH' # Пара, по которой работаем

start_time = time.time() - 15*60*60 # за какой период брать данные - 15 часов в данном случае

resource = requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999&period=300" % (PAIR, start_time))
data = json.loads(resource.text)

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

macd, macdsignal, macdhist = talib.MACD(quotes['close'], fastperiod=12, slowperiod=26, signalperiod=9)

print('=====MACD=======', macd)
print('*'*80)

print('=====MACDSIGNAL=======', macdsignal)
print('*'*80)

idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0
print('======IDX=======',idx)
print('*'*80)

inters = []

for offset, elem in enumerate(macd):
    if offset in idx:
        inters.append(elem)
    else:
        inters.append(numpy.nan)

print('======INTERS=======',inters)
print('*'*80)

Вот что, примерно, будет выведено у нас в консоль:

Для построения графика мы используем несколько наборов данных. На шкале X мы используем время – для всех графиков в данной статье используется время, которое мы получили с биржи.

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

На втором мы получаем данные сами, с помощью вызова вот этой функции:

macd, macdsignal, macdhist = talib.MACD(quotes['close'], fastperiod=12, slowperiod=26, signalperiod=9)

Как я писал в прошлой статье, мы в результате получаем три набора данных – macd, macdsignal, macdhist – это три массива значений, каждое из которых является значением для оси Y. Т.е. первый элемент будет отрисован в X(0), второй в X(1), на высоте Y, указанной в самом элементе. На скриншоте выше вы видите, я вывел в консоль полученные значения

=====MACDSIGNAL======= [             nan              nan              nan              nan

              nan              nan              nan              nan

              nan              nan              nan              nan

              nan              nan              nan              nan

              nan              nan              nan              nan

              nan              nan              nan              nan

              nan              nan              nan              nan

              nan              nan              nan              nan

              nan   7.91964156e-06   4.14538137e-06   2.60110672e-08

  -4.07798778e-06  -7.95972541e-06  -1.00486163e-05  -1.19658012e-05

  -1.41967407e-05  -1.91172395e-05  -2.54980919e-05  -3.30112736e-05

  -4.08438995e-05  -4.82626516e-05  -5.56410407e-05  -6.42993299e-05

  -7.47543657e-05  -8.34476354e-05  -9.08057290e-05  -9.68925398e-05

  -1.01468395e-04  -1.04801729e-04  -1.06813122e-04  -1.05755025e-04

  -1.00109101e-04  -9.20068930e-05  -8.33780421e-05  -7.33571885e-05

Nan – это значит Not a number, и это то, чего не видно на графике (в начале, линии рисуются с отступом). Дальше идут значения – они крутятся вокруг нуля, именно эти значения мы и отрисовываем на графике и используем для анализа. В данном случае первые 33 элемента отрисованы не будут, потом (X=34, Y=7.91964156e-06), (X=35, Y=4.14538137e-06) и т.п.

То же самое справедливо и для macd.

В этой строке:

idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0

я получаю пересечение значений (или графиков, как удобнее), и получаю на выходе массив индексов.

======IDX======= [  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17

  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  54  75  86

 110 111 114 116 125 154 156 157 161 162]

Что это значит – это значит, если я возьму массив значений macd, то пересечение будет в точках 0, 1, 2, …. 75, 86… 161, 162. То же самое справедливо и для массива macdsignal. Можно сказать и так, что IDX указывает на точки X на графике.

Для отображения пересечений (красных точек на графике) я создаю новый набор данных – он по длине такой же, как macd и macdsignal, но там, где есть пересечение macd и macdsignal, я вставляю значение macd, там где пересечения нет, вставляю nan. Таким образом, я отрисовываю все точки X, но красная точка появится только там, где есть пересечение.

Давайте ловить тренд

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

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

import numpy
import talib
import requests
import json
import time

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

PAIR = 'BTC_ETH' # Пара, по которой работаем

start_time = time.time() - 15*60*60 # за какой период брать данные - 15 часов в данном случае

resource = requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999&period=300" % (PAIR, start_time))
data = json.loads(resource.text)

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

xdate=[datetime.datetime.fromtimestamp(item['date']) for item in data]

fig, ax = plt.subplots(3, sharex=True)

candlestick2_ohlc(ax[0], quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6)

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

def chart_date(x,pos):
    try:
        return xdate[int(x)]
    except IndexError:
        return ''

ax[0].xaxis.set_major_formatter(ticker.FuncFormatter(chart_date))

fig.autofmt_xdate()
fig.tight_layout()

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

idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0
print(idx)

inters = []

for offset, elem in enumerate(macd):
    if offset in idx:
        inters.append(elem)
    else:
        inters.append(numpy.nan)
ax[1].plot(inters, 'ro')

hist_data = []
max_v = 0

for offset, elem in enumerate(macdhist):

    
    if macd[offset] > macdsignal[offset]: # восходящий тренд
        v = 1 #perc
    else:
        v = -1
    hist_data.append(v*1000)

ax[2].fill_between([x for x in range(len(macdhist))], 0, hist_data, facecolor='green', interpolate=True)

plt.show()

Тут наглядно видно, когда график рос, а когда падал. Давайте добавим логику чуть-чуть поумнее.

Мне кажется, боту будет выгоднее торговать в такие моменты:

  1. Когда график падал, но начал расти (в самом конце падения)
  2. Когда график начал расти, растет, и не наметил тенденцию к падению (торговать во время роста, прекратить ближе к концу)

Вот как то так (нарисовал в пейнте. Обвел не всё, но самое показательное):

Понятно, что текущая логика с этим не справляется. Значит, надо её поменять!

Вот какой алгоритм пришел мне в голову: Мы берем разницу между двумя линиями MACD, и сравниваем с максимальной разницей линий MACD за период от одного изменения тренда до другого. Каждый раз, когда тренд разворачивается (пересечение линий) мы обнуляем этот максимум в ноль.

Таким образом, после разворота тренда, первая разница между двумя линиями будет максимальной (100% разницей). После этого если линии еще сильнее разойдутся, то уже следующая разница между линиями станет максимальной. В тот момент, когда линии начнут сходиться, разница уже не будет максимальной, а будет убывать (90%, 80%) и т.п.

Поэтому для торгов мы будем использовать две настроечные переменные:

Если рынок бычий (растет) то торгуй, пока разница больше X%.  В таком случае он будет торговать на бычьем рынке с момента разворота тренда до тех пор, пока линии не начнут плотно сходиться.

Если рынок медвежий (падает) то торгуй тогда, когда разница между линиями меньше Y%. В таком случае он включится в торговлю только после того как тренд развернется, линии разойдутся на максимум, потом сойдутся почти полностью.

Вот так определим эти переменные:

BEAR_PERC = 70 # При падении рынка

BULL_PERC = 30 # При росте рынка

Каждое из этих значений может колебаться от 0 до 100, не обязательно, что бы они в сумме что-то давали, они независимые.

Давайте внесем изменения в код и посмотрим, что получится:

import numpy
import talib
import requests
import json
import time

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

PAIR = 'BTC_ETH' # Пара, по которой работаем

BEAR_PERC = 70
BULL_PERC = 10

start_time = time.time() - 15*60*60 # за какой период брать данные - 15 часов в данном случае

resource = requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999&period=300" % (PAIR, start_time))
data = json.loads(resource.text)

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

xdate=[datetime.datetime.fromtimestamp(item['date']) for item in data]

fig, ax = plt.subplots(3, sharex=True)

candlestick2_ohlc(ax[0], quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6)

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

def chart_date(x,pos):
    try:
        return xdate[int(x)]
    except IndexError:
        return ''

ax[0].xaxis.set_major_formatter(ticker.FuncFormatter(chart_date))

fig.autofmt_xdate()
fig.tight_layout()

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

idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0
print(idx)

inters = []

for offset, elem in enumerate(macd):
    if offset in idx:
        inters.append(elem)
    else:
        inters.append(numpy.nan)
ax[1].plot(inters, 'ro')

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

ax[2].fill_between([x for x in range(len(macdhist))], 0, hist_data, facecolor='green', interpolate=True)

plt.show()

Работает. Правда, сработало в середине, там где тренд почти развернулся, но передумал, но это от настроек зависит, если выставить BEAR_PERC = 99, например, то такого не будет, но и на падении он не срубит… А если выставить 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 = 30

PAIR = 'BTC_ETH'

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

def update_graph(interval):
    
    start_time = time.time() - 15*60*60
    resource = requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999&period=300" % (PAIR, start_time))
    data = json.loads(resource.text)

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

    xdate=[datetime.fromtimestamp(item['date']) for item in 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)
    
    # print(ax[0].get_xdata())
    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')

    #ax[1].scatter(x=ax[0].get_xdata(), y=inters, c='b')

    hist_data = []
    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 # обнуляем пик спреда между линиями
        hist_data.append(v*1000)
 
    ax[2].clear()
    ax[2].fill_between([x for x in range(len(macdhist))], 0, hist_data, facecolor='green', interpolate=True)
    plt.gcf().texts.remove(fig.comment)
    fig.comment = plt.figtext(.7,.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()

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


Реклама


Прикручиваем к боту

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

Poloniex

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

Убираем все лишнее, и получаем небольшую, скромную функцию, которая возвращает нам все, что надо:

import numpy
import talib
import requests
import json
import time

from datetime import datetime

BEAR_PERC = 70
BULL_PERC = 30

PAIR = 'BTC_ETH'

def should_buy(pair):
    
    start_time = time.time() - 15*60*60
    resource = requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999&period=300" % (pair, start_time))
    data = json.loads(resource.text)

    quotes = {}
    quotes['close']=numpy.asarray([item['close'] for item in data])
    macd, macdsignal, macdhist = talib.MACD(quotes['close'], 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)

    hist_data = []
    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 # обнуляем пик спреда между линиями
        hist_data.append(v*1000)
 
    return activity_time

while True:
    print("Покупать?", should_buy(PAIR))
    time.sleep(1)

Как добавить в код бота для полоникс? В бота на сайте я добавил, вот ссылка на обновленную версию. В какого-то другого – скопируйте функцию, подключите numpy, talib и requests, выставьте параметры  BEAR_PERC и BULL_PERC, ну и вызывайте, когда надо.

Exmo

Тут немного сложнее, т.к. Exmo не возвращает архивные данные по торгам… Плохо, придется собирать инфу с биржи, пока не накопится достаточно данных для анализа. Воспользуемся методом API trades. Он возвращает 100 последних торгов, и, судя по документации к API, ничего больше.. Но если не следовать документации, а добавить на свой страх и риск не указанный параметр limit, то можно получать до 10 000 записей :) Пишем функцию:

import numpy
import talib
import requests
import json
import time

from datetime import datetime

BEAR_PERC = 70
BULL_PERC = 30

PAIR = 'BTC_USD'

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

    close_prices = {} # сформируем словарь с ценой закрытия по 5 минут
    for item in reversed(data[pair]):
        d = int(float(item['date'])/300)*300 # Округляем время сделки до 5 минут
        close_prices[d] = float(item['price'])
    
    macd, macdsignal, macdhist = talib.MACD(numpy.asarray([close_prices[item] for item in sorted(close_prices)]), 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)

    hist_data = []
    max_v = 0

    activity_time = False
    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 # обнуляем пик спреда между линиями
        hist_data.append(v*1000)
 
    return activity_time

while True:
    print("Покупать?", should_buy(PAIR))
    time.sleep(1)

Её можно прикрутить, опять же, к любому боту, но я прикрутил к нашему, можете скачать обновленную версию. Здесь бот будет покупать реже, но уже с некоторым проблеском интеллекта.


Реклама


Теперь о том, как строить MACD для эксмо

Давайте наш скрипт модифицируем так, что бы видеть MACD линии и гистограмму для торгов на эксмо, оставив логику советчика - покупать или нет. График советчика я заменил на гистограмму, для полноты картины. Так же добавил в скрипт переменную PERIOD, это время в минутах, за которое строим свечи. Для демострации, я выставил 30 минут - именно так строит эксмо, и так вы можете сравнить точность работы скрипта. Но я советую поменять вам это число на 5 - тогда вы сможете видеть пятиминутные свечи, более оперативно оценивать обстановку, и, возможно, получите преимущество перед теми, кто торгует на эксмо через родной интерфейс биржи.

Вот код:

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 = 30

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

PAIR = 'BTC_USD'

SHOW_BOT_CHART = False

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)
    print(resource.text[:100])
    #return
    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
    hist_data = []
     
    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 # обнуляем пик спреда между линиями

        hist_data.append(v*1000)

    ax[2].fill_between([x for x in range(len(macdhist))], 0, hist_data if SHOW_BOT_CHART else 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()

Вот результат:

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

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

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

Комментарии: (159)
03.11.2017 14:59
Доброго дня Андрей!

Спасибо вам за ваши статьи!

сейчас пытаюсь запустить новую версию бота.
столкнулся с такой ошибкой:



Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 17:26:49) [MSC v.1900 32 bit (Intel)] on win32 
Type "copyright", "credits" or "license()" for more information. 
»> 
================ RESTART: C:\Users\***\exmo_macd.py ================ 
Открытых ордеров нет 

Warning (from warnings module): 
File "C:\Users\***\exmo_macd.py", line 93 
idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0 
RuntimeWarning: invalid value encountered in sign 
Выход, по MACD рынок падает 
Открытых ордеров нет 
Выход, по MACD рынок падает 
Открытых ордеров нет 
Выход, по MACD рынок падает 


дальше по кругу пишет:  

Открытых ордеров нет 
Выход, по MACD рынок падает 

и ничего не происходит.

Буду признателен за помощь.
03.11.2017 15:20
Бот работает. Посмотрел график, тренд действительно был нисходящий.
Но ошибка при старте бота так и есть.
03.11.2017 18:03
Да, по сути это не ошибка а предупреждение, на процесс не влияет. Просто когда ищем пересечения, не хватает данных из прошлого, и он не может найти пересечения в самом начале периода, когда боту они и не нужны. На скриншотах видно, свечи строятся с начала, а macd с отступом - именно там и ругается. Попозже я обновлю код, добавлю подавление вывода этого сообщения.
03.11.2017 20:43
Спасибо за доработку бота.
Есть вопросы: ссылка на данные в коде на фолоникс, эта ссылка должны быть и для биржи эксмо?)
И правильно ли я понимаю, что достаточно установить базу талиб и скачать обновленную версию бота?
Так же в обновленной версии ORDER_LIFE_TIME = 0.5, тобишь ордер живет пол минуты?
03.11.2017 20:53
Добрый день.
1. Первого вопроса не понял - в статье есть примеры для кода на полониксе, и для кода на эксмо, и есть ссылки на скачивание ботов для той биржи и для этой. Там разные способы получения данных, т.к. они по разному отдают, но и тот и другой случай разобраны в коде в соответствующих разделах статьи.
2. Да, установить талиб и всё остальное, как расписано тут: https://bablofil.ru/python-indicators. После этого запустить новую версию бота.
3. Да, полминуты, но это под каждую пару надо подбирать эмпирически. В принципе, на эксмо не так часто сделки происходят, так что наверное разумно поставить побольше.
03.11.2017 22:25
Cкачал бота под заголовком Exmo, и там все же внутри кода ссылка: #start_time = time.time() - 15*60*60
    #resource = requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999.=300" % (pair, start_time))
    #data = json.loads(resource.text).
Мб  я что - то путаю?
03.11.2017 23:04
Ааа, точно, этот кусок кода закомментирован, и выполняться не будет, я его забыл удалить (.
Можете у себя удалить, ничего не изменится)
03.11.2017 22:41
И да, ссылки в конце этой статьи Вы не указали, забыли, видимо.
03.11.2017 23:16
Точно, спасибо! Добавил.
04.11.2017 13:22
Здравствуйте, Андрей. Я по ошибке оставил комментарий под другой статьей, там у меня были проблемы с установкой NumPy. С этим я разобрался, но библиотека ta-lib ни в какую не хочет устанавливаться. Можете подсказать, в чем проблема?
C:\Users\Jura>pip install ta-lib
Collecting ta-lib
Using cached TA-Lib-0.4.10.tar.gz
Installing collected packages: ta-lib
Running setup.py install for ta-lib ... error
Complete output from command c:\users\jura\appdata\local\programs\python\pyt
hon35-32\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\Jura
\\AppData\\Local\\Temp\\pip-build-bqdme5_a\\ta-lib\\setup.py';exec(compile(getat
tr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'ex
ec'))" install —record C:\Users\Jura\AppData\Local\Temp\pip-s2sskwci-record\ins
tall-record.txt single-version-externally-managed compile:
C:\Users\Jura\AppData\Local\Temp\pip-build-bqdme5_a\ta-lib\setup.py:77: User
Warning: Cannot find ta-lib library, installation may fail.
warnings.warn('Cannot find ta-lib library, installation may fail.')
running install
running build
running build_py
creating build
creating build\lib.win32-3.5
creating build\lib.win32-3.5\talib
copying talib\deprecated.py -> build\lib.win32-3.5\talib
copying talib\test_abstract.py -> build\lib.win32-3.5\talib
copying talib\test_data.py -> build\lib.win32-3.5\talib
copying talib\test_func.py -> build\lib.win32-3.5\talib
copying talib\test_stream.py -> build\lib.win32-3.5\talib
copying talib\__init__.py -> build\lib.win32-3.5\talib
running build_ext
building 'talib.common' extension
error: Unable to find vcvarsall.bat

--------------------------------------
Command "c:\users\jura\appdata\local\programs\python\python35-32\python.exe -u -
c "import setuptools, tokenize;__file__='C:\\Users\\Jura\\AppData\\Local\\Temp\\
pip-build-bqdme5_a\\ta-lib\\setup.py';exec(compile(getattr(tokenize, 'open', ope
n)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install —record
C:\Users\Jura\AppData\Local\Temp\pip-s2sskwci-record\install-record.txt single
-version-externally-managed compile" failed with error code 1 in C:\Users\Jura
\AppData\Local\Temp\pip-build-bqdme5_a\ta-lib\
04.11.2017 15:04
Это он VisualStudio пытается найти на вашем компе. 
Что бы не ставить студию, можно скачать тут http://www.lfd.uci.edu/%7Egohlke/pythonlibs/ уже собранный whl файл talib, потом установить его pip install путь_к_файлу.whl
04.11.2017 15:28
Спасибо большое, заработало. А ещё можно узнать, что нужно заменить в скрипте графика, чтобы отображались кривые не с poloniex, а с EXMO?
04.11.2017 17:32
Отличный вопрос!
.Дополнил статью, выложил пример.
04.11.2017 20:42
Скрипт работает, но не без изъянов. На что-то ругается, не отображает нижний график (там серое поле) и не показывает точки
Warning (from warnings module):
  File "C:\Users\Jura\AppData\Local\Programs\Python\Python35-32\lib\site-packages\matplotlib\cbook\deprecation.py", line 106
    warnings.warn(message, mplDeprecation, stacklevel=1)
MatplotlibDeprecationWarning: The finance module has been deprecated in mpl 2.0 and will be removed in mpl 2.2. Please use the module mpl_finance instead.

Warning (from warnings module):
  File "C:\Users\Jura\Desktop\Крипта\chart.py", line 78
    idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0
RuntimeWarning: invalid value encountered in sign
04.11.2017 20:47
Что самое интересное, это происходит только на паре BTC_USD. В ZEC_RUB, LTC_EUR всё замечательно
04.11.2017 21:33
Сейчас по BTC_USD пересечений нет.. Можно считать это ограничением эксмо.
Мы можем получить только 10 000 последних торгов.
Если для ZEC_RUB 10 000 это грубо говоря три дня, то для ходовой пары BTC_USD час-два.. Боту для принятия решения такого набора данных хватит, а вот красивый график из этого не построишь.
Поставьте период в 5 минут - будут и точки, и графики
04.11.2017 23:59
Да, так работает. Тем не менее хоть в основном действительно бот стал торговать выгоднее и научился выжидать, но за ним нужно следить, только что он, например, выставил лайт за 158 евро
05.11.2017 14:26
И снова добрый день. Не могу сказать точно, это только у меня так или же у всех, но некоторые тенденции у бота замечены, поэтому хотел бы высказать некоторые пожелания:.
1. Бот очень хорошо работает на биткоинах (за ночь при игре на 8 долларах поднял 30 центов), но на альтах при игре на понижение он часто просчитывается и потом не может продать. Думаю, если прикрутить какой-нибудь скрипт, который при игре на альтах учитывает ещё и курс битка (от которого очень сильно альты зависят), он сможет так же хорошо торговать, как и на битках
2. Бот, как уже сказал, изредка выставляет слишком высокие цены за криптовалюту, когда в альтах
3. Было бы интересно посмотреть, как бот будет работать при учете нескольких индикаторов (например, облака Ишимоку Кинко Хё), и будет ли от этого увеличиваться точность
13.11.2017 15:14
Добрый день! При запуске бота для exmo пишет 
Traceback (most recent call last):
  File "C:\Bots\exmo_macd.py", line 6, in <module>
    import numpy
ModuleNotFoundError: No module named 'numpy'
В чем может быть дело?
 </module>
13.11.2017 15:16
Разобрался)
14.11.2017 21:48
poloniex_macd.py:62: RuntimeWarning: invalid value encountered in sign
  idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0

выдает и не торгует что делать подскажите?
14.11.2017 22:37
Предупреждение это нормально, что бы не писал такого, в начале скрипта, после 
import numpy
 
добавьте 
numpy.seterr(all='ignore')

А вот почему не торгует, другой вопрос.. Вы правильно указали пару? Что пишет в логе?
15.11.2017 08:40
Все торгует спасибо! Вот такой вопрос BEAR_PERC 70 и BULL_PERC 98 при таких настройка очень мало сделок совершает вы на таких тестировали?
17.11.2017 13:13
Добрый день. На таких же.
Ну да, чем осторожнее бот, тем меньше сделок (удобных ситуаций на рынке по паре), нарастить можно, увеличив количество пар. Вот тут в конце статьи есть отчет по работе подобного бота на другой бирже https://bablofil.ru/bot-dlya-birgi-bittrex/.
20.11.2017 23:34
Андрей, с чем связаны жуткие фризы окна Figure1? я думал мой старенький ноут не тянет эту супер графику, но сегодня провозившись я установил PyCharm под Mac OS на Imac, но и там пользоваться графиком очень не удобно, тормозит при каждой попутке нажать на какую либо кнопку
18.12.2017 16:21
¯\_()_/¯
Попробуйте интервал снизить, секунд до 3х например

ani = animation.FuncAnimation(fig, update_graph, interval=3000)
22.11.2017 14:58
насчет exmo, так же как и в битрексе можно было подсмотреть запрос - https://exmo.me/ctrl/chartMain?type=0.=day=ETH_RUB
07.12.2017 08:25
Андрей, добрый день! Спасибо огромное за бота. Не подскажите, что нужно поправить в коде, чтобы бот в паре например BTC_USD работал на увеличение BTC, а не USD. Заранее спасибо.
15.12.2017 08:45
Добрый день, Андрей. Большое спасибо за проделанную работу. Бот самое то для такого нуба в программировании как я) Хотел спросить можно ли сделать так, чтобы бот на покупку ставил цену на 0.0000001 BTC больше (например), а не высчитывал среднюю цену за определенный период. Я заметил, что часто ордер не успевает срабатывать т.к. цена сильно занижена, даже если я ставлю AVG_PRICE_PERIOD = 1. А таким образом бы за счёт частотности конечный профит был бы больше. Спасибо!
19.12.2017 17:10
Андрей, а не подскажите как прикрутить к индикатору какое-нибудь звуковое сопровождение при пересечении линий, например звонок или колокол, как на обычной бирже. Запустил ботов на торговлю, пока в тестовом режиме, отслеживать множество графиков очень тяжело на одном мониторе и хотелось бы получать какое-нибудь быстрое оповещение с графика пары на которой началась торговля.
19.12.2017 19:10
Вот эту строчку вставтьте в самый верх

import winsound

А эти две - в любое место где нужен звук

soundfile = "c:/Windows/Media/chimes.wav"
winsound.PlaySound(soundfile, winsound.SND_FILENAME | winsound.SND_ASYNC)
20.12.2017 07:09
К сожалению, так и не разобрался в какое место вставлять 
soundfile = "c:/Windows/Media/chimes.wav"
winsound.PlaySound(soundfile, winsound.SND_FILENAME | winsound.SND_ASYNC)
При восходящем или нисходящем тренде.
Я так понимаю, что необходимо вставлять где-то в этом блоке
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 # обнуляем пик спреда между линиями
Но к сожалению выдает ошибку не сможете мне помочь?
20.12.2017 15:36
Я не знаю какую он ошибку выдает, но скорее всего нарушены отступы. Надо эти строки отделить пробелами или табуляциями так, что бы интервал был таким же, как у соседей.
Но вообще скрипт перерисовывает график каждую секунду, так что если вставлять, то лучше примерно так:
Найти строку 
 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})

и перед ней добавить
if activity_time:
    soundfile = "c:/Windows/Media/chimes.wav"
    winsound.PlaySound(soundfile, winsound.SND_FILENAME | winsound.SND_ASYNC)

Ну и не забыть в самый верх добавить
import winsound
20.12.2017 17:42
Выдает ошибку:
expected an indented block
Что-то типа ожидается отложенный блок
20.12.2017 18:52
Нет, ожидается что блок кода будет иметь нужные отступы
21.12.2017 09:37
Все понял, спасибо. Правда пропала строка с указанием времени.
Еще один вопрос, если можно.
Можно ли майнить на DigitalOcean.com сервере через VPS на базе Ubuntu?
21.12.2017 11:42
Можно, только плата за хостинг выйдет дороже, чем доход с майнинга)
22.12.2017 21:30
Андрей, помогите разобраться.
Успешно запустил бот exmo_macd.py - все работает. А вот любой код с графикой не хочет запускаться. Запускаю из командной строки на ноутбуке mac. 
Вот такой файл 1.py с текстом:
******************************************************************************************************
import numpy
import talib
import requests
import json
import time

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

PAIR = 'BTC_ETH' # Пара, по которой работаем

start_time = time.time() - 15*60*60 # за какой период брать данные - 15 часов в данном случае

resource = requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999.=300" % (PAIR, start_time))
data = json.loads(resource.text)

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

xdate=[datetime.datetime.fromtimestamp(item['date']) for item in data]

fig, ax = plt.subplots(3, sharex=True)

candlestick2_ohlc(ax[0], quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6)

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

def chart_date(x,pos):
    try:
        return xdate[int(x)]
    except IndexError:
        return ''

ax[0].xaxis.set_major_formatter(ticker.FuncFormatter(chart_date))

fig.autofmt_xdate()
fig.tight_layout()

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

idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0
print(idx)

plt.show()
*******************************************************************************************************************
Выдает ошибки:@ MacBook-Air(oleh)$ @ MacBook-Air(oleh)$ python3 1.py
bash: syntax error near unexpected token `('
~/Downloads/Python books/BITTREX MACD BOT @ MacBook-Air(oleh)$ /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/matplotlib/cbook/deprecation.py:106: MatplotlibDeprecationWarning: The finance module has been deprecated in mpl 2.0 and will be removed in mpl 2.2. Please use the module mpl_finance instead.
bash: /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/matplotlib/cbook/deprecation.py:106:: No such file or directory
~/Downloads/Python books/BITTREX MACD BOT @ MacBook-Air(oleh)$   warnings.warn(message, mplDeprecation, stacklevel=1)
bash: syntax error near unexpected token `message,'
~/Downloads/Python books/BITTREX MACD BOT @ MacBook-Air(oleh)$ Traceback (most recent call last):
bash: syntax error near unexpected token `most'
~/Downloads/Python books/BITTREX MACD BOT @ MacBook-Air(oleh)$   File "1.py", line 17, in <module>
bash: syntax error near unexpected token `newline'

Беру любые куски из статьи и нулевой результат...
</module>
23.12.2017 13:42
Не встречал такого..
Попробуйте переустановить matplotlib
01.01.2018 22:47
установка пипой талиба это полный пипец, установил благодаря подсказкам, запустил код и вот что выдало на эти апросы
import numpy
import talib
import requests
import json
import time


>>> import graf
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\sily\AppData\Local\Programs\Python\Python36-32\graf.py", line 2
, in <module>
    import talib
  File "C:\Users\sily\AppData\Local\Programs\Python\Python36-32\talib\__init__.p
y", line 4, in <module>
    from ._ta_lib import (
ModuleNotFoundError: No module named 'talib._ta_lib'
>>>
как можно проверить, что все модули установились правильно, или в чем может быть еще причина, спасибо

</module></module></module></stdin>
08.01.2018 18:03
Доброго времени суток, тестирую бота. Вроде прочитал тут, что он пока не продаст ордер, новый на покупку не создает. Но у меня почему-то через два чеса бот создал второй ордер на продажу и потом на покупку. Так должно быть, или это глюк какой-то?
12.01.2018 16:34
Он должен выставлять ордер на покупку только после того, как полностью исполнен ордер на продажу.
Если создался ордер на покупку при существующем ордере на продажу, то да, какой то глюк)
13.01.2018 19:34
Здравствуйте! Тестирую бота на exmo, одного на 5 ти парах к доллару. Как и у Александра А. бот может выставить и 2 и 3 ордер по одной паре. Думал так задумано. Как бороться с этим ? И надо ли?
Я так понял , что бот если видит в данный момент , что можно брать, то покупает еще . Пока вроде динамика нормальная. Подскажите, как в боте для poloniex добавить пары? По аналогии с ботом exmo не работает, как только не пробовал... Или только разных ботов по каждой паре?
Вроде написано пары... Подскажите пожалуйста. Спасибо.

# Пары, по которым собираемся торговать
PAIRS = {
'BTC_VTC' : {
'ORDER_AMOUNT': '0.001', # Сколько валюты 1 использовать в ордере ( в данном случае, 0.002 Btc),
'ORDER_LIFE_TIME': 3, # через сколько минут отменять неисполненный ордер на покупку CURR_1
'PROFIT_MARKUP_DOWN': 0.001, # Какой навар нужен с каждой сделки при покупке (поверх комиссии)? (0.001 = 0.1%). Можно ставить 0
'PROFIT_MARKUP_UP': 0.002, # Какой навар нужен с каждой сделки при продаже (поверх комиссии)? (0.002 = 0.2%)
'MED_PRICE_PERIOD': 20, # За какой период брать среднюю цену (в минутах)

},
13.01.2018 20:58
Тогда надо внимательно смотреть что он пишет, может быть какой-то сетевой сбой или вроде того.. Я еще раз посмотрел код, так сходу не вижу, где могло бы такое сработать. Но если что-то замечу, поправлю.
Про Полоникс - спасибо, действительно была недоработка, поправил - скачайте код по новой.

13.01.2018 20:54
И еще такая проблема.
С ноутбука рабочего все боты работают. (WINDOWS10)
Смог запустить и на виртуальном сервере-работает

Те же боты из дома, со стационарного компа тоже (WINDOWS10) - не запускаются.
вот такая ошибка все время. Ругается на сертификаты постоянно. При чем и в ботах exmo и poloniex 

Вот из poloniex лог

2018-01-13 23:18:46.243673 HTTPSConnectionPool(host='poloniex.com', port=443): Max retries exceeded with url: /public?command=returnChartData&currencyPair=BTC_USDT&start=1515820726.1746655&end=9999999999.=300 (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:864)')))
13.01.2018 21:04
Кто-то подменяет вам сертификаты, или доверенный центр сертификации неправильный. Возможно антивирус, возможно провайдер, может быть вирус. А может быть кто-то навроде Ростелекома запрещает вам доступ..
Про эксмо смотрите комменты, как обойти запреты https://bablofil.ru/bot-dlya-birjy-exmo/
Про полоникс я выкладывал как использовать прокси, тоже в комментариях https://bablofil.ru/bot-dlya-birjy-poloniex
14.01.2018 16:57
Спасибо большое Андрей. Буду искать "виновника" по сертификатам.

А вот код по exmo , который работает у меня и по три ордера создает


#!/usr/bin/python3.5
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)
14.01.2018 17:49
Ну это community бот, тут похоже да, спецом так сделано
28.01.2018 19:48
Здравствуйте. Пытаюсь работать с отредактированной версией бота . Лог писался для BCH_RUB при росте курса на 1,66%. Те же сообщения в логе и для BTC_RUB при падении курса на 1,40%. В чем может быть причина?
Открытых ордеров нет
2018-01-28 22:47:25.843394   BCH_RUB Открытых ордеров нет
2018-01-28 22:47:25.861406   BCH_RUB  Обработка...
2018-01-28 22:47:26.867640   BCH_RUB Условия рынка не подходят для торговли {'growing': False, 'trand': 'BEAR'}
Открытых ордеров нет
2018-01-28 22:47:28.125568   BCH_RUB Открытых ордеров нет
2018-01-28 22:47:28.148584   BCH_RUB  Обработка...
2018-01-28 22:47:29.142673   BCH_RUB Условия рынка не подходят для торговли {'growing': False, 'trand': 'BEAR'}
Открытых ордеров нет
2018-01-28 22:47:30.393727   BCH_RUB Открытых ордеров нет
2018-01-28 22:47:30.420745   BCH_RUB  Обработка...
2018-01-28 22:47:31.304715   BCH_RUB Условия рынка не подходят для торговли {'growing': False, 'trand': 'BEAR'}
Открытых ордеров нет
2018-01-28 22:47:32.578159   BCH_RUB Открытых ордеров нет
2018-01-28 22:47:32.593167   BCH_RUB  Обработка...
2018-01-28 22:47:33.618493   BCH_RUB Условия рынка не подходят для торговли {'growing': False, 'trand': 'BEAR'}
Открытых ордеров нет
2018-01-28 22:47:34.871383   BCH_RUB Открытых ордеров нет
2018-01-28 22:47:34.895398   BCH_RUB  Обработка...
2018-01-28 22:47:35.876252   BCH_RUB Условия рынка не подходят для торговли {'growing': False, 'trand': 'BEAR'}
Открытых ордеров нет
2018-01-28 22:47:37.141311   BCH_RUB Открытых ордеров нет
2018-01-28 22:47:37.156321   BCH_RUB  Обработка...
14.11.2018 13:34
доброго дня. не запускается этот бот на эхмо, пишет это красным: Traceback (most recent call last):
  File "C:/Users/User/Desktop/мультиМАСД 990.py", line 8, in <module>
    import numpy
ModuleNotFoundError: No module named 'numpy'

в чем может быть проблема? спс</module>
14.11.2018 13:40
Не хватает модулей
Нужно в командной строке выполнить
pip install numpy
pip install requests
pip install matplotlib
И еще кое-что поставить, подробнее тут https://bablofil.ru/python-indicators/
14.11.2018 18:48
в cmd пишет всем этим командам: "не является внутренней или внешней командой, исполняемой программой или пакетным файлом"

а "И еще кое-что поставить, подробнее тут https://bablofil.ru/python-indicators/" я правильно понимаю что речь идет про талиб?
14.11.2018 19:21
победил, бот заработал! по поводу установки pip install numpy, pip install requests, pip install matplotlib, нужно ставить питон со всеми галками в расширенном режиме, и майкрософт визуал с++ 2015 ставить и все пойдет! талиб отсюда скачал https://www.lfd.uci.edu/~gohlke/pythonlibs/, перебрал 4 кода подошел этот TA_Lib-0.4.17-cp37-cp37m-win_amd64.whl
15.01.2018 12:18
community бот ? А что это значит? Я дилетант, поэтому возможно такие вопросы.
Я думал -это Ваш бот, но доработанный на торговлю несколькими парами.

А как в нем ставить ограничение, чтобы по одной паре выставлялись только ордера на сумму не превышающие сумму заданную в этом параметре?
CAN_SPEND = 20 (например)

У меня он как раз сейчас в паре DASH_USD подвесил все же купленные на пике 3 ордера . Я так понимаю, что именно из-за отсутствия ограничения. С ограничением был бы один наверно. До падения курсов последнего работал очень даже не плохо, профит около 3% в день составил.
21.01.2018 12:04
Ну, я имею в виду, что эта версия бота допиливалась участниками, тут да, селл не учитывается. Что бы ордер не выставлялся, замените
 #raise ScriptQuitCondition('Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)')
на
 raise ScriptQuitCondition('Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)')
И наверное еще один отступ в табуляцию подставьте перед этой строчкой
21.01.2018 19:40
Спасибо Вам большое! Буду пробовать.
18.01.2018 08:12
беда у меня с этим Талибом какаято, то коека его поставил,  сейчас вот что говорит:
Traceback (most recent call last):
  File "C:\Program Files\Python36\1.py", line 9, in <module>
    import talib
  File "C:\Program Files\Python36\lib\talib\__init__.py", line 4, in <module>
    from ._ta_lib import (
ModuleNotFoundError: No module named 'talib._ta_lib'
чего ему надо, скажите люди?
причем одна установ ка pip instal ta-lib, пишет requirement allready satisfied, я так понимаю, цто уже установлено.
а когда пишешь pip instal talib, пишет красным....... no matches distribution found for talib
прям не понимаю</module></module>
21.01.2018 12:12
У вас может быть несколько питонов установлено?
Или талиб встал как-то криво.
Попробуйте снести все, что ставили - и поставьте питон для всех пользователей - вот все галочки прям, при установке выберите расширенный режим, там все галочки.
Потом скачайте whl файл, и установите его.
Должно работать.
Ну и если не будет, на диск C скачайте и распакуйте талиб
18.01.2018 16:15
Warning (from warnings module):
  File "C:\Program Files\Python37\гр.py", line 48
    idx = numpy.argwhere (numpy.diff(numpy.sign(macd - macdsignal))!=0).reshape(-1) + 1
RuntimeWarning: invalid value encountered in sign
такая еше ошибка выскакивает и не дстроит нижний график
21.01.2018 12:06
Если график не строится, значит данных мало, надо увеличить временной интервал
18.01.2018 16:28
интересно почему при Bear рост true, он не покупает и не продает
19.01.2018 16:21
я сам запарился с этими пипами и талибами. самый простой способ установить это распаковать архив .whl  d в папку питона c:\Users\xxx\AppData\Local\Programs\Python\Python36-32\Lib\site-packages\. можно еще положить архив в папку c:\Users\xxx\AppData\Local\Programs\Python\Python36-32\Scripts\, чтоб не заморачиваться с путями и запустить в командной строке прямо из этой папки pip install название файла.whl . результат будет тот же. у меня запустился только один график для эксмо, самый последний и работает нормально, на остальных графиках при запуске какието матюки и в лучшем случае загружает только форму. думаю причина не в установке талиба а в скриптах, судя по коментам у многих такие косяки
21.01.2018 12:09
Даже не знаю, что вам ответить.
Специально взял несколько скриптов со статьи, запустил, графики построились.
Если вы видите какие-то матюки, то выкладывайте - может быть версия питона не та, либо с часовым поясом заморочки, либо сетевые какие-то вопросы.
19.01.2018 16:57
Спасибо за Вашу работу! Решил погонять полоникс бота. Заметил следующее -
Строка со сдвигом по времени от биржи не нужна (вернее нужно ставить STOCK_SHIFT = 0), т.к. вы используете время unix а оно согласуется с UTC также как и биржа.
21.01.2018 12:13
Да, это так, спасибо. Но в каких-то версиях на каких-то платформах это было не так, сейчас может быть не актуально но все же пусть будет)
25.01.2018 20:08
добрый вечер Андрей, с "матюками" разобрался, они были вызваны капчей на полоникс, зашел через европейские прокси и матюки пропали, за то есть вопросы по работе графика на ексмо, часто виснет, приходит ответ на превышение лимита полученных данных, думаю вынести получение пачки последних  сделок за пределы цикла обновления, чтоб при следующем обновлении  запрашивать только последние сделки за минуту и стирать устаревшие, думаю будет быстрее работать и сайт банить не будет.  если подскажете как проще сделать, буду благодарен, в питоне только начал разбираться, слишком много времени уходит на изучение работы всех необходимык библиотек.
хочу еще установить на график горизонтальный маркер текущей цены, линию, которая будет бегать за ценой и менять  цвет в зависимости от падения или роста, как на тradingview, но пока не нашел  в matplotlib нужного инструмента. есть там такой или нужно самому писать?
и еще, если подправить функцию  def candlestick2_ohlc в файле  c:\Users\FOX\AppData\Local\Programs\Python\Python36-32\Lib\site-packages\matplotlib\finance.py и установить цвета свеч вместо черного на зеленый, то он выглядит намного интересней.
вот кусок кода который нужно заменить или исправить  в оригинале
 rangeCollection = LineCollection(rangeSegments,
                                     colors=colors,
                                     linewidths=lw,
                                     antialiaseds=useAA,
                                     )

    barCollection = PolyCollection(barVerts,
                                   facecolors=colors,
                                   edgecolors=colors,
                                   antialiaseds=useAA,
                                   linewidths=lw,
         
спасибо за помощь
26.01.2018 07:06
Во первых, по поводу лимита, вот тут указано получать 10 000 записей
https://api.exmo.com/v1/trades/?pair=%s&limit=10000
Поставьте, для начала, 1000, или даже 100 - чем активнее торги по паре, тем больше число.
Будет работать быстрее.

Насчет горизонтальной линии - что вам мешает рисовать и перерисовывать просто линию на указанной высоте указанного цвета?
У вас будет массив, размерностью с macdhist, например, каждый элемент которого равен нужной цене, и он будет неизменен по всей длине..
26.01.2018 12:22
при запросах в 10000 график виснет через пару минут, при 500-1000 работает чуть дольше и график вполне приемлемый, при 100 запросах работает минут 20 а потом виснет, но это былобы терпимо но график никакой, пару кубиков на весь экран.
про линию не совсем разобрал. ясно что нужно фиксировать цену по оси у, а вот откуда брать данные по х, пока не понял, 
вот код
  xdate =[datetime.fromtimestamp(item) for item in sorted(chart_data)]
    
    ax.xaxis.set_major_locator(ticker.MaxNLocator(6))
    #ax.xaxis.set_minor_locator(ticker.MaxNLocator(6))
    def chart_date(x,pos):
        try:
            return xdate[int(x)]
			
        except IndexError:
            return ''		
    ax.grid(True, axis='y', which='major', color='grey', linestyle='dotted')    
    plt.title(PAIR)
    
    ax.xaxis.set_major_formatter(ticker.FuncFormatter(chart_date))
    
    candlestick2_ohlc(ax, quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6, colorup='#7cf70c', colordown='red', alpha=1.0)
  

ani = animation.FuncAnimation(fig, update_graph, interval=2000)

plt.show()
28.01.2018 10:49
Warning (from warnings module):
  File "C:\Program Files\Python37\советчик-график-RUB.py", line 77
    idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0
RuntimeWarning: invalid value encountered in sign
28.01.2018 10:50
ребят подскажите чего он ругается
28.01.2018 11:19
у меня на эксмо тоже так ругается когда сайт считает что его сильно задалбывают запросами, он сначала перестает возвращать некоторые данные(отсюда и ошибки) а затем вообще игнорирует нафиг, приходится перезагружать
28.01.2018 17:27
Бот периодически зависает. 
2018-01-28 20:23:26.873764   BTC_RUB  Обработка... - какое то количество секунд в Shell замирает.
Но счетчик времени, после "оживления", работает правильно.
2018-01-28 20:24:27.894003   BTC_RUB Условия рынка не подходят для торговли {'growing': False, 'trand': 'BEAR'}
29.01.2018 12:08
Ну "зависать" бот может по разному, возможно обрывы соединения интернета, а он с биржи тянет, либо объелся памяти если её маловато
28.01.2018 17:57
Хорошо бы записывать работу бота в лог файл.
28.01.2018 18:24
Лог пишется если USE_LOG = True! 
Запускаю советчик со звуковым сообщением, как рекомендовано выше. Он подает сигналы. А бот пишет 2018-01-28 21:13:19.385447 BTC_RUB Условия рынка не подходят для торговли {'trand': 'BEAR', 'growing': False}. Я чего то не понимаю или бот не работает как надо?
29.01.2018 12:07
А что не так?
Рынок в медвежьей фазе и не растет, бот не покупает..
29.01.2018 22:03
Это сообщения из бота Олега, который не торгует при любых комбинациях, (а может при каких то работает, не было случая проверить все):
1. {'growing': False, 'trand': 'BULL'}
2. {'growing': True, 'trand': 'BULL'}
3. {'growing': False, 'trand': 'BULL'}
4. {'growing': True, 'trand': 'BULL'}
При каких комбинациях будут покупки или продажи? 

Ваш бот два (есть и другие боты для эксмо, попроще - один и два) торгует, но не продает при частичной покупке, т.е. ждет до полного исполнения ордера на покупку, а за это время цена продажи может измениться не в лучшую сторону. Есть скрин с exmo  на котором видна разница бай-сейл за один раз и бай до полного исполнения.
Цены, как мне кажется лучше брать по верху стаканов. Настройки Вашего бота два:
CURRENCY_1 = 'ZEC' 
CURRENCY_2 = 'RUB'

BEAR_PERC = 70
BULL_PERC = 99.9

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

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

STOCK_TIME_OFFSET = 0 # Если расходится время биржи с текущим
30.01.2018 09:30
заколебался ловить % Быка и Медведя.... и у же совсем запутался Андрей ил кто действительн понял как они работают обьясните на пальцах
BEAR_PERC = 99.9
BULL_PERC = 99.9

BEAR_PERC = 1
BULL_PERC = 1

BEAR_PERC = 1
BULL_PERC = 99.9

BEAR_PERC = 99.9
BULL_PERC = 1

при таких настройках как будет выглядеть работа бота, в какие моменты он будет торговать?
30.01.2018 10:57
Возьмите код из статьи, меняйте проценты и запускайте, смотрите на графике как меняются зеленые конусы снизу. Зеленая область - это где бот будет торговать
30.01.2018 13:16
к сожалению боюсь у меня графики неправильно строятся я писал об этом выше
30.01.2018 13:17
Warning (from warnings module):
  File "C:\Program Files\Python37\советчик-график-RUB.py", line 77
    idx = numpy.argwhere(numpy.diff(numpy.sign(macd - macdsignal)) != 0).reshape(-1) + 0
RuntimeWarning: invalid value encountered in sign
30.01.2018 13:25
Warning (from warnings module):
  File "C:\Program Files\Python37\lib\site-packages\matplotlib\cbook\deprecation.py", line 106
    warnings.warn(message, mplDeprecation, stacklevel=1)
MatplotlibDeprecationWarning: The finance module has been deprecated in mpl 2.0 and will be removed in mpl 2.2. Please use the module mpl_finance instead.
30.01.2018 18:08
Андрей, здравствуйте.
Тут каша полная, "Возьмите код из статьи...........". Из какой? В этом форуме ветвить его сложно, т.е. не возможно. Можно развит проект здесь https://github.com/Calambuuur/Exmo_bot/tree/master/V .
30.01.2018 18:10
Не торгует. Это факт.
30.01.2018 19:01
В этой, конечно. Выше в статье примеры кода и графики.
Берите любой и запускайте
30.01.2018 19:34
Да, видимо интервалы слишком большие для текущих вялых торгов из-за падения.
Я обновил последний код, и добавил параметр SHOW_BOT_CHART - если поставить True, будет отрисовывать как торговал бы, если False - то гистограмму MACD
02.02.2018 18:01
Андрей! Вы подарили много радости - ковыряться с ботом.
Спасибо огромное!
Подскажи пожалуйста, как убрать в индикаторе "грязь"
[url=https://radikal.ru][img]https://a.radikal.ru/a41/1802/62/7d9a3bcbf86f.png[/img][/url]

Из за чего ложные срабатывания бота. Хотелось бы желтая линия сверху однозначно торговать, снизу не торговать, т.е. переключение строго по красным точкам ???
02.02.2018 18:08
Не удалось вставить картинку, тогда ссылка:
https://a.radikal.ru/a41/1802/62/7d9a3bcbf86f.png
"Грязь" это то что между второй и третьей точкой справа, провал на уровне возле 150.
В боте из за такого идет ложное срабатывание.
05.02.2018 07:49
Есть такое.. На графике видно, что тренд шел к изменению, но потом откатился.
Честно говоря не знаю, а что бы человек сделал, если бы видел, что macd сближаются и намечается разворот?
Как вариант можно страховать другим индикатором, RSI например, и решать на основе двух значений.
03.02.2018 19:51
Из бота Олега.
Сделал отмену действий по ордерам т.к. в алгоритме есть ошибка (поставил # перед create_buy и create_sell) .
В этих местах:
                            pass
                            #create_sell(pair=pair) 
и
                            pass
                            #create_buy(pair=pair)
Нарушено условие: "Чтобы, что-то продать, нужно, что-то купить". Хотя это не аксиома, при условии, что можно продать какое-то количество, для входа (в ручную например).
В результате ошибки, при отсутствии средств на покупку и положительном индикаторе будут выставлены ордера на продажу на неограниченное количество (пробовал на ETH_LTC). Если это не так - подскажите почему?
print('Выставляем ордер на продажу, т.к ситуация подходящая: '+str(macd_advice['trand'])+' '+str(macd_advice['growing']))
Вывод информации в лог, аналогичен информации в терминале.
05.02.2018 07:44
Бот устроен так, что сначала покупает, потом продает, и по кругу.
Если с ним мудрить - покупать руками и подсовывать валюту то да, последствия будут соответствующими, и это не ошибка.
Предлагаю вопросы, не относящиеся к теме статьи, обсуждать на форуме)
07.02.2018 06:26
Андрей, научите плиз, как прикрутить MACD графики к Вашему боту для биттрекса
07.02.2018 06:28
Допустим, я хочу оставить там только пару бакс-биток и выводить на экран график свечей, скользящие с точками пересечений и гистограмму как в вашем примере для эксмо
10.02.2018 17:15
Ох, это на целую статью тянет )
В принципе в боте уже есть свечи и цены их закрытия, вам всего лишь надо перенести функцию update_graph и передавать ей на вход данные свечей. Но это надо тут поменять, там прописать..
08.02.2018 19:21
Идея про измерение в процентах разницу между скользящими классная.
10.02.2018 17:16
Gracias =)
10.02.2018 16:43
Вопрос, возможно, глупый, но правильно ли я понял: в ботах по ссылкам
https://bablofil.ru/static/macd_bots/poloniex_macd.py
https://bablofil.ru/static/macd_bots/exmo_macd.py
функция анализа по MACD и прогнозирование тренда уже реализованы и боты сами себе советчики, сами размещают ордера, просто делают это молча без визуализации? А советчик с графиками работает независимо от бота и служит исключительно для визуализации работы бота и демонстрации его логики?
10.02.2018 17:11
Здравствуйте.
Да, всё именно так.
10.02.2018 17:15
Здравствуйте. Спасибо за ответ. Ещё такой вопрос: как в советчике сделать частоту запросов не раз в секунду, а пореже?
10.02.2018 17:18
Параметр interval отвечает за частоту обновления, 1000 = 1 секунда
animation.FuncAnimation(fig, update_graph, interval=1000)
11.02.2018 08:25
Гистограмма при продвижении графика накладывается сама на себя. С этим можно как-то бороться, кроме как перезапуском советника?
17.02.2018 16:52
Здравствуйте Андрей. Такая ситуация: Торгую на паре XRP_USD. Бот купил риплы по MACD на низах, но с учётом профита (хорошо, что рынок дёрнулся не много вниз и получилось купить по цене ещё ниже, а он ведь мог и не дёрнуться), далее сразу выставил ордер на продажу риплов с учётом профита, получается без учёта рекомендаций советчика "не торговать". Ну профит понятно, можно поставить 0. Как сделать так, чтобы бот торговал только когда разрешает индикатор?
18.02.2018 17:46
Добрый день, Андрей! Объясните пожалуйста, как будет действовать бот https://bablofil.ru/static/macd_bots/exmo_macd.py :
- есть CURRENCY_1, а CURRENCY_2 нет;
- есть CURRENCY_1 и CURRENCY_2 для закупки CURRENCY_1_MIN_QUANTITY ;
Вопрос сводится к тому, будет ли бот сливать CURRENCY_1, если его запустить при указанных условиях т.е. продаст ли он всю имеющуюся CURRENCY_1 и по какому курсу.
18.02.2018 18:01
Добрый день!
Практически полный алгоритм расписан тут https://bablofil.ru/bot-dlya-birjy-exmo/, даже есть блок-схема - вот прямая ссылка https://bablofil.ru/media/uploads/2017/04/11/bot1.png

- есть CURRENCY_1, а CURRENCY_2 нет;
Бот продаст CURRENCY_1 на сумму CAN_SPEND + PROFIT

- есть CURRENCY_1 и CURRENCY_2
Бот продаст CURRENCY_1 на сумму CAN_SPEND + PROFIT

В любом случае, если есть что продать, бот сначала продаст.
Потом купит и снова вернется к предыдущему шагу, если вкратце.

CURRENCY_1_MIN_QUANTITY - это не сумма торгов, а минимальный размер лота на бирже, биржа не даст купить/продать меньше, чем CURRENCY_1_MIN_QUANTITY

21.02.2018 04:00
В как можно перейти на анализ по МАСД только по гистограмме чтобы не сравнивать линии?
Т е покупаем при переходе гистограммы из "-" в "+", продаем в обратном порядке
26.02.2018 13:22
Бот продаст CURRENCY_1 на сумму CAN_SPEND + PROFIT
Тут ошибочка. Бот продаст CURRENCY_1 всю.
26.02.2018 13:47
Товарищи, давайте без флуда.
Есть форум, там можно создать любую тему
26.02.2018 15:05
Скачал обновленную версию и при запуске скрипт открывается и сразу же закрывается. Версия Python 3.6. В чем может быть проблема?
26.02.2018 15:37
Обычно проблема пишется перед закрытием.
Сделайте так - запустите cmd, там напишите python и путь к файлу, и посмотрите, что пишет
26.02.2018 15:50
Вот скриншот ошибки: https://i.imgur.com/beWJTLz.png?1
26.02.2018 16:42
Выполните в командной строке эти команды
pip install numpy
pip install requests
pip install matplotlib
26.02.2018 19:30
Осталась ошибка при запуске:
Traceback (most recent call last):
  File "D:\exmo_macd.py", line 7, in <module>
    import talib
ModuleNotFoundError: No module named 'talib'

А при попытке установки библиотеки - Ta-Lib выбивает такую ошибку.
https://i.imgur.com/pvDsall.png?1</module>
28.02.2018 17:35
Библиотеки все установились, пришлось запускать с Linux и выдало такую ошибку.
https://i.imgur.com/bFln3RX.jpg?1
13.03.2018 17:18
А есть возможность брать данные построения графика (в итоге и для работы индикатора) с биржи бинанс? Или YoBit?
Спасибо.
16.04.2018 15:16
Да, под статьей есть ссылки на другие статьи, там есть разбор API Binance и Yobit, по сути поменять пару строк..
22.06.2018 21:05
А чтобы поменять нужные пару строк, надо полгода не вылезать из компа, изучая python )))
18.03.2018 18:29
Добрый день!
Будет ли разобран пример с ботом для wex.nz?
16.04.2018 15:15
Добрый день!
Не совсем понимаю вопроса, бот для wex выложен - https://bablofil.ru/bot-dlya-birgi-wex/, алгоритм и прочее примерно как тут.
Уточните, что именно нужно разобрать?
20.03.2018 23:25
Добрый день!

Для binance такое как будет выглядеть?:
Спасибо

import numpy
import talib
import requests
import json
import time

from datetime import datetime

BEAR_PERC = 70
BULL_PERC = 30

PAIR = 'BTC_ETH'

def should_buy(pair):
    
    start_time = time.time() - 15*60*60
    resource = requests.get("https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999.=300" % (pair, start_time))
    data = json.loads(resource.text)

    quotes = {}
    quotes['close']=numpy.asarray([item['close'] for item in data])
    macd, macdsignal, macdhist = talib.MACD(quotes['close'], 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)

    hist_data = []
    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 # обнуляем пик спреда между линиями
        hist_data.append(v*1000)
 
    return activity_time

while True:
    print("Покупать?", should_buy(PAIR))
    time.sleep(1
23.03.2018 22:06
Добрый вечер!

Скажите пожалуйста, что означает эта ошибка:

RESTART: C:\Users\Администратор\Downloads\exmo_macd_romanbot.py ======
Traceback (most recent call last):
  File "C:\Users\Администратор\Downloads\exmo_macd_romanbot.py", line 6, in <module>
    import numpy
ModuleNotFoundError: No module named 'numpy'</module>
27.03.2018 04:31
Спасибо, разобрался!
04.04.2018 12:52
Андрей К. спасибо за труды - все очень интересно!

но т.к. не программист была куча плясок с бубном на win10 (x64) - поэтому решил написать, для таких же как сам, в чем удалось разобраться:

- через pip установился python 3.6
- талиб на него опять же через pip не вставал ни в какую даже после установки VisualStudio (оно мне вообще надо было?)
- благо по ссылке выше https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib лежит куча колес
----- с трудом сообразил что требуется  TA_Lib0.4.17cp36cp36mwin_amd64.whl (36 - версия питона, win - окна, amd64 - разрядность окон)
- спасибо помогло

Едем дальше:
- вставил ваш код - снова получаю кулак дружбы

<code>
Traceback (most recent call last):
  File "graph.py", line 7, in <module>
    from matplotlib.finance import candlestick2_ohlc
ModuleNotFoundError: No module named 'matplotlib.finance'
</module></code>

- оказалось теперь нужно использовать другой модуль mpl_finance
---- который "состоит из кода, извлеченного из устаревшего matplotlib.finance модуль вместе с несколькими примерами использования".
- ставим pip install git+https://github.com/matplotlib/mpl_finance.git
- заменяем 
<code>from matplotlib.finance import candlestick2_ohlc</code>
 на
<code>from mpl_finance import candlestick2_ohlc</code>
- всем profit!
04.04.2018 13:20
а вот из кода "смотрим в будущее"получил ошибку

    xdate=[datetime.fromtimestamp(item['date']) for item in data]
AttributeError: module 'datetime' has no attribute 'fromtimestamp'

пока не разобрался
04.04.2018 13:48
разобрался заменой

xdate=[datetime.fromtimestamp(item['date']) for item in data]

на

xdate=[datetime.datetime.fromtimestamp(item['date']) for item in data]
06.04.2018 14:13
Всем привет. Подскажите, как можно прикрутить к боту RSI индикатор?
Есть примерный код самого индикатора:
def rsiFunc(prices, n=14):
    deltas = np.diff(prices)
    seed = deltas[:n+1]
    up = seed[seed>=0].sum()/n
    down = -seed[seed<0].sum()/n
    rs = up/down
    rsi = np.zeros_like(prices)
    rsi[:n] = 100. - 100./(1.+rs)

    for i in range(n, len(prices)):
        delta = deltas[i-1] # cause the diff is 1 shorter

        if delta>0:
            upval = delta
            downval = 0.
        else:
            upval = 0.
            downval = -delta

        up = (up*(n-1) + upval)/n
        down = (down*(n-1) + downval)/n

        rs = up/down
        rsi[i] = 100. - 100./(1.+rs)

    return rsi
16.04.2018 15:38
Добрый день
Тут в коде используется MACD - talib.MACD(quotes['close'], fastperiod=12, slowperiod=26, signalperiod=9)
Но вы можете использовать RSI, STOCH  и т.п., что вам больше нравится.
Подробности - тут https://mrjbq7.github.io/ta-lib/func_groups/momentum_indicators.html
24.04.2018 22:01
Во-первых, спасибо Андрей, за интересные статьи, продолжайте нас радовать и далее...
        В данный момент переработал ваш код с графиками для биржи Binance. Однако в процессе лицезрения работы графиков я заметил, как "советчик" несколько раз моргает при определении точки входа в рынок с зеленого на красный и обратно, прежде чем начать строить трендовую линию (зеленую полосу на нижнем графике). По моему мнению это связано с тем, что процентное соотношение спреда между линиями MACD несколько раз меняется прежде чем определится и окончательно снизится ниже запланированного BEAR_PERC = 70.
        Сразу оговорюсь, я только начал программировать вообще, и на Python 3.6 в частности, по этому прикручивать для эксперимента Ваш код с MACD к боту на Binance я не решился, т.к. не понимаю, как Вы боретесь с этим миганием индикатора на вход в рынок, так, чтобы бот не выставлял несколько ордеров на покупку полагаясь на приходящие от "советчика" сигналы, а выставил только один.
        Кроме того, меня заинтересовал индикатор KDJ. Рассматривали ли Вы его как дополнительный сигнал для входа в рынок и выхода из него совместно с MACD? Если да, прошу поделиться мнением, а если есть ссылка на библиотеки, содержащие функцию или рабочий код RDJ в Python 3.6 поделитесь пожалуйста - хочу сам поэкспериментировать.
Заранее спасибо.
26.04.2018 08:44
По поводу мигания - скрипт берет все данные, и анализирует с начала - первое пересечение, второе, третье и т.п. В итоге вы видите последнее. Можно усложнить код, добавить какие-то проверки, но я, честно говоря, мигания не видел, и не вижу в этом особой нужды.
Насчет проверок все очень просто - код (покупок/продаж) не вызовется, пока не доработает предыдущий кусок кода. Т.е. индикатор может как угодно моргать, скрипеть, жужжать, но когда он прекратит и даст последние (актуальные) значения, вся процессия двинется дальше.
KDJ я не реализовывал, но глянул краем глаза, это пересечения нескольких скользящих (*MA). Скользящюю среднюю вы можете строить и без каких-либо библиотек, можете взять готовые из Talib, вызывать с разными параметрами и проверять на пересечение.
26.04.2018 15:43
Добрый день! Пробую запустить ботов , хотя бы один из вариантов. И получается забавная штука не работает не один . Пишет разные причины , вроде всё делаю по описаниям а не получается . Даже уже не знаю что делать уже крыша едет. Например первый Бот пишет Вроде запускается и деньги в том кол-.ве что указаны в коде а пишет
Открытых ордеров нет
buy 0.0005675477515121432 8809.83139599844
Выход, не хватает денег на создание ордера
Открытых ордеров нет
Номер два пишет что нет какой то библиотеки хот я выполнял все действия что били описаны. Вы не могли бы подсказать что я неправильно делаю. Я понимаю что не по теме просто не знаю где еще можно спросить совета. Заранее признателен.

28.04.2018 11:45
Добрый день!
Насчет первого случая - вы, вероятно, указываете не ту сумму для торгов, или она слишком мала для торговли
Насчет второго - выполните все по инструкции из статьи https://bablofil.ru/python-indicators/ (и особенно из комментариев)
29.04.2018 03:58
Добрый день!
Спасибо за ответ, попробую увеличить сумму . И ещё раз внимательно изучу статью.
29.04.2018 04:08
Доброго день!
Изменил сумму указал 15 дол. вот что пишет:
Выход, продолжаем надеяться купить валюту по указанному ранее курсу, со времени создания ордера прошло 79.48328137397766 секунд
Проверяем, что происходит с отложенным ордером 778802291
Частично исполненных ордеров нет
Изменения вносил в эту строку CAN_SPEND = 15 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1


29.04.2018 04:36
Доброго дня ! 
Видимо я тороплю события вроде первый бот заработал что то там вроде покупает и продаёт посмотрю.
При установки талиба возникли проблемы:
Command "c:\users\veser\appdata\local\programs\python\python36-32\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\veser\\AppData\\Local\\Temp\\pip-install-_75w55_7\\ta-lib\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\veser\AppData\Local\Temp\pip-record-q4it4yde\install-record.txt --single-version-externally-managed --compile" failed with error code 1 in C:\Users\veser\AppData\Local\Temp\pip-install-_75w55_7\ta-lib\
вот что пишет и не очень понимаю что ему не нравится , вроде папка как и написано находится в корневом каталоге. Не пойму где на косячил. Заранее признателен за помощь.
30.04.2018 19:50
Доброго времени суток! Нашёл комментарий на преведущий вопрос выше, попробовал воспользоваться и не смог сообразить куда скопировать колесо и как написать к нему путь. Никогда не сталкивался с этим.
04.05.2018 19:21
Доброго времени суток!
С первого робота удалось таки запустить увеличил сумму работает вреде что там даже уже и наторговал. Информации много очень интересно, но отсутствуют так сказать базовые знания. Никак не могу понят как посмотреть какой адрес вбивать. 
Пробовал запустить вторую версию ругается вот что пишет : 
Traceback (most recent call last):\Programs\Python\Python36-32\Эксперимент\exmo5.py", line 2, in <module>
    import talib
ModuleNotFoundError: No module named 'talib'
Хотя модуль стоит во всяком случае в командной строке об этом пишет.  </module>
06.05.2018 06:32
Добрый день! Спасибо вам за труд!
Как и многие жду код binance + индикаторы. Сейчас биржа набирает обороты, думаю интересно будет большому количеству народа.
10.05.2018 11:55
Добрый день!
Удалось таки запустить всех ботов , для таких "знатоков" опишу процедуру. В этом комментарии она описана -(
04.11.2017 15:04:10
Это он VisualStudio пытается найти на вашем компе. 
Что бы не ставить студию, можно скачать тут http://www.lfd.uci.edu/%7Egohlke/pythonlibs/ уже собранный whl файл talib, потом установить его pip install путь_к_файлу.whl )Но лично у меня возникла проблема как собственно написать этот путь написать , оказалось просто всё просто в поиске (там где вызываешь командную строку пишешь название файла он его находит , жмёшь правую кнопку мыши , выбираешь копировать путь, а дальше как в комментарии.
Спасибо .
03.09.2018 15:40
доброго времени суток. Подкручиваю бота для Binance, вставила апи_ключи, исправила на resource = requests.get('https://api.binance.com/api/v1/klines?symbol={pair}&interval={period}&limit=100'.format(pair=PAIR, period=PERIOD)), api_url='https://api.binance.com/api',
подключила библиотеки...
по итогу: выдает бесконечное число раз " 2018-09-03 23:31:45.609269 Найдены пары, по которым нет неисполненных ордеров: ['ZIL_BTC']
2018-09-03 23:31:45.636270 Работаем с парой ZIL_BTC
2018-09-03 23:31:46.294308 string indices must be integers
2018-09-03 23:31:46.332310 Получаем все неисполненные ордера по БД
2018-09-03 23:31:46.349311 Неисполненных ордеров в БД нет
2018-09-03 23:31:46.368312 Получаем из настроек все пары, по которым нет неисполненных ордеров
 и при этом есть неисполненный ордер!!! 

насильно останавливаю этот "процесс" и тут куча ошибок : Traceback (most recent call last):
  File "C:/Users/Cyber/Desktop/БОТ-ИНДИКАТОР/bot_new03.py", line 310, in <module>
    if should_buy(pair):
  File "C:/Users/Cyber/Desktop/БОТ-ИНДИКАТОР/bot_new03.py", line 53, in should_buy
    resource = requests.get('https://api.binance.com/api/v1/klines?symbol={pair}&interval={period}&limit=100'.format(pair=PAIR, period=PERIOD))
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\site-packages\requests\api.py", line 72, in get
    return request('get', url, params=params, **kwargs)
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\site-packages\requests\api.py", line 58, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\site-packages\requests\sessions.py", line 512, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\site-packages\requests\sessions.py", line 622, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\site-packages\requests\adapters.py", line 445, in send
    timeout=timeout
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\site-packages\urllib3\connectionpool.py", line 600, in urlopen
    chunked=chunked)
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\site-packages\urllib3\connectionpool.py", line 343, in _make_request
    self._validate_conn(conn)
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\site-packages\urllib3\connectionpool.py", line 849, in _validate_conn
    conn.connect()
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\site-packages\urllib3\connection.py", line 356, in connect
    ssl_context=context)
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\site-packages\urllib3\util\ssl_.py", line 359, in ssl_wrap_socket
    return context.wrap_socket(sock, server_hostname=server_hostname)
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 407, in wrap_socket
    _context=self, _session=session)
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 814, in __init__
    self.do_handshake()
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 1068, in do_handshake
    self._sslobj.do_handshake()
  File "C:\Users\Cyber\AppData\Local\Programs\Python\Python36-32\lib\ssl.py", line 689, in do_handshake
    self._sslobj.do_handshake()
KeyboardInterrupt


может сможите подсказать как решить проблему?
заранее спасибо :)</module>
14.11.2018 13:41
Видимо, пара неправильно указана
10.01.2019 13:16
Андрей, здравствуйте. Помогите, пожалуйста. Запускаю бота на полониксе, он выжидает сигнал от MACD и покупает валюту по рыночной цене с комиссией 0,2. После покупки выставляет ордер на продажу с наценкой под 2%. Менял настройки PROFIT_MARKUP_DOWN и PROFIT_MARKUP_UP, но бот по прежнему закупает по рынку и продает слишком дорого. Как можно сделать, чтобы после сигнала от macd, бот выставлял ордер в самый верх в стакане заявок на покупку (с комиссией мейкера) и в случае исполнения просто накидывал бы 2,5 процента к цене покупки и выставлял ордер на продажу?
13.01.2019 16:58
Здравствуйте,
Выложил запрошенный код сюда: https://forum.bablofil.ru/files/file/5-poloniex_macd/
13.01.2019 19:05
Спасибо за ответ. Продаёт вроде с адекватной наценкой, но закупился всё равно по комиссии тейкера (0,2%). Подскажите, как можно сделать, чтобы индикатор оценивал не пятиминутный график, а, например, двухчасовой? Там сигналы от macd более точные. Менял в этой ссылке "https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999.=300" в конце вместо 300 ставил 7200, но без особого успеха. И ещё вопрос: Как можно прикрепить к боту стоп-лосс? К примеру, бот закупается по сигналу от macd, выставляет ордер и ждёт продажи. В случае, если цена монеты падает на 1% от суммы покупки, то бот отменяет выставленный ранее ордер на продажу и продаёт по рынку, предотвращая тем самым потери, а затем снова ждёт сигнал от macd?
14.01.2019 07:07
Кажется разобрался с таймфреймом, чтобы индикатор оценивал не пятиминутные свечи, а получасовые или двухчасовые. В коде бота, в этой ссылке "https://poloniex.com/public?command=returnChartData&currencyPair=%s&start=%s&end=9999999999.=300" в конце, где число 300, нужно его поменять доступный в полониксе таймфрейм (300, 900, 1800, 7200, 14400, или 86400 - это в секундах). Затем я изменил "start_time = time.time() - 200*60*60", вместо 15 поставил 200, и поменял в настройках MACD "signalperiod=48".
03.02.2019 07:08
Для биттрекса добавлена аналогичная вещь, доступна тут
https://forum.bablofil.ru/topic/380-%D0%BE%D1%82%D1%80%D0%B8%D1%81%D0%BE%D0%B2%D0%BA%D0%B0-%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D0%BA%D0%B0-%D0%B4%D0%BB%D1%8F-macd/
12.02.2019 19:10
Ваш ресурс , наверно единственный где пишутся актуальные вещи , спалите тему , в итоге каждая домохазяйка будет торговать ботом , судя по некоторым вопросам несколько уже добрались до трейдинга ) 
Насколько ,  я понимаю функция talib.MACD не может помочь , при наличии малого количества данных . Я запускал и получал 
ее для другой бирже , в которой история торгов не велика , получил :
macd =  [nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
 nan nan nan nan nan nan nan nan]
 macdsignal =  [nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
 nan nan nan nan nan nan nan nan]
 macdhist =  [nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
 nan nan nan nan nan nan nan nan]
Подскажите , что можно использовать в данном случае , чтобы понять тренд , при малом количестве данных? 
неохота изобретать велосипед. 
Спасибо .
18.02.2019 11:44
Ну и хорошо, подстегнем рынок :)

По MACD - как вариант можно брать не свечи, а истории сделок.
Из этих историй сделок формировать свои свечи, например 11-секундные (просто для примера)
Т.е. берете за 11 секунд все сделки, самая большая цена за период будет high, самая низкая - low, самая ранняя open, самая поздняя - close, объемы торгов складываете... Если сделок за период не было берете значение предыдущей, как на многих биржах ставят. В итоге у вас будет МНОГО свечей :)
Правда, нужно учитывать, что чем короче свечи тем чаще ошибается macd..
11.09.2019 04:59
А зачем индикатору получать 10.000 ордеров каждую секунду если он рисует 5 минутки? Думается достаточно будет 100 ордеров один раз в 5 минут. А то включил индикатор и прощай ютуб :)
13.09.2019 11:51
Это смотря, сколько сделок в минуту, зависит от пары. Смотрите сами, конечно)
Вообще я пару раз писал в саппорт что бы добавили полноценные свечи в апи, но там кивают да да, и ниче не делается)
23.04.2020 06:04
Здравствуйте!
Вопросик появился.
Торговал, торговал у меня бот с МАКД.
Не шибко, но всё же и вот стал выдавать такую ошибку:
"buy 0.008639612120048917 185.19349917192127
Error 50381: More than 8 decimal places are not permitted for pair ETH_USD
Открытых ордеров нет"
Вроде такой ошибки ни у кого не было.
23.04.2020 11:46
Пока ждал, прочёл и заменил 2 строки кода.
my_need_price = avg_price - avg_price * (STOCK_FEE+PROFIT_MARKUP)
my_amount = CAN_SPEND/my_need_price
на
# my_need_price = avg_price - avg_price * (STOCK_FEE+PROFIT_MARKUP)
my_need_price = round((avg_price - avg_price * (STOCK_FEE+PROFIT_MARKUP)), 8)
# my_amount = CAN_SPEND/my_need_price
my_amount = round((CAN_SPEND/my_need_price), 8)
Всё вроде пошло работать дальше.
28.04.2020 11:24
При продаже тоже появлялась такая ошибка.
Аналогично исправил чуть код и при продаже.
Пожалуйста, Авторизуйтесь что бы оставить свой комментарий