Делает ли программа больше данных более или менее надежной?

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

Концепция:

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

Единственный индикатор, который я буду использовать, - это простая скользящая средняя. Два простых списка скользящих средних будут использоваться в качестве входных данных нейронной сети. Первая SMA будет иметь значение 60. Другая SMA будет иметь значение 4. Это потому, что классическая торговая стратегия для SMA - это пересечение между этими двумя линиями SMA. Это означало бы, что если бы нейронная сеть обнаружила подобный паттерн, она добавила бы больше доказательств того, что это действительно работает.

Код:

Шаг 1 | Предпосылки:

from keras.models import Sequential
from keras.layers import Dense,LSTM,BatchNormalization,Flatten
from matplotlib import pyplot as plt
import requests
import json
import numpy as np

Импорт keras предназначен для импорта слоев и инфраструктуры, необходимых для построения нейронной сети. Я буду использовать запросы для получения данных и JSON для анализа данных.

Шаг 2 | SMA:

def SMA(prices,value):
    means = []
    count = 0
    while value+count <= len(prices):
        pre_val = prices[count:value+count]
        count +=1
        means.append(np.mean(pre_val))
    return means

Эта функция возвращает строку SMA в виде списка, когда вводятся цены и значение SMA. На самом деле это довольно просто. Программа просто вычисляет скользящее среднее значение цены акции с течением времени.

Если вы хотите попробовать другие технические индикаторы, вы можете использовать мои программы, использующие библиотеку talib:

MACD:

import yfinance
import talib
from matplotlib import pyplot as plt
data = yfinance.download('NFLX','2016-1-1','2020-1-1')
data["macd"], data["macd_signal"], data["macd_hist"] = talib.MACD(data['Close'])
fig = plt.figure()
fig.set_size_inches((25, 18))
ax_macd = fig.add_axes((0, 0.24, 1, 0.2))
ax_macd.plot(data.index, data["macd"], label="macd")
ax_macd.plot(data.index, data["macd_signal"], label="signal")
ax_macd.legend()

RSI:

import yfinance
import talib
from matplotlib import pyplot as plt
from mplfinance.original_flavor import candlestick_ohlc
from matplotlib.pylab import date2num
data = yfinance.download('NFLX','2016-1-1','2020-1-1')
rsi = talib.RSI(data["Close"])
fig = plt.figure()
fig.set_size_inches((25, 18))
ax_rsi = fig.add_axes((0, 0.24, 1, 0.2))
ax_rsi.plot(data.index, [70] * len(data.index), label="overbought")
ax_rsi.plot(data.index, [30] * len(data.index), label="oversold")
ax_rsi.plot(data.index, rsi, label="rsi")
ax_rsi.plot(data["Close"])
ax_rsi.legend()

Parabolic SAR:

sar = talib.SAR(df['High'], df['Low'], 0.020)
fig = plt.figure()
fig.set_size_inches((20, 16))
ax_candle = fig.add_axes((0, 0.72, 1, 0.32))
ohlc = []
for date, row in df.iterrows():
    openp, highp, lowp, closep = row[:4]
    ohlc.append([date2num(date), openp, highp, lowp, closep])
candlestick_ohlc(ax_candle, ohlc, colorup="g", colordown="r", width=0.8)
plt.plot(sar,'ro')
plt.show

Шаг 3 | Данные доступа:

import yfinance
df = yfinance.download('AAPL','2020-1-1','2021-01-27')
close = df['Close']

Я буду использовать данные AAPL в качестве основы, но вы можете использовать и другие компании. Вот примеры загрузки других данных компании:

import yfinance
df = yfinance.download('MSFT','2020-1-1','2021-01-27')
close = df['Close']

import yfinance
df = yfinance.download('TSLA','2020-1-1','2021-01-27')
close = df['Close']

Шаг 4 | Значения SMA:

sma_1 = SMA(close,60)
sma_2 = SMA(close,4)

В результате получатся линии SMA 60 и 4, а вот график линий SMA:

Но, похоже, есть проблема: есть отсечка на 700! Почему это так? Это связано с тем, что SMA 60 недостаточно данных для вычисления среднего из последних 60 точек данных. Это означает, что мы должны удалить последний бит, который SMA 60 не может вычислить.

sma_1 = np.array(sma_1).reshape(len(sma_1),1)
sma_2 = np.array(sma_2).reshape(len(sma_2),1)
sma_2 = sma_2[:-60]
print(len(sma_1),len(sma_2))
plt.plot(sma_1)
plt.plot(sma_2)

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

smas = np.hstack((sma_1,sma_2))
smas.shape
X = np.array(smas)
y = np.array(close_price[:-59])
X.shape,y.shape

Затем два SMA соединяются с помощью np.hstack, чтобы значения располагались рядом. При этом значения X и y для сети были установлены.

Шаг 5 | Нейронная сеть:

model = Sequential()
model.add(Dense(100,input_shape = (None,2)))
model.add(Dense(128))
model.add(Dense(1))
print(model.summary())
model.compile(optimizer = 'adam', loss = 'mse')
model.fit(X,y,epochs = 100,validation_split = 0.33)

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

ConvLSTM:

model = Sequential()
    model.add(TimeDistributed(Conv1D(filters=128, kernel_size=1, activation='relu'), input_shape=(None, n_steps, n_features)))
    model.add(TimeDistributed(MaxPooling1D(pool_size=2, strides=None)))
    model.add(TimeDistributed(Conv1D(filters=128, kernel_size=1, activation='relu')))
    model.add(TimeDistributed(MaxPooling1D(pool_size=2, strides=None)))
    model.add(TimeDistributed(Conv1D(filters=128, kernel_size=1, activation='relu')))
    model.add(TimeDistributed(MaxPooling1D(pool_size=2, strides=None)))
    model.add(TimeDistributed(Conv1D(filters=128, kernel_size=1, activation='relu')))
    model.add(TimeDistributed(Flatten()))
    model.add(LSTM(128,return_sequences = True))
    model.add(LSTM(64))
    model.add(BatchNormalization())
    model.add(Dense(1))
    model.compile(optimizer=optimizer, loss='mse')

LSTM:

model = Sequential()
        model.add(LSTM(100, activation='relu', kernel_initializer='he_normal', input_shape=(n_steps,1)))
        model.add(Dense(50, activation='relu', kernel_initializer='he_normal'))
        model.add(Dense(50, activation='relu', kernel_initializer='he_normal'))
        model.add(Dense(50, activation='relu', kernel_initializer='he_normal'))
        model.add(Dense(50, activation='relu', kernel_initializer='he_normal'))
        model.add(Dense(50, activation='relu', kernel_initializer='he_normal'))
        model.add(BatchNormalization())
        model.add(Dense(1))

Глубокая плотность:

model = tensorflow.keras.Sequential()
        model.add(Dense(50, activation='relu', kernel_initializer='he_normal', input_shape=(len(data[0]),)))
        model.add(Dense(50, activation='relu', kernel_initializer='he_normal'))
        model.add(BatchNormalization())
        for i in range(10):
            model.add(Dense(50, activation='relu', kernel_initializer='he_normal'))
            model.add(Dropout(0.5))
            model.add(Dense(50, activation='relu', kernel_initializer='he_normal'))
            model.add(BatchNormalization())
        model.add(BatchNormalization())
        model.add(Dense(1))

Шаг 5 | Оценка прибыли:

def estimate_profits(pred,y):
    profits = 0
    investment = 100
    log = []
    for i in range(len(y)-1):
        if pred[i][0] > y[i]:
            trade = 'buy'
        elif pred[i][0] < y[i]:
            trade = 'sell'
        else:
            trade = None
        if y[i+1] > y[i]:
            correct_trade = 'buy'
        elif y[i+1] < y[i]:
            correct_trade = 'sell'
        else:
            correct_trade = None
        if correct_trade:
            if trade == correct_trade:
                profits += 0.8*investment
                log.append(1)
            else:
                profits -= investment
                log.append(0)
    accuracy = round(log.count(1)/len(log)*100)
    return profits,accuracy
profit,acc = estimate_profits(X,y)
profit /= 100
acc,profit

Это действительно базовая функция, которая вычисляет прибыль и точность модели, если она используется в течение периода времени, на котором она обучалась. Я использую это, потому что величина убытка не указывает на то, будет ли модель прибыльной или нет.

Функция возвращает:

(63, 124.4)

Это означает, что модель может правильно угадать, будет ли цена акций увеличиваться или уменьшаться в 63% случаев, и принесет общую прибыль в размере 124,4 доллара, учитывая каждый раз инвестиции в 1 доллар.

Заключение:

На рисунке ниже показаны все случаи, когда модель покупала акцию, а также две линии SMA.

Мы ясно видим, что в большинстве случаев цены на покупку привязаны к данным 60 SMA! Вдобавок, похоже, что модель действительно следует идее пересечения SMA. Например, для пересечения около отметки 600 модель не совершает сделки до тех пор, пока не будет пересечена! Может быть, идея пересечения SMA имеет свои достоинства!

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

Мои ссылки:

Если вы хотите увидеть больше моего контента, нажмите эту ссылку.