Торговый сигнал LSTM

  • Торговый сигнал LSTM
  • Прогноз цен на акции с помощью ChatGPT и Finazon
  • Использование модели LSTM для прогнозирования фондового рынка
  • Высвобождение мощи LSTM

Торговый сигнал LSTM

Предисловие

В предыдущей статье мы использовали модель LSTM для прогнозирования цены акций. Мы использовали цену открытия, самую высокую цену, самую низкую цену, цену закрытия и объем торгов за предыдущие 10 дней, чтобы спрогнозировать цену закрытия на следующий день. Мы обнаружили, что модель работает не очень хорошо. Завтрашние акции были предсказаны только вчерашней ценой акций. В результате этого мы меняем наш подход и хотим использовать модель, чтобы помочь нам судить о покупках и продажах и реализовывать торговые стратегии. На этот раз мы добавили больше индикаторов функций, надеясь получить лучшие результаты.

Введение в индикаторы функций

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

Технические индикаторы

KD: Стохастический индикатор, который указывает на изменение текущей цены относительно прошедшего периода.RSI: индикатор силы цены акций, который указывает на силу как покупателей, так и продавцов.MACD: индикатор скользящей средней, который указывает на долгосрочную и краткосрочную конвергенцию или дивергенцию скользящих среднихMOM: Индикатор тренда, который указывает диапазон изменения ценовых трендов и направление рыночных трендов.

Общеэкономические показатели

Сигнал контрмеры делового климата Тайваня: важная общая экономическая переменная, которая представляет экономическую активность и может отражать изменения в деловом климате.Индекс VIX: волатильный индикатор, который также отражает настроения рынка и панику.Опережающий индикатор: экономический индикатор, который заранее отражает процветание и используется для прогнозирования будущей тенденции процветания.Среднее соотношение цены и прибыли тайваньских акций: Принимая среднее значение соотношения цены и прибыли листинговых компаний, можно увидеть, является ли общий взгляд инвестора на весь рынок оптимистичным или пессимистичным.

Загрузка данных

В этой статье ОС Windows используется в качестве системы и jupyter в качестве редактора.

import tejapi
import pandas as pd

tejapi.ApiConfig.api_key = "Your Key"
tejapi.ApiConfig.ignoretz = True

База данных

0050 Корректировка цены акций (день) — корректировка без учета дивидендов (TWN/APRCD1)Среднее соотношение цены и прибыли по акциям Тайваня — экономика в целом (GLOBAL/ANMAR)Сигнал контрмер к процветанию Тайваня — экономика в целом (GLOBAL/ANMAR)Опережающие индикаторы — общая экономика (GLOBAL/ANMAR)Chicago VIX Index — Международный фондовый индекс (GLOBAL/GIDX)

Загрузка данных

Период данных: 01.01.2011–15.11.2022.

0050 Скорректированная цена акции без учета дивидендов и цена ее открытия, цена закрытия, самая высокая цена, самая низкая цена, объем торгов

coid = "0050"
mdate = {'gte':'2011-01-01', 'lte':'2022-11-15'}
data = tejapi.get('TWN/APRCD1',
coid = coid,
mdate = {'gte':'2011-01-01', 'lte':'2022-11-15'},
paginate=True)


#開高低收、成交量
data = data[["coid","mdate","open_adj","high_adj","low_adj","close_adj","amount"]]
data = data.rename(columns={"coid":"coid","mdate":"mdate","open_adj":"open",
"high_adj":"high","low_adj":"low","close_adj":"close","amount":"vol"})

Технические индикаторы (KD, RSI, MACD, MOM)

from talib import abstract
data["rsi"] = abstract.RSI(data,timeperiod=14)
data[["macd","macdsig","macdhist"]] = abstract.MACD(data)
data[["kdf","kds"]] = abstract.STOCH(data)
data["mom"] = abstract.MOM(data,timeperiod=15)
data.set_index(data["mdate"],inplace = True)

Общие экономические показатели (среднее соотношение цены и прибыли по акциям Тайваня, сигнал противодействия деловому климату Тайваня, опережающие индикаторы, индекс Chicago VIX)

data1 = tejapi.get('GLOBAL/ANMAR',
mdate = mdate,
coid = "SA15",
paginate=True)
data1.set_index(data1["mdate"],inplace = True)
data1 = data1.resample('D').ffill()
data = pd.merge(data,data1["val"],how='left', left_index=True, right_index=True)
data.rename({"val":"pe"}, axis=1, inplace=True)
#芝加哥VIX指數
data2 = tejapi.get('GLOBAL/GIDX',
coid = "SB82",
mdate = mdate,
paginate=True)
data2.set_index(data2["mdate"],inplace = True)
data = pd.merge(data,data2["val"],how='left', left_index=True, right_index=True)
data.rename({"val":"vix"}, axis=1, inplace=True)
#景氣對策訊號
data3 = tejapi.get('GLOBAL/ANMAR',
coid = "EA1101",
mdate = mdate,
paginate=True)
data3.set_index(data3["mdate"],inplace = True)
data3 = data3.resample('D').ffill()
data = pd.merge(data,data3["val"],how='left', left_index=True, right_index=True)
data.rename({"val":"light"}, axis=1, inplace=True)
#領先指標
data4 = tejapi.get('GLOBAL/ANMAR',
coid = "EB0101",
mdate = mdate,
paginate=True)
data4.set_index(data4["mdate"],inplace = True)
data4 = data4.resample('D').ffill()
data = pd.merge(data,data4["val"],how='left', left_index=True, right_index=True)
data.rename({"val":"advance"}, axis=1, inplace=True)

Удалите пустые и бесполезные столбцы

data.set_index(data["mdate"],inplace=True)
data = data.fillna(method="pad",axis=0)
data = data.dropna(axis=0)
del data["coid"]
del data["mdate"]
data

Торговые сигналы

Мы выбираем скользящую среднюю в сочетании с индикатором импульса, чтобы определить тренд, и просто используем MA5 > MA20 и RSI5 > RSI 20, это оценивается как восходящий тренд.

data["short_mom"] = data["rsi"].rolling(window=10,min_periods=1,center=False).mean()
data["long_mom"] = data["rsi"].rolling(window=20,min_periods=1,center=False).mean()
data["short_mov"] = data["close"].rolling(window=10,min_periods=1,center=False).mean()
data["long_mov"] = data["close"].rolling(window=20,min_periods=1,center=False).mean()

Маркировка этикетки
Восходящий тренд обозначается как 1, в противном случае он отмечен как 0.

import numpy as np
data['label'] = np.where(data.short_mov > data.long_mov, 1, 0)
data = data.drop(columns=["short_mov"])
data = data.drop(columns=["long_mov"])
data = data.drop(columns=["short_mom"])
data = data.drop(columns=["long_mom"])

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

Предварительная обработка данных

Стандартизация данных

X = data.drop('label', axis = 1)
from sklearn.preprocessing import StandardScaler
X[X.columns] = StandardScaler().fit_transform(X[X.columns])
y = pd.DataFrame({"label":data.label})

Раздельный обучающий набор и тестовый набор с соотношением 7:3

import numpy as np
split = int(len(data)*0.7)
train_X = X.iloc[:split,:].copy()
test_X = X.iloc[split:].copy()
train_y = y.iloc[:split,:].copy()
test_y = y.iloc[split:].copy()

X_train, y_train, X_test, y_test = np.array(train_X), np.array(train_y), np.array(test_X), np.array(test_y)

Измените измерение данных на трехмерное в соответствии с требованиями модели

X_train = np.reshape(X_train, (X_train.shape[0],1,16))
y_train = np.reshape(y_train, (y_train.shape[0],1,1))
X_test = np.reshape(X_test, (X_test.shape[0],1,16))
y_test = np.reshape(y_test, (X_test.shape[0],1,1))

Модель LSTM

Загрузка посылок

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import Dropout
from keras.layers import BatchNormalization

Добавить модель LSTM
Добавьте четыре слоя слоев LSTM и используйте Dropout, чтобы предотвратить переобучение модели

regressor = Sequential()
regressor.add(LSTM(units = 32, return_sequences = True, input_shape = (X_train.shape[1], X_train.shape[2])))
regressor.add(BatchNormalization())
regressor.add(Dropout(0.35))
regressor.add(LSTM(units = 32, return_sequences = True))
regressor.add(Dropout(0.35))
regressor.add(LSTM(units = 32, return_sequences = True))
regressor.add(Dropout(0.35))
regressor.add(LSTM(units = 32))
regressor.add(Dropout(0.35))
regressor.add(Dense(units = 1,activation="sigmoid"))
regressor.compile(optimizer = 'adam', loss="binary_crossentropy",metrics=["accuracy"])
regressor.summary()

Результаты модели (обучающая выборка)
Установите эпохи на 100 раз.

train_history = regressor.fit(X_train,y_train,
batch_size=200,
epochs=100,verbose=2,
validation_split=0.2)

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

import matplotlib.pyplot as plt
loss = train_history.history["loss"]
var_loss = train_history.history["val_loss"]
plt.plot(loss,label="loss")
plt.plot(var_loss,label="val_loss")
plt.ylabel("loss")
plt.xlabel("epoch")
plt.title("model loss")
plt.legend(["train","valid"],loc = "upper left")

Важность переменных
Показано, насколько важны различные собственные значения. Он показывает, что MACD, среднее соотношение цены и прибыли тайваньских акций и RSI являются важными характерными значениями.

from tqdm.notebook import tqdm
results = []
print(' Computing LSTM feature importance...')
# COMPUTE BASELINE (NO SHUFFLE)
oof_preds = regressor.predict(X_test, verbose=0).squeeze()
baseline_mae = np.mean(np.abs(oof_preds-y_test))

results.append({'feature':'BASELINE','mae':baseline_mae})

for k in tqdm(range(len(list(test_X.columns)))):

# SHUFFLE FEATURE K
save_col = X_test[:,:,k].copy()
np.random.shuffle(X_test[:,:,k])

# COMPUTE OOF MAE WITH FEATURE K SHUFFLED
oof_preds = regressor.predict(X_test, verbose=0).squeeze()
mae = np.mean(np.abs( oof_preds-y_test ))
results.append({'feature':test_X.columns[k],'mae':mae})
X_test[:,:,k] = save_col

Результаты модели (тестовый набор)

Уровень точности тестового набора достигает 95,49%, что свидетельствует о том, что модель LSTM может реализовать нашу стратегию.

regressor.evaluate(X_test, y_test,verbose=1)

Сравнили реальные (Real) Labels с моделями прогноза (Predict) Labels

Визуализация стратегии

На рисунке ниже показан график представления тренда прогноза стратегии LSTM, красный цвет представляет собой восходящий тренд, а зеленый — нисходящий тренд.

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime as dt

df = result.copy()
df = df.resample('D').ffill()

t = mdates.drange(df.index[0], df.index[-1], dt.timedelta(hours = 24))
y = np.array(df.Close[:-1])

fig, ax = plt.subplots()
ax.plot_date(t, y, 'b-', color = 'black')
for i in range(len(df)):
if df.Predict[i] == 1:
ax.axvspan(
mdates.datestr2num(df.index[i].strftime('%Y-%m-%d')) - 0.5,
mdates.datestr2num(df.index[i].strftime('%Y-%m-%d')) + 0.5,
facecolor = 'red', edgecolor = 'none', alpha = 0.5
)
else:
ax.axvspan(
mdates.datestr2num(df.index[i].strftime('%Y-%m-%d')) - 0.5,
mdates.datestr2num(df.index[i].strftime('%Y-%m-%d')) + 0.5,
facecolor = 'green', edgecolor = 'none', alpha = 0.5
)
fig.autofmt_xdate()
fig.set_size_inches(20,10.5)

Бэктест стратегии

Торговая стратегия

Купите позицию и удерживайте ее, когда сигнал тренда направлен вверх, продайте исходную позицию, когда сигнал тренда направлен вниз, и закоротите позицию и удерживайте ее до следующего раза, когда сигнал передаст восходящий тренд, затем закройте позицию.

Примечание: Эта стратегия не учитывает комиссию за обработку, и все фонды входят и выходят из рынка.

Результат бэктеста

Совокупная доходность стратегии LSTM составляет 82,6%Фактическая стратегия (MA+MOM) совокупная доходность составляет 71,3%Совокупная доходность покупки и удержания составляет 52%

Заключение

Основная цель этого отчета заключается в том, может ли LSTM правильно судить о точках покупки и продажи в соответствии с первоначальной стратегией, которую мы установили. Результат положительный с высокой точностью 95,49%. Совокупная доходность результата бэктеста составляет 82,6%, что лучше, чем исходная стратегия с 52%. Вдобавок ко всему, стратегия LSTM значительно превосходит рынок. Первоначальная стратегия легко стирается вверх и вниз в период консолидации, что приводит к снижению торговых показателей. Напротив, стратегия LSTM дает относительно меньше торговых сигналов в описанной выше ситуации.

И последнее, но не менее важное: обратите внимание, что «Акции, упомянутые в этой статье, предназначены только для обсуждения, пожалуйста, не считайте это какими-либо рекомендациями или предложениями по инвестициям или продуктам». b10> Следовательно, если вас интересуют такие вопросы, как создание торговой стратегии, тестирование производительности, исследования, основанные на фактических данных, добро пожаловать на покупку планов, предлагаемых в TEJ E Shop и используйте полную базу данных, чтобы найти потенциальное событие.

Исходный код

#!/usr/bin/env python
# coding: utf-8

# In[16]:


#載入資料


# In[52]:


#下載資料
import tejapi
import pandas as pd
tejapi.ApiConfig.api_key = "Your Key"
tejapi.ApiConfig.ignoretz = True
coid = "0050"
mdate = {'gte':'2011-01-01', 'lte':'2022-11-15'}
data = tejapi.get('TWN/APRCD1',
                          coid = coid,
                          mdate = {'gte':'2011-01-01', 'lte':'2022-11-15'},
                          paginate=True)


#開高低收、成交量
data = data[["coid","mdate","open_adj","high_adj","low_adj","close_adj","amount"]]
data = data.rename(columns={"coid":"coid","mdate":"mdate","open_adj":"open",
                   "high_adj":"high","low_adj":"low","close_adj":"close","amount":"vol"})


# In[53]:


#技術指標
#動能 : KD、RSI、MACD、MOM
from talib import abstract
data["rsi"] = abstract.RSI(data,timeperiod=14)
data[["macd","macdsig","macdhist"]] = abstract.MACD(data)
data[["kdf","kds"]] = abstract.STOCH(data)
data["mom"] = abstract.MOM(data,timeperiod=15)
data.set_index(data["mdate"],inplace = True)


# In[54]:


#總經指標
#台股本益比
data1 = tejapi.get('GLOBAL/ANMAR',
                          mdate = mdate,
                          coid = "SA15",
                          paginate=True)
data1.set_index(data1["mdate"],inplace = True)
data1 = data1.resample('D').ffill()
data = pd.merge(data,data1["val"],how='left', left_index=True, right_index=True)
data.rename({"val":"pe"}, axis=1, inplace=True)
#芝加哥VIX指數
data2 = tejapi.get('GLOBAL/GIDX',
                   coid = "SB82",
                          mdate = mdate,
                          paginate=True)
data2.set_index(data2["mdate"],inplace = True)
data = pd.merge(data,data2["val"],how='left', left_index=True, right_index=True)
data.rename({"val":"vix"}, axis=1, inplace=True)
#景氣對策訊號
data3 = tejapi.get('GLOBAL/ANMAR',
                   coid = "EA1101",
                          mdate = mdate,
                          paginate=True)
data3.set_index(data3["mdate"],inplace = True)
data3 = data3.resample('D').ffill()
data = pd.merge(data,data3["val"],how='left', left_index=True, right_index=True)
data.rename({"val":"light"}, axis=1, inplace=True)
#領先指標
data4 = tejapi.get('GLOBAL/ANMAR',
                   coid = "EB0101",
                          mdate = mdate,
                          paginate=True)
data4.set_index(data4["mdate"],inplace = True)
data4 = data4.resample('D').ffill()
data = pd.merge(data,data4["val"],how='left', left_index=True, right_index=True)
data.rename({"val":"advance"}, axis=1, inplace=True)


# In[55]:


#刪除空值
data.set_index(data["mdate"],inplace=True)
data = data.fillna(method="pad",axis=0)
data = data.dropna(axis=0)
del data["coid"]
del data["mdate"]


# In[48]:


data


# In[56]:


#定義趨勢(5,20,5,20)
data["short_mom"] = data["rsi"].rolling(window=10,min_periods=1,center=False).mean()
data["long_mom"] = data["rsi"].rolling(window=20,min_periods=1,center=False).mean()
data["short_mov"] = data["close"].rolling(window=10,min_periods=1,center=False).mean()
data["long_mov"] = data["close"].rolling(window=20,min_periods=1,center=False).mean()


# In[57]:


#標記Label
import numpy as np
data['label'] = np.where(data.short_mov > data.long_mov, 1, 0)
data = data.drop(columns=["short_mov"])
data = data.drop(columns=["long_mov"])
data = data.drop(columns=["short_mom"])
data = data.drop(columns=["long_mom"])


# In[58]:


#觀察資料分佈情形
import matplotlib.pyplot as plt
fig = plt.figure
plot = data.groupby(["label"]).size().plot(kind="barh",color="grey")


# In[ ]:


#資料前處理


# In[59]:


#標準化
X = data.drop('label', axis = 1)
from sklearn.preprocessing import StandardScaler
X[X.columns] = StandardScaler().fit_transform(X[X.columns])
y = pd.DataFrame({"label":data.label})


# In[60]:


# 切割成學習樣本以及測試樣本
import numpy as np
split = int(len(data)*0.7)
train_X = X.iloc[:split,:].copy()
test_X = X.iloc[split:].copy()
train_y = y.iloc[:split,:].copy()
test_y = y.iloc[split:].copy()

X_train, y_train, X_test, y_test = np.array(train_X), np.array(train_y), np.array(test_X), np.array(test_y)


# In[61]:


#將資料改成三維
X_train = np.reshape(X_train, (X_train.shape[0],1,16))
y_train = np.reshape(y_train, (y_train.shape[0],1,1))
X_test = np.reshape(X_test, (X_test.shape[0],1,16))
y_test = np.reshape(y_test, (X_test.shape[0],1,1))


# In[62]:


test_X


# In[ ]:


#模型設計


# In[62]:


#載入套件
#import packages
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import Dropout
from keras.layers import BatchNormalization


# In[63]:


#加入模型
regressor = Sequential()
regressor.add(LSTM(units = 32, return_sequences = True, input_shape = (X_train.shape[1], X_train.shape[2])))
regressor.add(BatchNormalization())
regressor.add(Dropout(0.35))
regressor.add(LSTM(units = 32, return_sequences = True))
regressor.add(Dropout(0.35))
regressor.add(LSTM(units = 32, return_sequences = True))
regressor.add(Dropout(0.35))
regressor.add(LSTM(units = 32))
regressor.add(Dropout(0.35))
regressor.add(Dense(units = 1,activation="sigmoid"))
regressor.compile(optimizer = 'adam', loss="binary_crossentropy",metrics=["accuracy"])
regressor.summary()


# In[64]:


#模型結果
train_history = regressor.fit(X_train,y_train,
                          batch_size=200,
                          epochs=100,verbose=2,
                          validation_split=0.2)


# In[65]:


#模型評估
#畫出loss, val_loss
import matplotlib.pyplot as plt
loss = train_history.history["loss"]
var_loss = train_history.history["val_loss"]
plt.plot(loss,label="loss")
plt.plot(var_loss,label="val_loss")
plt.ylabel("loss")
plt.xlabel("epoch")
plt.title("model loss")
plt.legend(["train","valid"],loc = "upper left")


# In[26]:


#變數重要性
from tqdm.notebook import tqdm
results = []
print(' Computing LSTM feature importance...')
# COMPUTE BASELINE (NO SHUFFLE)
oof_preds = regressor.predict(X_test, verbose=0).squeeze() 
baseline_mae = np.mean(np.abs(oof_preds-y_test))

results.append({'feature':'BASELINE','mae':baseline_mae})           

for k in tqdm(range(len(list(test_X.columns)))):
                
  # SHUFFLE FEATURE K
  save_col = X_test[:,:,k].copy()
  np.random.shuffle(X_test[:,:,k])
                        
  # COMPUTE OOF MAE WITH FEATURE K SHUFFLED
  oof_preds = regressor.predict(X_test, verbose=0).squeeze() 
  mae = np.mean(np.abs( oof_preds-y_test ))
  results.append({'feature':test_X.columns[k],'mae':mae})
  X_test[:,:,k] = save_col


# In[27]:


#變數重要性視覺化
import matplotlib.pyplot as plt

print()
df = pd.DataFrame(results)
df = df.sort_values('mae')
plt.figure(figsize=(10,20))
plt.barh(np.arange(len(list(test_X.columns))+1),df.mae)
plt.yticks(np.arange(len(list(test_X.columns))+1),df.feature.values)
plt.title('LSTM Feature Importance',size=16)
plt.ylim((-1,len(list(test_X.columns))+1))
plt.plot([baseline_mae,baseline_mae],[-1,len(list(test_X.columns))+1], '--', color='orange',
  label=f'Baseline OOF\nMAE={baseline_mae:.3f}')
plt.xlabel(f'Fold {1} OOF MAE with feature permuted',size=14)
plt.ylabel('Feature',size=14)
plt.legend()
plt.show()


# In[ ]:


#模型結果(測試集)


# In[66]:


#評估模型準確率
regressor.evaluate(X_test, y_test,verbose=1)


# In[67]:


#查看測試資料預測結果
predict_x = regressor.predict(X_test) 
df_predict = pd.DataFrame(predict_x,columns = ["Buy"])
df_predict["Action"] = np.where(df_predict["Buy"] > 0.5, 1, 0)
result = pd.DataFrame({"Close":data.iloc[split:]["close"]})
result["Real"] = test_y["label"]
result["Predict"] = list(df_predict["Action"])
result["mdate"] = result.index
result['mdate'] = pd.to_datetime(result['mdate'],format='%Y/%m/%d')
result.set_index(result["mdate"],inplace=True)
result


# In[ ]:


#策略視覺化


# In[68]:


#視覺化Predict
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime as dt

df = result.copy()
df = df.resample('D').ffill()

t = mdates.drange(df.index[0], df.index[-1], dt.timedelta(hours = 24))
y = np.array(df.Close[:-1])

fig, ax = plt.subplots()
ax.plot_date(t, y, 'b-', color = 'black')
for i in range(len(df)):
    if df.Predict[i] == 1:
        ax.axvspan(
            mdates.datestr2num(df.index[i].strftime('%Y-%m-%d')) - 0.5,
            mdates.datestr2num(df.index[i].strftime('%Y-%m-%d')) + 0.5,
            facecolor = 'red', edgecolor = 'none', alpha = 0.5
            )
    else:
        ax.axvspan(
            mdates.datestr2num(df.index[i].strftime('%Y-%m-%d')) - 0.5,
            mdates.datestr2num(df.index[i].strftime('%Y-%m-%d')) + 0.5,
            facecolor = 'green', edgecolor = 'none', alpha = 0.5
            )
fig.autofmt_xdate()
fig.set_size_inches(20,10.5)


# In[69]:


#回測
test_data = data.iloc[split:].copy()
backtest = pd.DataFrame(index=result.index)
backtest["r_signal"] = list(test_data["label"])
backtest["p_signal"] = list(result["Predict"])
backtest["m_return"] = list(test_data["close"].pct_change())

backtest["r_signal"] = backtest["r_signal"].replace(0,-1)
backtest["p_signal"] = backtest["p_signal"].replace(0,-1)
backtest["a_return"] = backtest["m_return"]*backtest["r_signal"].shift(1)
backtest["s_return"] = backtest["m_return"]*backtest["p_signal"].shift(1)
backtest[["m_return","s_return","a_return"]].cumsum().hist()
backtest[["m_return","s_return","a_return"]].cumsum().plot()


# In[70]:


backtest[["m_return","s_return","a_return"]].cumsum()[-1:]

Прогноз цен на акции с помощью ChatGPT и Finazon

Полностью основанный на искусственном интеллекте подход к прогнозированию цен на акции

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

В этой статье мы сначала получим данные временных рядов акций, которые мы хотим предсказать, используя API временных рядов Finason, а затем передадим эти данные в программу, сгенерированную ChatGPT. Все процессы, включая подготовку данных, построение модели, прогнозирование и оценку модели, возьмет на себя ChatGPT. Без лишних слов, давайте погрузимся в статью!

Краткое содержание проекта

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

Затем я попросил ChatGPT помочь в составлении плана обширного проекта LSTM Python для прогнозирования цен на акции, и вот что он сгенерировал:

1. Obtaining data
2. Linear Regression
3. A basic LSTM model
4. Improving the LSTM model
5. Hyperparameter Tuning

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

1. Получение данных с помощью Finazon

Чтобы построить успешную модель машинного обучения, которая может прогнозировать с более высоким уровнем точности, данные качества и надежности должны быть предпочтительнее всего остального. Вот тут-то и вступает в игру Финазон. Finazon — это торговая площадка для данных различного характера, которые напрямую берутся из авторизованных источников, таких как SIP, Coinbase, Binance и т. д.

Для этого проекта мы будем прогнозировать цены на акции Apple, для которых нам нужны данные временных рядов за длительный период. Таким образом, я выбрал API данных фондового рынка США Finazon, предоставляемый SIP, охватывающий 100% рынков США. Подписавшись на данные, я использовал следующий код для извлечения исторических данных Apple за последние 4000 дней (около 10–11 лет):

import pandas as pd
import requests
from datetime import datetime as dt

api_key = 'YOUR API KEY'
page_no = [0,1,2,3,4]
data_dict = []

for i in page_no:
hist_json = requests.get(f'https://api.finazon.io/latest/time_series?publisher=sip&ticker=AAPL&interval=1d&page={i}&page_size=1000&order=desc&apikey={api_key}').json()['data']
data_dict.append(hist_json)

aapl_df = pd.DataFrame(columns = ['t', 'o', 'h', 'l', 'c', 'v'])

for i in range(0,len(data_dict)):
df = pd.DataFrame(data_dict[i])
aapl_df = aapl_df.append(df, ignore_index = True)

aapl_df = aapl_df[::-1].reset_index(drop = True)
aapl_df.columns = ['Date', 'Open', 'High', 'Low', 'Close', 'Volume']
aapl_df.Date = pd.to_datetime(aapl_df.Date.astype(int), unit = 's').dt.date
aapl_df.tail()

В этом коде нет ничего сложного. Для бесперебойной работы кода обязательно замените YOUR API KEY на ваш секретный ключ API Finazon, который вы можете получить после создания учетной записи у них. Мы сохраняем извлеченные данные, чтобы их можно было легко импортировать и вводить в предстоящую программу прогнозирования, а не делать вызовы API каждый раз. Одна вещь, которую я хотел бы добавить, заключается в том, что, хотя API имеет охват данных 40+ лет, я решил оставить его 10, так как этого более чем достаточно для нашей программы. Это окончательный кадр данных:

2. Линейная регрессия

Вместо того, чтобы сразу переходить к созданию модели LSTM, я хотел не торопиться с ChatGPT, чтобы получить представление о результатах, сгенерированных кодом, предоставленным ботом. Поэтому я попросил его написать мне программу на Python для построения базовой модели линейной регрессии с использованием Scikit Learn с целью прогнозирования цен на акции. Сначала он дал мне шаги, которые необходимо выполнить для построения регрессионной модели, а затем написал этот пример кода:

import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import r2_score, mean_squared_error
import matplotlib.pyplot as plt

# Get the stock data
df = pd.read_csv('aapl.csv').dropna()
df = df.set_index('Date')

# Add a column for the target variable
df['Price'] = df['Close']

# Define the features and target variable
features = ['Open', 'High', 'Low', 'Volume']
target = 'Price'

# Split the data into training and testing sets
train_size = 0.8
train_data = df[:int(train_size * len(df))]
test_data = df[int(train_size * len(df)):]

# Normalize the data
scaler = StandardScaler()
train_data[features] = scaler.fit_transform(train_data[features])
test_data[features] = scaler.transform(test_data[features])

# Train the model
model = LinearRegression()
model.fit(train_data[features], train_data[target])

# Make predictions on the test data
predictions = model.predict(test_data[features])

# Compute the R^2 score and RMSE
r2 = r2_score(test_data[target], predictions)
rmse = np.sqrt(mean_squared_error(test_data[target], predictions))

print(f'R^2 score: {r2:.4f}')
print(f'RMSE: {rmse:.4f}')

# Plot the predicted and actual values
plt.plot(test_data[target].values, label='Actual')
plt.plot(predictions, label='Predicted')
plt.legend()
plt.show()

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

Одна маленькая вещь, которую я бы сделал с этим кодом, — это поиграть с параметрами модели, чтобы определить наиболее идеальную модель для нашего случая, но это тема для другого дня, потому что основное внимание здесь уделяется пониманию кода ChatGPT и его результатов.

3. Базовая модель LSTM

Теперь пришло время улучшить игру и попросить ChatGPT создать программу Python для построения модели LSTM для прогнозирования цен на акции. Но прежде чем двигаться дальше, вот краткое описание LSTM: Long Short-Term Memory (LSTM) — это сложная нейронная сеть и мощный инструмент для анализа последовательных данных. Он выборочно сохраняет или забывает информацию, чтобы понять сложные последовательности данных. Это делает его идеальным для таких задач, как распознавание речи, обработка естественного языка и анализ данных временных рядов. Вот код, сгенерированный ChatGPT для построения прогнозной модели LSTM:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics import *
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout

# Load the stock price data
df = pd.read_csv('aapl.csv').dropna()
df = df.set_index('Date')

# Preprocess the data
scaler = MinMaxScaler()
df_scaled = scaler.fit_transform(df['Close'].values.reshape(-1, 1))

# Define the training and testing data
train_size = int(len(df_scaled) * 0.8)
train_data = df_scaled[:train_size, :]
test_data = df_scaled[train_size:, :]

# Define the function to create a sliding window dataset
def create_dataset(dataset, time_steps=1):
X_data, y_data = [], []
for i in range(len(dataset)-time_steps-1):
X_data.append(dataset[i:(i+time_steps), 0])
y_data.append(dataset[i + time_steps, 0])
return np.array(X_data), np.array(y_data)

# Define the time steps and create the sliding window dataset
time_steps = 60
X_train, y_train = create_dataset(train_data, time_steps)
X_test, y_test = create_dataset(test_data, time_steps)

# Reshape the data for LSTM input
X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 1))
X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))

# Define the LSTM model architecture
model = Sequential()
model.add(LSTM(units=64, return_sequences=True, input_shape=(X_train.shape[1], 1)))
model.add(Dropout(0.2))
model.add(LSTM(units=64, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(units=64, return_sequences=False))
model.add(Dropout(0.2))
model.add(Dense(units=1))

# Compile the model
model.compile(optimizer='adam', loss='mean_squared_error')

# Train the model
model.fit(X_train, y_train, epochs=50, batch_size=64, validation_data=(X_test, y_test), verbose=1)

# Make predictions
y_pred = model.predict(X_test)

# Inverse transform the predicted and actual values
y_pred = scaler.inverse_transform(y_pred)
y_test = y_test.reshape(y_pred.shape[0], 1)
y_test = scaler.inverse_transform(y_test)

# Evaluate the model
mse = mean_squared_error(y_test, y_pred)
msle = mean_squared_log_error(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)

print('MSE: ', mse)
print('MSLE: ', msle)
print('MAE: ', mae)
print('R-squared: ', r2)

# Plot the predicted vs actual values
plt.figure(figsize=(10, 6))
plt.style.use('fivethirtyeight')
plt.plot(y_test, label='Actual', linewidth = 3, alpha = 0.4)
plt.plot(y_pred, label='Predicted', linewidth = 1.5)
plt.xlabel('Days')
plt.ylabel('Stock Price')
plt.title('AAPL Stock Price Prediction')
plt.legend()
plt.show()

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

4. Совершенствование модели LSTM

Модель LSTM, которую мы только что построили и использовали для прогнозирования, очень упрощена по своей природе и может быть улучшена в различных аспектах. Поэтому я попросил ChatGPT дать мне несколько предложений по улучшению кода для лучшей модели LSTM, и вот что он может сказать об этом:

  1. Увеличьте количество слоев LSTM: Одним из способов повышения производительности модели является добавление в модель большего количества слоев LSTM. Это может помочь модели фиксировать более сложные закономерности в данных.
  2. Увеличьте количество нейронов в каждом слое: Еще один способ улучшить производительность модели — увеличить количество нейронов в каждом слое LSTM. Это может помочь модели изучить более сложные взаимосвязи между входными признаками и целевой переменной.
  3. Отрегулируйте скорость обучения: скорость обучения определяет, насколько модель корректирует свои веса в ответ на ошибку между прогнозируемыми и фактическими значениями. Небольшая скорость обучения может замедлить процесс обучения, в то время как большая скорость обучения может привести к тому, что модель превысит оптимальные веса. Настройка скорости обучения может повысить производительность модели.
  4. Добавить выпадающие слои: Выпадающие слои могут быть добавлены в модель, чтобы предотвратить переобучение. Этот метод случайным образом выбрасывает некоторые нейроны во время обучения, что может помочь модели лучше обобщать новые данные.
  5. Попробуйте разные функции активации: выбор функции активации может повлиять на способность модели изучать сложные взаимосвязи в данных. Эксперименты с различными функциями активации, такими как tanh, relu и sigmoid могут помочь улучшить производительность модели.
  6. Используйте больше данных: увеличение объема данных, используемых для обучения модели, может повысить ее производительность. Это может быть достигнуто либо за счет увеличения количества исторических данных за несколько лет, либо за счет использования дополнительных функций, таких как данные о настроениях на новостях или технические индикаторы.
  7. Используйте другую функцию потерь: выбор функции потерь также может повлиять на производительность модели. Использование функции потерь, которая больше подходит для данных временных рядов, таких как логарифмическая ошибка среднего квадрата (MSLE), может помочь повысить точность модели.

Это чертовски круто! Это просто дало нам полное руководство, которому нужно следовать, чтобы улучшить модель ИИ, в частности, LSTM в нашем случае. Затем я попросил ChatGPT включить все эти предложения в предыдущий код, и он вернул мне эту обновленную версию:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics import *
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
from tensorflow.keras.callbacks import EarlyStopping

# Obtain stock data for Apple
df = pd.read_csv('aapl.csv').dropna()

# Extract the closing prices
close_prices = df[["Date", "Close"]].copy()
close_prices.columns = ["ds", "y"]
close_prices.set_index("ds", inplace=True)

# Normalize the data
scaler = MinMaxScaler(feature_range=(0, 1))
close_prices_scaled = scaler.fit_transform(close_prices)

# Create training and testing data
train_size = int(len(close_prices) * 0.8)
train_data = close_prices_scaled[:train_size]
test_data = close_prices_scaled[train_size:]

# Define the number of time steps to look back
look_back = 60

# Create training and testing data for the LSTM model
def create_data(data):
X, Y = [], []
for i in range(look_back, len(data)):
X.append(data[i - look_back : i, 0])
Y.append(data[i, 0])
X, Y = np.array(X), np.array(Y)
X = np.reshape(X, (X.shape[0], X.shape[1], 1))
return X, Y

X_train, Y_train = create_data(train_data)
X_test, Y_test = create_data(test_data)

# Define the LSTM model
model = Sequential()

model.add(LSTM(units=64, return_sequences=True, input_shape=(X_train.shape[1], 1)))
model.add(Dropout(0.2))

model.add(LSTM(units=128, return_sequences=True))
model.add(Dropout(0.2))

model.add(LSTM(units=64))
model.add(Dropout(0.2))

model.add(Dense(units=1))

# Compile the model
model.compile(optimizer="adam", loss="mean_squared_logarithmic_error")

# Define the early stopping criteria
early_stop = EarlyStopping(monitor="val_loss", patience=10)

# Fit the model to the training data
history = model.fit(X_train, Y_train, epochs=100, batch_size=32, validation_data=(X_test, Y_test), callbacks=[early_stop])

# Make predictions on the test data
y_pred = model.predict(X_test)

# Inverse the scaling of the data
y_pred = scaler.inverse_transform(y_pred)
Y_test = scaler.inverse_transform([Y_test])

# Evaluate the model
mse = mean_squared_error(Y_test[0], y_pred)
msle = mean_squared_log_error(Y_test[0], y_pred)
mae = mean_absolute_error(Y_test[0], y_pred)
r2 = r2_score(Y_test[0], y_pred)

print('MSE: ', mse)
print('MSLE: ', msle)
print('MAE: ', mae)
print('R-squared: ', r2)

# Plot the predicted vs actual values
plt.figure(figsize=(10, 6))
plt.style.use('fivethirtyeight')
plt.plot(df["Date"][train_size + look_back :], Y_test.flatten(), label="Actual", linewidth = 3, alpha = 0.4)
plt.plot(df["Date"][train_size + look_back :], y_pred.flatten(), label="Predicted", linewidth = 1.5)
plt.title("LSTM: Actual vs Predicted")
plt.xlabel("Date")
plt.ylabel("Stock Price")
plt.legend()
plt.show()

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

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

Наблюдая за результатами, мы можем сделать вывод, что в производительность модели LSTM внесены некоторые улучшения. Оценка R2 новой модели увеличилась с 0,93 до 0,96, что указывает на более высокую точность прогнозирования, а оценки MSE, MSLE и MAE значительно снизились, что еще больше приблизило их к нулю, что, опять же, является хорошим признаком лучшей модели. Отныне ChatGPT действительно проделал большую работу по улучшению нашей модели.

5. Настройка гиперпараметров

Ни один проект AI & ML не обходится без настройки гиперпараметров. Вот небольшая предыстория настройки гиперпараметров: Процесс, который включает в себя настройку параметров модели машинного обучения для повышения ее производительности, называется настройкой гиперпараметров. Эти параметры, известные как гиперпараметры, задаются перед обучением модели и включают такие параметры, как скорость обучения, количество слоев и нейронов и т. д. Основной целью тонкой настройки этих параметров является повышение точности прогнозов модели. Вот код, сгенерированный ChatGPT при запросе на настройку гиперпараметров в ранее сгенерированной модели:

import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, LSTM, Dropout
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.wrappers.scikit_learn import KerasRegressor
from sklearn.model_selection import GridSearchCV, TimeSeriesSplit

# Download the data
df = pd.read_csv('aapl.csv').dropna()
df = df.set_index('Date')

# Scale the data
scaler = MinMaxScaler()
scaled_data = scaler.fit_transform(df['Close'].values.reshape(-1, 1))

# Define the training and test sets
train_size = int(len(scaled_data) * 0.8)
train_data = scaled_data[:train_size]
test_data = scaled_data[train_size:]

# Define the function to create the LSTM model
def create_model(neurons=50, layers=2, dropout=0.2, learning_rate=0.001):
model = Sequential()
for i in range(layers):
model.add(LSTM(units=neurons, return_sequences=True, input_shape=(train_data.shape[1], 1)))
model.add(Dropout(dropout))
model.add(LSTM(units=neurons))
model.add(Dropout(dropout))
model.add(Dense(units=1))
optimizer = Adam(learning_rate=learning_rate)
model.compile(optimizer=optimizer, loss='mean_squared_error')
return model

# Define the parameter grid for hyperparameter tuning
param_grid = {
'neurons': [50, 100, 200],
'layers': [2, 3],
'dropout': [0.2, 0.3],
'learning_rate': [0.001, 0.01]
}

# Define the time series split for cross-validation
tscv = TimeSeriesSplit(n_splits=3)

# Create the KerasRegressor for hyperparameter tuning
model = KerasRegressor(build_fn=create_model, epochs=50, batch_size=32, verbose=0)

# Perform the hyperparameter tuning
grid = GridSearchCV(estimator=model, param_grid=param_grid, cv=tscv, scoring='neg_mean_squared_error', n_jobs=-1)
grid_result = grid.fit(train_data, train_data)

# Print the best parameters and score
print("Best parameters: ", grid_result.best_params_)
print("Best score: ", np.sqrt(-grid_result.best_score_))

# Use the best model to make predictions on the test data
best_model = grid_result.best_estimator_.model
predictions = best_model.predict(test_data.reshape(-1, 1))
predictions = scaler.inverse_transform(predictions)

# Plot the predictions and actual values
import matplotlib.pyplot as plt

# Plot the predicted vs actual values
plt.figure(figsize=(10, 6))
plt.style.use('fivethirtyeight')
plt.plot(pd.to_datetime(df.index[train_size:]), df['Close'][train_size:], label='Actual', linewidth = 3, alpha = 0.4)
plt.plot(pd.to_datetime(df.index[train_size:]), predictions, label='Predicted', linewidth = 1.5)
plt.title(f"AAPL Stock Price Prediction")
plt.xlabel("Date")
plt.ylabel("Stock Price")
plt.legend()
plt.show()

Как и все другие программы, созданные ранее, этот код также следует чистой структуре, аккуратно написанным комментариям и довольно известной процедуре настройки гиперпараметров, которая заключается в определении param_grid и передаче сетки в функцию GridSearchCV для выполнения поиска сетки и определения наилучших параметров модели. Это лучшие параметры в соответствии с процессом настройки гиперпараметров ChatGPT:

Best parameters:  {'dropout': 0.3, 'layers': 2, 'learning_rate': 0.001, 'neurons': 200}
Best score: 0.02022405674165489

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

Заключительные мысли

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

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

Огромное спасибо Finazon за создание такого удивительного рынка данных. Мне очень нравится их платформа, потому что данные, которые они предоставляют, невероятно точны, что в конечном итоге помогло существенно повысить производительность модели. Я настоятельно рекомендую проверить их платформу, и многие могут найти ее очень полезной для своих будущих проектов и начинаний.

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

Использование модели LSTM для прогнозирования фондового рынка

Знакомство

Инвестирование в фондовый рынок — сложный бизнес, и даже самые опытные инвесторы изо всех сил пытаются сделать точные прогнозы о будущих тенденциях. В предыдущей статье под названием «StockProphet: Попытка предсказать фондовый рынок» мы исследовали, как деревья решений могут быть использованы для прогнозирования фондового рынка. Однако в этой статье мы сделаем еще один шаг вперед и познакомим вас с более продвинутой техникой машинного обучения — моделями Long Short-Term Memory (LSTM).

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

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

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

Итак, если вы готовы вывести свои прогнозы на фондовый рынок на новый уровень, давайте погрузимся! А для тех, кто пропустил нашу предыдущую статью о деревьях решений для прогнозирования фондового рынка, вы можете найти ее здесь: StockProphet: Попытка предсказать фондовый рынок

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

Вы можете найти репозиторий Github для этой статьи здесь: Pouyaexe/StockProphet

Что такое LSTM?

LSTM (Long Short-Term Memory) — это тип рекуррентной нейронной сети (RNN), которая особенно хорошо подходит для обработки последовательных данных. В отличие от традиционных нейронных сетей с прямой связью, которые обрабатывают каждый вход независимо друг от друга, RNN могут учитывать предыдущие входы при обработке нового ввода в последовательности. LSTM — это особый тип RNN, который способен захватывать долгосрочные зависимости в данных временных рядов путем выборочного сохранения или забывания информации с течением времени.

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

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

Райан Долфин имеет отличную статью о LSTM, которую вы можете найти здесь: LSTM Networks | Подробное объяснение

Подготовка данных

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

Во-первых, нам нужно загрузить исторические данные интересующего нас индекса фондового рынка. В этом примере мы будем использовать индекс Russell 1000, который является подмножеством индекса Russell 3000, который отслеживает результаты 1000 крупнейших компаний США.

import yfinance as yf

data = yf.download(tickers = '^RUI', start = '2012-03-11',end = '2022-07-10')

Далее мы добавим к данным некоторые технические индикаторы, которые могут помочь модели LSTM фиксировать более сложные закономерности на фондовом рынке. В этом примере мы добавим четыре технических индикатора: индекс относительной силы (RSI), экспоненциальную скользящую среднюю (EMA) с разной длиной.

import pandas_ta as ta

data['RSI'] = ta.rsi(data.Close, length=15)
data['EMAF'] = ta.ema(data.Close, length=20)
data['EMAM'] = ta.ema(data.Close, length=100)
data['EMAS'] = ta.ema(data.Close, length=150)

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

data['Target'] = data['Adj Close'] - data.Open
data['Target'] = data['Target'].shift(-1)

Чтобы обучить двоичную классификационную модель, нам нужно преобразовать целевую переменную в двоичную переменную, где 1 указывает на увеличение индекса фондового рынка, а 0 — на уменьшение или отсутствие изменений.

data['TargetClass'] = [1 if data.Target[i] > 0 else 0 for i in range(len(data))]

Наконец, нам нужно удалить несколько ненужных столбцов и удалить все строки, содержащие отсутствующие данные.

data['TargetNextClose'] = data['Adj Close'].shift(-1)data.dropna(inplace=True)
data.reset_index(inplace=True)
data.drop(['Volume', 'Close', 'Date'], axis=1, inplace=True)data_set = data.iloc[:, 0:11]
pd.set_option('display.max_columns', None)
data_set.head(20)

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

Масштабирование данных

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

В этом проекте мы используем MinMaxScaler из библиотеки scikit-learn для масштабирования данных. MinMaxScaler масштабирует все входные объекты до значения от 0 до 1. Этот масштабатор хорошо подходит для этого проекта, так как он сохраняет относительные различия между точками данных без изменений.

from sklearn.preprocessing import MinMaxScaler

sc = MinMaxScaler(feature_range=(0, 1))
data_set_scaled = sc.fit_transform(data_set)
print(data_set_scaled)

В приведенном выше коде показано, как использовать MinMaxScaler для масштабирования данных. Сначала мы импортируем MinMaxScaler из библиотеки scikit-learn. Затем мы создаем объект масштабирования и устанавливаем диапазон объектов в диапазоне от 0 до 1. Наконец, мы подгоняем объект масштабирования к набору данных и преобразуем его в масштабированную версию. Мы распечатываем масштабированные данные, чтобы увидеть, как они выглядят.

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

Несколько функций из данных, предоставленных модели

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

Мы возьмем 30 предыдущих значений каждого признака, чтобы предсказать текущее значение. Поэтому мы создадим список массивов для каждого объекта, а затем сложим их по третьему измерению.

X = []
backcandles = 30
print(data_set_scaled.shape[0])

for j in range(8):
X.append([])
for i in range(backcandles, data_set_scaled.shape[0]):
X[j].append(data_set_scaled[i - backcandles:i, j])

X = np.moveaxis(X, [0], [2])
X, yi = np.array(X), np.array(data_set_scaled[backcandles:, -1])
y = np.reshape(yi, (len(yi), 1))

Здесь мы создали список X для хранения массивов предыдущих значений каждого объекта. Мы использовали цикл для перебора всех функций и создания соответствующих массивов. Мы использовали функцию moveaxis() для сложения массивов по третьему измерению.

Мы также создали два массива, y и yiy содержит целевые значения для нашей модели, которые являются ценами закрытия. yi — это временный массив, в котором хранятся цены закрытия для всех временных шагов, кроме первых 30.

Далее мы разделим наши данные на обучающий и тестовый наборы. 80% данных мы будем использовать для обучения, а остальные 20% — для тестирования.

splitlimit = int(len(X) * 0.8)
X_train, X_test = X[:splitlimit], X[splitlimit:]
y_train, y_test = y[:splitlimit], y[splitlimit:]

Здесь мы использовали переменную splitlimit для определения индекса, в котором мы будем разбивать наши данные на обучающие и тестовые наборы. Мы использовали нарезку массивов, чтобы разделить наши данные на X_trainX_testy_train и y_test.

Создание модели LSTM

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

Входной размер модели LSTM равен 8, что соответствует количеству используемых нами технических индикаторов. Скрытое измерение составляет 150, что означает, что в слое LSTM 150 нейронов. Количество слоев равно 1, что означает, что у нас есть только один слой LSTM. Выходной размер равен 1, что соответствует прогнозируемой цене акций.

Мы будем использовать функцию убытка средней квадратичной ошибки (MSE) для измерения разницы между прогнозируемой ценой акций и фактической ценой акций. Мы будем использовать оптимизатор Адама для обновления весов модели LSTM во время обучения.

class LSTM(nn.Module):
def __init__(self, input_dim, hidden_dim, num_layers, output_dim):
super(LSTM, self).__init__()
self.hidden_dim = hidden_dim
self.num_layers = num_layers
self.lstm = nn.LSTM(input_dim, hidden_dim, num_layers, batch_first=True)
self.fc1 = nn.Linear(hidden_dim, output_dim)

def forward(self, x):
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_dim).requires_grad_()
c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_dim).requires_grad_()
out, (hn, cn) = self.lstm(x, (h0.detach(), c0.detach()))
out = self.fc1(out[:, -1, :])
return out

input_dim = 8
hidden_dim = 150
num_layers = 1
output_dim = 1

model = LSTM(input_dim, hidden_dim, num_layers, output_dim)

criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

В __init__ класса LSTM мы определяем слой LSTM с hidden_dim нейронами, num_layers слоями и batch_first=True, чтобы указать, что входной тензор имеет размер пакета в качестве первого измерения. Мы также определяем полностью связанный слой с одним нейроном для вывода прогнозируемой цены акций. В forward мы инициализируем скрытое и ячеистое состояния нулями, а затем передаем входной тензор в слой LSTM. Мы берем последний вывод слоя LSTM и передаем его на полностью связанный слой, чтобы получить прогнозируемую цену акции.

Затем мы определяем функцию потерь среднеквадратичной ошибки (MSE) и оптимизатор Адама с коэффициентом обучения 0,01.

Модельное обучение

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

Функция потерь и оптимизатор

В процессе обучения модель пытается оптимизировать свои параметры, чтобы минимизировать функцию потерь. В этом случае мы будем использовать среднеквадратичную ошибку (MSE) в качестве функции потерь.

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

Эпохи

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

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

Типовой код обучения

Для обучения нашей модели LSTM мы будем использовать следующий код:

input_dim = 8
hidden_dim = 150
num_layers = 1
output_dim = 1

model = LSTM(input_dim, hidden_dim, num_layers, output_dim)

criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

epochs = 30
losses = []

for epoch in range(epochs):
optimizer.zero_grad()
outputs = model(torch.Tensor(X_train))
loss = criterion(outputs, torch.Tensor(y_train))
loss.backward()
optimizer.step()
if epoch % 5 == 0:
print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, epochs, loss.item()))

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

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

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

Оценка модели

После обучения модели пришло время оценить ее работоспособность на тестовом наборе. Для этого нам нужно преобразовать наши массивы numpy в тензоры PyTorch и сделать прогнозы на тестовом наборе.

# Convert numpy arrays to PyTorch tensors
X_test_tensor = torch.Tensor(X_test)
y_test_tensor = torch.Tensor(y_test)

# Make predictions on the test set
with torch.no_grad():
y_pred_tensor = model(X_test_tensor)
y_pred = y_pred_tensor.cpu().numpy()

Сначала мы преобразуем X_test и y_test в тензоры PyTorch с помощью torch.Tensor() Затем мы используем обученную модель для прогнозирования тестового набора. Мы оборачиваем это в контекст torch.no_grad() чтобы гарантировать, что градиенты не вычисляются во время прогнозирования. Наконец, мы преобразуем прогнозируемые значения обратно в массив numpy с помощью метода cpu().numpy()

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

mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
print('MSE: {:.4f}, RMSE: {:.4f}'.format(mse, rmse))

Здесь мы используем mean_squared_error из scikit-learn для вычисления MSE, а затем берем квадратный корень, чтобы получить RMSE. Более низкие значения MSE и RMSE указывают на лучшую производительность модели.

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

Построение графика результатов

После оценки модели пришло время визуализировать результаты. Мы можем использовать Matplotlib для построения фактических и прогнозируемых цен на акции на тестовом наборе

# Plot the results
plt.figure(figsize=(16,8))
plt.plot(y_test, color='black', label='Test')
plt.plot(y_pred, color='green', label='Pred')
plt.legend()
plt.show()

Этот код создает график фактических цен на акции черным цветом и прогнозируемых цен на акции зеленым цветом. plt.figure(figsize=(16,8)) задает размер графика, plt.plot(y_test, color=’black’, label=’Test’) отображает фактические цены акций, а plt.plot(y_pred, color='green', label='Pred') отображает прогнозируемые цены акцийplt.plot(y_test, color='black', label='Test') Наконец, plt.legend() добавляет легенду к сюжету.

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

Заключение

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

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

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

Вы можете найти полный код для этого проекта в моем репозитории GitHub (LSTM.py): Pouyaexe/StockProphet

Высвобождение мощи LSTM

Изучение пределов предиктивной аналитики: сравнительный анализ моделей LSTM для прогнозирования цен на акции в различных сегментах рынка

Знакомство

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

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

Я решил сравнить прогнозную производительность по четырем различным типам акций: голубые фишки, представленные BMW.DE, акции роста, проиллюстрированные TSLA и BTC-USD, дивидендные акции на примере JNJ и акции с малой капитализацией, представленные ETSY.

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

Техническая концепция

Чтобы оценить производительность моей модели, я использовал среднюю абсолютную процентную ошибку (MAPE).

MAPE = (1/n) * Σ|[(Yi - Ŷi) / Yi]| * 100

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

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

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

Цель состоит в том, чтобы достичь MAPE менее 5% для прогнозирования скорректированного закрытия, которое является целевой переменной.

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

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

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

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

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

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

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

Цель моего проекта состояла в том, чтобы спрогнозировать скорректированную цену акций закрытия для будущих таймфреймов в 7, 14 и 28 дней. Я получил данные из Yahoo Finance API, популярного выбора для получения исторических данных об акциях.

Получив данные, я разделил их на обучающий, проверочный и тестовый наборы в соотношении 60:20:20 соответственно. Для того, чтобы сети LSTM могли обрабатывать данные, необходимо было преобразовать их в формат временных рядов. Ниже приведен пример преобразования данных.

Для начала важно определить размер окна, указывающий количество дней, которые модель должна учитывать для прогнозирования. Этот размер окна представляет собой X-данные для всех объектов, включая скорректированное закрытие. День, следующий за размером окна, представляет собой y-данные. В следующей итерации весь процесс смещается на один день и повторяется.

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

При построении графика данных объема по скорректированному закрытию некоторые значения выходят за пределы нормального диапазона и могут оказать негативное влияние на модель.

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

Исследовательский анализ данных (EDA)

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

  • Выбросы: Все наборы данных содержали выбросы, в основном в функции объема. Я счел важным обрабатывать эти выбросы, чтобы они не искажали результаты модели.
  • NaN-значения: В наборах данных не было обнаружено значений NaN, что указывает на хорошее общее качество данных.
  • Сравнение скользящих средних максимумов и минимумов: Я наблюдал значительные различия в ценах между высокими и низкими ценами в пиковые торговые периоды, что указывает на высокую волатильность в эти периоды.
  • Сравнение скользящего среднего открытия-закрытия-Adj_Close: Все наборы данных показали незначительные различия между ценами открытия и закрытия, за исключением BMW.DE и JNJ, где были обнаружены разные скорректированные значения закрытия.
  • Ежедневное изменение цены: Я обнаружил, что у BMW.DE были небольшие ежедневные изменения цен, указывающие на низкую волатильность, в то время как ETSY, JNJ, TSLA демонстрировали более высокую волатильность. Интересно, что BTC-USD оказался более стабильным, чем ожидалось.
  • Скорректированная корреляция закрытия/объема: Корреляции между скорректированным закрытием и объемом для ETSY и JNJ не было. BMW и Tesla показали небольшую отрицательную корреляцию, в то время как BTC-USD продемонстрировал небольшую положительную корреляцию.
  • Ежемесячная разница в ценах: Я не обнаружил последовательной закономерности повышения или понижения цен в одни и те же месяцы на протяжении многих лет. Это говорит о том, что акции не демонстрируют сильной сезонности, по крайней мере, в месячном исчислении.

Проектирование функций

Я обучил модель LSTM, используя шесть функций: «Открыть», «Закрыть», «Максимум», «Низкий», «Громкость» и «Скорректированное закрытие». Интересно, что производительность модели снизилась, когда я ввел еще 11 дополнительных функций, включая скользящие средние, средний истинный диапазон, полосу Боллинджера, конвергенцию-дивергенцию скользящих средних, индекс относительной силы, стохастический осциллятор и стохастический сигнал. Похоже, что эти дополнительные функции добавили больше шума, чем ценной прогностической информации.

Более высокий балл MAPE при использовании дополнительных функций может быть вызван несколькими причинами:

  1. Переобучение: Дополнительные функции могли привести к появлению шума или нерелевантной информации в модели, что привело к ее переподготовке обучающих данных и плохой работе с тестовыми данными.
  2. Мультиколлинеарность: Дополнительные признаки могут быть сильно коррелированы друг с другом или с существующими признаками, что приводит к проблемам мультиколлинеарности, которые могут затруднить для модели различение их индивидуальных эффектов.
  3. Качество данных: дополнительные функции могли содержать ошибки или отсутствующие значения, которые отрицательно влияли на производительность модели.
  4. Сложность: Дополнительные функции могли увеличить сложность модели, что затруднило ее обучение или интерпретацию.
  5. Отсутствие актуальности: дополнительные функции, возможно, просто не имели отношения к поставленной задаче прогнозирования, и их включение могло добавить ненужную сложность без повышения производительности.

Вот визуальное сравнение между моделью с 6 функциями и моделью с 17 функциями для того же запаса.

Сравнение 6 функций:

Сравнение 17 функций:

Визуально здесь есть явные отличия.

Моделирование

Учебный процесс велся на протяжении 200 эпох. Чтобы настроить модель, я случайным образом сгенерировал и протестировал различные параметры в течение 20 раундов, включая следующие параметры.

{'window_size': [4, 8, 12, 20], 
'lstm_
units': [16, 32, 64, 128],
'dense_units': [16, 32, 64, 128],
'learning_
rate': [0.0001, 0.001, 0.01, 0.1]}

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

На этапе моделирования я извлек данные из базы данных SQL, после чего последовало разделение, обучение и проверка модели. Я создал графики валидации для визуального сравнения фактических и прогнозируемых значений. Затем я использовал обученную модель для прогнозирования скорректированной цены закрытия на следующие 7, 14 и 28 дней. Эти прогнозы также были визуализированы с использованием графиков для облегчения интерпретации. Вот пример для предсказания.

Заключение

Запустив свою модель на различных типах акций, я обнаружил, что акции роста (TSLA и BTC-USD) и акции с малой капитализацией (ETSY) показали худшие результаты, чем акции голубых фишек (BMW.DE) и дивидендные акции (JNJ). Это было очевидно из сравнительных графиков, которые я сгенерировал.

Производительность стокового автомобиля «BMW. DE’:

Показатели акции «TSLA»:

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

Чтобы просмотреть дополнительные визуальные сравнения, посетите мой профиль на Github (ссылка указана в конце статьи).

Тем не менее, мне удалось получить оценку MAPE в размере <5% от предыдущих.

Что касается будущих улучшений, есть несколько потенциальных путей для изучения. Например, я мог бы реализовать форму перекрестной проверки, предназначенную для анализа временных рядов, или исследовать другие модели машинного обучения, такие как дерево решений Gradient Boosting или Autoregressive Integrated Moving Average (ARIMA) для сравнения. Я также мог бы попробовать различные переменные количества функций, чтобы увидеть, какое идеальное число будет для этой цели.

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

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

Заметка: Чтобы узнать больше о моем алгоритме, перейдите по ссылке на мой Github-Profile.

Ссылки

Yahoo Финансы. (По состоянию на 16 мая 2023 г.). Исторические данные по акциям BMW.DE. https://finance.yahoo.com/quote/BMW.DE/history?p=BMW.DE

Yahoo Финансы. (По состоянию на 16 мая 2023 г.). Исторические данные по акциям TSLA. https://finance.yahoo.com/quote/TSLA/history?p=TSLA

Хогг, Г. (ведущий). (2021, 12 марта). Пример прогноза фондового рынка LSTM. [Видеофайл]. Получено с https://www.youtube.com/watch?v=QIUxPv5PJOY&t=2002s

Хогг, Г. (Автор). (По состоянию на 16 мая 2023 г.). Модель LSTM для блокнота прогнозов фондового рынка. [Блокнот Google Colab]. Получено с https://colab.research.google.com/drive/1b3CUJuDOmPmNdZFH3LQDmt5F0K3FZhqD?usp=sharing

Источник 1

Источник 2

Источник 3

Источник 4