【量化交易笔记】8.基于深度学习(LSTM)预测股票价格

前言

前一章节,已作随机森林来预测股票价格,也是一种比较常见的方法,本章基于深度学习算法来处理时间序列,来预测股票未来的价格。LSTM是一种特殊类型的循环神经网络(RNN),在自然语言处理和时间序列数据分析等任务中取得了显著成果。LSTM通过处理序列数据中的长期依赖关系,能够更好地捕捉时间序列数据的特征和模式。这使得它成为预测股票价格这类时间相关数据的有力工具。关于LSTM 在之前的文章中也略作介绍。
我们仍以上一章的数据,采用类似于上一章的处理方式进行处理。

获取数据

本章我们采用 tensorflow框架的keras 来实现LSTM。

# 加载相应的库
import numpy as np
import pandas as pd
import tensorflow as tf
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus']=False

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

from sklearn.preprocessing import MinMaxScaler

%matplotlib inline

这部分内容,仍以sh.60000为例,从2019年1月1日 到至今天(2023-5-31)。

# 加载数据
df=pd.read_csv("data/sh.600000.csv",parse_dates=["date"],index_col=[0])
df.head()
datecodeopenhighlowclosepreclosevolumeamountadjustflagturntradestatuspctChgisST
2019-01-02sh.6000008.0793118.1207857.9465918.0461318.12908023762822229625669.020.0845541-1.0204120
2019-01-03sh.6000008.0461318.1456708.0129518.1373758.04613118654262181975985.020.06637611.1340270
2019-01-04sh.6000008.0710168.2949808.0461318.2618008.13737527172844268964563.020.09668811.5290480
2019-01-07sh.6000008.3696358.3696358.2286208.2783908.26180023597376235440197.020.08396510.2007980
2019-01-08sh.6000008.3198658.3198658.2203258.2618008.27839015104933150501650.020.0537471-0.2003960

分离数据

由于是时间序列,特征选 'open','high','low','close','volume','turn',考虑到volume得范围比较大,而股票价格,换手率比较小,采用MinMaxScaler对数据进行归一化处理,进行统一缩放到相同大小。

cols=['open','high','low','close','volume','turn']
df=df[cols]

scaler = MinMaxScaler(feature_range=(0,1))
df_scaled = scaler.fit_transform(df)
数据集处理

我们想用前30天数据预测第二天收盘价,这里的30天,即所有数据,由于LSTM 模型的特殊性,采用createXY函数生成数据。
具体这个函数

def createXY(dataset,n_past):
    j=0
    dataX = []
    dataY = []
    for i in range(n_past, len(dataset)):       
        x=dataset[i - n_past:i, 0:dataset.shape[1]]
        if (i+n_past>=len(dataset)):
            y=0
        else:
            y=dataset[i-1+n_past,3]
        dataX.append(x) 
        dataY.append(y)    
    return np.array(dataX),np.array(dataY) 
dataX,dataY=createXY(df_scaled,30)

让我们看看上面的代码中做了什么:
n_past是我们在预测下一个目标值时将在过去查看的步骤数。
这里使用30,意味着将使用过去的30个值(包括目标列在内的所有特性)来预测第31个目标值。
因此,在trainX中我们会有所有的特征值,而在trainY中我们只有目标值。
让我们分解for循环的每一部分
对于训练,dataset = df_for_training_scaled, n_past=30
当i= 30:
data_X.addend (df_for_training_scaled[i - n_past:i, 0:df_for_training.shape[1]])
从n_past开始的范围是30,所以第一次数据范围将是-[30 - 30,30,0:6] 相当于 [0:30,0:6]
因此在dataX列表中,df_for_training_scaled[0:30,0:6]数组将第一次出现。
现在, dataY.append(df_for_training_scaled[i,3])

i = 30,所以它将只取第30行开始的close(因为在预测中,我们只需要close列,所以列范围仅为3,表示close列)。
第一次在dataY列表中存储df_for_training_scaled[30,3]值。
所以包含5列的前30行存储在dataX中,只有close列的第31行存储在dataY中。然后我们将dataX和dataY列表转换为数组,它们以数组格式在LSTM中进行训练。

将数据集拆分为训练集、验证集和测试集。由于这个数据集是时间序列,以2023年前的数据作为训练集,之后数据为验证集。

npreddata_X=dataX[-30:]
npreddata_Y=dataY[-30:]
ddf_X=dataX[:-30]
ddf_Y=dataY[:-30]
test_split=68 #这里是从2023-1-1开始计时
trainX=ddf_X[:-test_split]
trainY=ddf_Y[:-test_split]

testX=ddf_X[-test_split:]
testY=ddf_Y[-test_split:]

看一下数据结构

trainX.shape,trainY.shape,testX.shape,testY.shape

((942, 30, 6), (942,), (68, 30, 6), (68,))

看到这里大家有没有看明白了,如果还不明白,我再给大伙解释一下

如果查看 trainX[1] 值,会发现到它与 trainX[0] 中的数据相同(第一列除外),因为我们将看到前 30 个来预测第 31 列,在第一次预测之后它会自动移动 到第 2 列并取下一个 30 值来预测下一个目标值。

让我们用一种简单的格式来解释这一切——

trainX — — →trainY  
[0 : 30,0:6][30,3]  
[1:31, 0:6][31,3]  
[2:32,0:6][32,3]

这下应该看明白了。

建模

以一般的 LSTM 模式,用Adam优化器,用mse作为损失函数,采用二层结构进行建模。

grid_model = Sequential()
grid_model.add(LSTM(50,return_sequences=True,input_shape=(30,6)))
grid_model.add(LSTM(50))
grid_model.add(Dropout(0.2))
grid_model.add(Dense(1))
grid_model.compile(loss = 'mse',optimizer = 'adam')

grid_model.summary()
Model: "sequential_4"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 lstm_8 (LSTM)               (None, 30, 50)            11400     
                                                                 
 lstm_9 (LSTM)               (None, 50)                20200     
                                                                 
 dropout_4 (Dropout)         (None, 50)                0         
                                                                 
 dense_4 (Dense)             (None, 1)                 51        
                                                                 
=================================================================
Total params: 31,651
Trainable params: 31,651
Non-trainable params: 0
_________________________________________________________________

训练

这里用 batch_size 用16 ,epochs =40来进行训练,在实际情况一下,数据集的数据量大的话,机器内存在或采用GPU等,可以用更大的参数,epoch 也可以有更大的参数。

history=grid_model.fit(
   trainX, trainY,
   batch_size = 16,
   epochs =40,
   validation_data=(testX,testY)
)
_________________________________________________________________
Output exceeds the size limit. Open the full output data in a text editor
Epoch 1/40
59/59 [==============================] - 1s 21ms/step - loss: 0.0088 - val_loss: 0.0030
Epoch 2/40
59/59 [==============================] - 1s 22ms/step - loss: 0.0089 - val_loss: 0.0036
Epoch 3/40
59/59 [==============================] - 2s 26ms/step - loss: 0.0084 - val_loss: 0.0099
Epoch 4/40
59/59 [==============================] - 1s 19ms/step - loss: 0.0082 - val_loss: 0.0129
Epoch 5/40
59/59 [==============================] - 1s 18ms/step - loss: 0.0079 - val_loss: 0.0059
Epoch 6/40
59/59 [==============================] - 1s 19ms/step - loss: 0.0078 - val_loss: 0.0061
Epoch 7/40
59/59 [==============================] - 1s 20ms/step - loss: 0.0078 - val_loss: 0.0051
Epoch 8/40
59/59 [==============================] - 1s 19ms/step - loss: 0.0075 - val_loss: 0.0113
Epoch 9/40
59/59 [==============================] - 1s 19ms/step - loss: 0.0074 - val_loss: 0.0075
Epoch 10/40
59/59 [==============================] - 1s 22ms/step - loss: 0.0070 - val_loss: 0.0045
Epoch 11/40
59/59 [==============================] - 1s 20ms/step - loss: 0.0078 - val_loss: 0.0088
Epoch 12/40
59/59 [==============================] - 1s 20ms/step - loss: 0.0073 - val_loss: 0.0090
Epoch 13/40
...
Epoch 39/40
59/59 [==============================] - 1s 19ms/step - loss: 0.0041 - val_loss: 0.0058
Epoch 40/40
59/59 [==============================] - 1s 19ms/step - loss: 0.0038 - val_loss: 0.0056

由于训练数据和测试数据是经过归一化的,因此要查看结果,需要将数据逆缩放过程。
先看训练集数据。

tprediction=grid_model.predict(trainX)
tprediction_copies_array = np.repeat(tprediction,6, axis=-1)
tpred=scaler.inverse_transform(np.reshape(tprediction_copies_array,(len(tprediction),6)))[:,0]

toriginal_copies_array = np.repeat(trainY,6, axis=-1)
toriginal=scaler.inverse_transform(np.reshape(toriginal_copies_array,(len(trainY),6)))[:,0]
plt.figure(figsize=(10, 8))
plt.plot(toriginal,  label = '真实')
plt.plot(tpred,  label = '预测')
plt.title(' 股票价格预测')
plt.xlabel('Time')
plt.ylabel('Stock Price')
plt.legend()
plt.show()


采用相同的方法,看验证集数据

prediction=grid_model.predict(testX)
prediction_copies_array = np.repeat(prediction,6, axis=-1)
pred=scaler.inverse_transform(np.reshape(prediction_copies_array,(len(prediction),6)))[:,0]

original_copies_array = np.repeat(testY,6, axis=-1)
# original_copies_array.shape
original=scaler.inverse_transform(np.reshape(original_copies_array,(len(testY),6)))[:,0]
plt.figure(figsize=(10, 8))
plt.plot(original,  label = '真实')
plt.plot(pred,  label = '预测')
plt.title(' 股票价格预测')
plt.xlabel('Time')
plt.ylabel('Stock Price')
plt.legend()
plt.show()

评估

from sklearn.metrics import make_scorer,mean_squared_error,mean_absolute_error
print('MSE:',mean_squared_error(toriginal,tpred),mean_squared_error(original,pred))
print('MAE:',mean_absolute_error(toriginal,tpred),mean_absolute_error(original,pred))

MSE: 0.05473229063101591 0.12244576326985654
MAE: 0.17944593014201451 0.24734961573477243

从MSE和 MAE来看,值并不大。从数值上看并不大,可从图形上来看预测效果并不理想。

作图

见上图

总结

以上是深度学习中RNN中的LSTM来作股票价格预测,从结果来看效果并不理想,作为一种方法,需要我们掌握的。除了LSTM之外,还有GAN和ANN等方法,处理数据方面大同小异,GAN 是一种比较特殊的方法。
由于在实际应用中效果不理解,很少被采用,因此不作过多的介绍。
总之,我们学习其方法以及原理,决不能作为投资的依据。
以后可以通过机器学习来生成投资策略,那还是比较靠谱的。那是机器学习的另一个应用。

在此警告:文章中的所有内容,不能给你构成投资的理由。

  • 7
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值