当前位置:   article > 正文

基于LSTM算法的股票预测_基于lstm的股票预测

基于lstm的股票预测

一、LSTM基本原理

1.长短期记忆(LSTM)

LSTM是一种循环神经网络(RNN),可学习时间步长序列和数据之间的长期依赖关系,与CNN不同,LSTM可以记住预测之间的网络状态。
LSTM适用于序列和时序数据分类,此时必须基于记忆的数据点序列进行网络预测或输出。股票是随着时间变化的,恰好可以用LSTM。

二、LSTM预测股票走势

1.导入相关库文件

#导入相关库文件
import numpy as np
import pandas as pd
import math
import sklearn
import sklearn.preprocessing
import datetime
import os
import matplotlib.pyplot as plt
import tensorflow as tf
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

2.从oss2下载并解压数据集

(1)关于oss的学习

oss_getenv()用于获取环境变量的值(存在),否则返回默认值

环境变量获取,或者把诸如“<你的Access_Key_Id>”替换成真实的AccessKeyId等。
access_key_id = os.getenv(‘OSS_TEST_ACCESS_KEY_ID’, ‘你的ACCESS_KEY_ID’) access_key_secret = os.getenv(‘OSS_TEST_ACCESS_KEY_SECRET’, ‘你KEY_SECRET’) bucket_name = os.getenv(‘OSS_TEST_BUCKET’, ‘你的bucket name’)

(2)具体代码及注释
#准备数据,从oss2文件中下载并解压

import oss2
access_key_id = os.getenv('OSS_TEST_ACCESS_KEY_ID','LTAI4G1MuHTUeNrKdQEPnbph')
access_key_secret = os.getenv('OSS_TEST_ACCESS_KEY_SECRET','m1ILSoVqcPUxFFDqer4tKDxDkoP1ji')
bucket_name = os.getenv('OSS_TEST_BUCKET','mldemo')
endpoint = os.getenv('OSS_TEST_ENDPOINT','https://oss-cn-shanghai.aliyuncs.com')
#创建Bucket对象,所有Object相关接口都可以通过BUcket对象来进行
bucket = oss2.Bucket(oss2.Auth(access_key_id,access_key_secret),endpoint,bucket_name)
#下载到本地文件
#下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
#<yourLocalFile>由本地文件路径加文件名包括后缀组成,例如/users/local/myfile.txt。
#<yourObjectName>表示下载的OSS文件的完整名称,即包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
#bucket.get_object_to_file('<yourObjectName>', '<yourLocalFile>')
bucket.get_object_to_file('data/c12/stock_data.zip','stock_data.zip')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3.解压数据

(1)关于解压命令

unzip命令常用参数
-l:显示压缩文件内所包含的文件;
-t:检查压缩文件是否正确;
-o:不必先询问用户,unzip执行后覆盖原有的文件;
·-n:解压缩时不要覆盖原有的文件;
#-q:执行时不显示任何信息;
#-d<目录>:指定文件解压缩后所要存储的目录;

(2)关于!rm -rf __MACOSX
  • rm -rf * 删除当前目录下的所有文件

压缩文件夹里边的 __MACOSX是缓存文件,可以直接删除掉

  • __MACOSX的由来

Mac在压缩文件时会往里面写入MetaData,这样做的目的是为了方便其他的Mac用户使用,就想Windows会在图片目录中加入的Thumbs.db,以方便显示预览图一样
#这些MetaData产生的文件就是 __MACOSX,本身这些文件在Mac上是隐藏属性的,也确实方便了Mac用户
#但在Windows中 __MACOSX就成了“缓存文件”或垃圾文件,只有在Windows系统才能看到,Mac不可见
#所以,当我们打开压缩文件的时候,如果出现 __MACOSX,直接删除即可,不会对你的文件有任何影响

(3)具体代码及相关注释
#解压数据
#-o:不必先询问用户,unzip执行后覆盖原有的文件;
#-q:执行时不显示任何信息;
!unzip -o -q stock_data.zip
#rm -rf * 删除当前目录下的所有文件
!rm -rf __MACOSX
#ls 命令将每个由 Directory 参数指定的目录或者每个由 File 参数指定的名称写到标准输出,以及您所要求的和标志一起的其它信息。
#这里表示每个由 stock_data参数指定的名称写到标准输出
#-ilht主文件关联
!ls stock_data -ilht
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4.导入数据可视化

(1)df.info():

主要介绍数据集各列的数据类型,是否为空值,内存占用情况;

#pandas在读取csv文件时,不会去管原来的csv中是否存在index,而在于在读取的时候是否有设置index。
#如果读取的时候不设置index,那么系统会默认生成自然序列的index,
#如果读取时,给系统#####指定index,那么生成的dataframe的index就是是指定的,
#但是这里有个问题就是,这里指定的index只能是指定已经存在的列的序号或者列名,以读取test.csv这个文件所示:
df = pd.read_csv("./stock_data/sh300index.csv",index_col = 0)
#df.info():主要介绍数据集各列的数据类型,是否为空值,内存占用情况;
df.info()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

运行结果

(2)head()函数的观察读取的数据
#Pandas读取数据之后使用pandas的head()函数的时候,来观察一下读取的数据,head函数只读取前5行的数据
df.head()
  • 1
  • 2

运行结果:

(3)使用describe观察数据的分布情况
#数据的分布情况:df.describe(): 主要介绍数据集各列的数据统计情况(最大值、最小值、标准偏差、分位数等等)。
df.describe()
  • 1
  • 2

运行结果:

(4)可视化选取的相关指标
plt.figure(figsize=(15,5));#figsize=(15,5)表示figure 的大小为宽、长(单位为inch
plt.subplot(2,1,1);#subplot(2,1,1)指的是在一个2行1列共2个子图的图中,定位第1个图来进行操作。最后的数字就是表示第几个子图,此数字的变化来定位不同的子图。
plt.plot(df.open.values,color='red',label='open')#红色曲线绘制开盘价变化情况
plt.plot(df.close.values,color='green',label='close')#绿色曲线绘制收盘价变化情况
plt.plot(df.low.values,color='blue',label='low')#蓝色曲线表示最低价变化情况
plt.plot(df.high.values,color='black',label='high')#黑色曲线绘制最高价变化情况
plt.title('stock price')
plt.xlabel('time [days]')
plt.ylabel('price')
#上面参数loc表示location哦,代表标签所放置的位置哦,下面的loc=’best’的意思就是图形你自己看着办吧,放到合适的位置就行啦,
plt.legend(loc = 'best')

plt.subplot(2,1,2)#定位第2个子图
plt.plot(df.vol.values,color='black',label='volume')
plt.title('stock volume')
plt.xlabel('time [days]')
plt.ylabel('volume')
plt.legend(loc = 'best')
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行结果:
图中上面的图为股票的四个指标随时间变化的走势曲线图,下面的图为股票交易量随时间变化的走势图,可以看出,当股票价格下跌的时候,股票的交易量有所下降。

5.数据的预处理

(1)数据集划分比例

按照80%数据集,10%划分验证集,10%测试集对数据集进行划分。

#按照80%10%10%划分数据集。验证集,测试集
valid_set_size_percentage = 10#百分之十的验证集
test_set_size_percentage = 10#百分之十的次测试集
  • 1
  • 2
  • 3
(2)定义最小最大值归一化函数
#min-max归一化,将开盘价,收盘价,最高价,最低价归一化
def normalize_data(df):
    min_max_scaler = sklearn.preprocessing.MinMaxScaler()#调用sklearn的最小最大值归一化函数MinMaxScaler()
    df['open'] = min_max_scaler.fit_transform(df.open.values.reshape(-1,1))#reshape(-1,1)表示将数据转换成1列
    df['high'] = min_max_scaler.fit_transform(df.high.values.reshape(-1,1))#然后再进行归一化
    df['low'] = min_max_scaler.fit_transform(df.low.values.reshape(-1,1))
    df['high'] = min_max_scaler.fit_transform(df['close'].values.reshape(-1,1))
    return df#将归一化的结果返回给df
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
(3)划分数据集
#划分数据集
def load_data(stock,seq_len):
    data_raw = stock.to_numpy()#将stock的数据转换成numpy的array的数据,然后依次做数据切切分与读取
    data = []
    
    #create all possible sequences of Length seq_len
    for index in range(len(data_raw)-seq_len):
        data.append(data_raw[index: index+seq_len])
        
    data = np.array(data);
    valid_set_size = int(np.round(valid_set_size_percentage/100*data.shape[0]));#验证集的数据大小=数据集的行数*10%
    test_set_size = int(np.round(test_set_size_percentage/100*data.shape[0]));
    train_set_size = data.shape[0] - (valid_set_size + test_set_size);
    
    #将三部分数据按照x和y依次切分
    x_train = data[:train_set_size,:-1,:]
    y_train = data[:train_set_size,-1,:]
    
    x_valid = data[train_set_size:train_set_size+valid_set_size,:-1,:]
    y_valid = data[train_set_size:train_set_size+valid_set_size,-1,:]
    
    x_test = data[train_set_size+valid_set_size:,:-1,:]
    y_test = data[train_set_size+valid_set_size:,-1,:]
    
    return [x_train,y_train,x_valid,y_valid,x_test,y_test]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
(4)去除冗余指标并显示训练集的有效指标
#去除冗余,即将原始数据列表中不需要的指标删除
df_stock = df.copy()
df_stock.drop(['vol'],1,inplace=True)
df_stock.drop(['lastclose'],1,inplace=True)
df_stock.drop(['label'],1,inplace=True)
df_stock.drop(['ZTM:ma5'],1,inplace=True)
df_stock.drop(['ZTM:ma7'],1,inplace=True)
df_stock.drop(['ZTM:ma10'],1,inplace=True)
df_stock.drop(['ZTM:ma21'],1,inplace=True)
df_stock.drop(['holdingvol'],1,inplace=True)
df_stock.drop(['ZTM:MACD'],1,inplace=True)
df_stock.drop(['ZTM:RSI'],1,inplace=True)

#使用pandas的head函数查看输入数据(前5行)
#将训练集的四个指标作为训练数据
df_stock.head()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

运行结果:

(5)归一化并查看训练集,验证集,测试集的大小
df_stock_norm = normalize_data(df_stock)#调用normalize_data对df_stock归一化

#查看训练集,验证集和测试集情况
seq_len = 20 #设置最长序列长度
x_train, y_train, x_valid,y_valid,x_test,y_test = load_data(df_stock_norm,seq_len)#seq_len是我们加窗一次去的数据
print('x_train.shape =',x_train.shape)#经过处理,训练数据集是5207条,所以它的数据就是0~19,维度是4(因为有四个数据,开盘价,收盘价,最高价和最低价)
print('y_train.shape =',y_train.shape)
print('x_valid.shape =',x_valid.shape)#验证数据是651条,
print('y_valid.shape =',y_valid.shape)
print('x_test.shape =',x_test.shape)#测试数据是651条
print('y_test.shape =',y_test.shape)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

运行结果:

(6)对指标数据可视化
#对指标数据可视化
plt.figure(figsize=(15, 6));
plt.plot(df_stock_norm.open.values,color='red',label='open')
plt.plot(df_stock_norm.close.values,color='green',label='close')
plt.plot(df_stock_norm.low.values,color='blue',label='low')
plt.plot(df_stock_norm.high.values,color='black',label='high')
plt.title('stock')
plt.xlabel('time [days]')
plt.ylabel('normalized price/volume')
plt.legend(loc='best')
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

运行结果:

6.RNN建模-LSTM/GRU

(1)对训练数据随机化处理
#对训练数据随机化处理
index_in_epoch = 0;
perm_array = np.arange(x_train.shape[0])
np.random.shuffle(perm_array)#shuffle将数据打乱

#数据读取方法
def get_next_batch(batch_size):#从数据里边随机抽取batch_size的数量
    global index_in_epoch,x_train,perm_array
    start = index_in_epoch
    index_in_epoch += batch_size
    
    if index_in_epoch > x_train.shape[0]:
        np.random.shuffle(perm_array)
        start = 0
        index_in_epoch = batch_size
        
    end = index_in_epoch
    return x_train[perm_array[start:end]],y_train[perm_array[start:end]]#从x_train,y_train分别读取训练数据和标签
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
(2)定义超参
#定义超参
n_steps = seq_len-1#
#输入大小(与指标数量对应)
n_inputs = 4   #输入指标的数量
n_neurons =200 #循环神经网络有多少个神经元
#输出大小(与指标数量对应)
n_outputs = 4#输出指标的数量
#层数
n_layers = 2
#学习率
learning_rate =0.001
#批大小
batch_size = 50
#迭代训练次数
n_epochs = 20
#训练集大小
train_set_size = x_train.shape[0]#获取训练集的大小即训练数据的行数
#测试集大小
test_set_size = x_test.shape[0]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
(3)定义网络结构
#用的tensorflow定义网络的结构
tf.reset_default_graph()

X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])#用tf.placeholder定义了输入x和输出y
y = tf.placeholder(tf.float32, [None, n_outputs])

# 使用GRU单元结构
layers = [tf.contrib.rnn.GRUCell(num_units=n_neurons, activation=tf.nn.leaky_relu)#使用GRUCell定义了两层的神经网络
         for layer in range(n_layers)]
                                                                     
multi_layer_cell = tf.contrib.rnn.MultiRNNCell(layers)#将定义好的神经网络放在MultiRNNCell,构造一个多层的cell
rnn_outputs, states = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32)#将multi_layer_cell放到dynamic_rnn里面构成一个循环神经网络

stacked_rnn_outputs = tf.reshape(rnn_outputs, [-1, n_neurons]) 
stacked_outputs = tf.layers.dense(stacked_rnn_outputs, n_outputs)
outputs = tf.reshape(stacked_outputs, [-1, n_steps, n_outputs])#将循环神经网络的输出reshape成我们需要的大小
outputs = outputs[:,n_steps-1,:] # 定义输出

#将预测与实际结果求均方误差损失
loss = tf.reduce_mean(tf.square(outputs - y)) # 使用MSE作为损失
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate) #采用Adam优化方法
training_op = optimizer.minimize(loss)#最小化loss值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
(4)开始训练
# 执行训练
with tf.Session() as sess: 
    sess.run(tf.global_variables_initializer())
    for iteration in range(int(n_epochs*train_set_size/batch_size)):
        x_batch, y_batch = get_next_batch(batch_size) # fetch the next training batch 
        sess.run(training_op, feed_dict={X: x_batch, y: y_batch}) #依次运行training_op
        if iteration % int(5*train_set_size/batch_size) == 0:#获取最小化的损失,每隔(5*train_set_size/batch_size)步就print一次MSE的值
            mse_train = loss.eval(feed_dict={X: x_train, y: y_train}) 
            mse_valid = loss.eval(feed_dict={X: x_valid, y: y_valid}) 
            print('%.2f epochs: MSE train/valid = %.6f/%.6f'%(
                iteration*batch_size/train_set_size, mse_train, mse_valid))

    y_train_pred = sess.run(outputs, feed_dict={X: x_train})#将训练集进行预测
    y_valid_pred = sess.run(outputs, feed_dict={X: x_valid})#将验证集进行预测
    y_test_pred = sess.run(outputs, feed_dict={X: x_test})#将测试集进行预测
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

运行结果:
可以看出训练集的均方误差损失已经减少到了0.000032,验证集的均方误差已经减少到了0.000022.

7.模型预测

(1)模型的预测
ft = 0 # 0 = open, 1 = close, 2 = highest, 3 = lowest

#结果可视化
plt.figure(figsize=(15, 5));
plt.subplot(1,2,1);
#测试数据可视化
plt.plot(np.arange(y_train.shape[0]), y_train[:,ft], color='blue', label='train target')

plt.plot(np.arange(y_train.shape[0], y_train.shape[0]+y_valid.shape[0]), y_valid[:,ft],
         color='gray', label='valid target')

plt.plot(np.arange(y_train.shape[0]+y_valid.shape[0],
                   y_train.shape[0]+y_test.shape[0]+y_test.shape[0]),
         y_test[:,ft], color='black', label='test target')

plt.plot(np.arange(y_train_pred.shape[0]),y_train_pred[:,ft], color='red',
         label='train prediction')
#验证集数据可视化
plt.plot(np.arange(y_train_pred.shape[0], y_train_pred.shape[0]+y_valid_pred.shape[0]),
         y_valid_pred[:,ft], color='orange', label='valid prediction')
#将测试集的预测结果可视化,看测试结果与我们实际结果存在多大的误差
plt.plot(np.arange(y_train_pred.shape[0]+y_valid_pred.shape[0],
                   y_train_pred.shape[0]+y_valid_pred.shape[0]+y_test_pred.shape[0]),
         y_test_pred[:,ft], color='green', label='test prediction')

plt.title('past and future stock prices')
plt.xlabel('time [days]')
plt.ylabel('normalized price')
plt.legend(loc='best');

plt.subplot(1,2,2);

plt.plot(np.arange(y_train.shape[0], y_train.shape[0]+y_test.shape[0]),
         y_test[:,ft], color='black', label='test target')

plt.plot(np.arange(y_train_pred.shape[0], y_train_pred.shape[0]+y_test_pred.shape[0]),
         y_test_pred[:,ft], color='green', label='test prediction')

plt.title('future stock prices')
plt.xlabel('time [days]')
plt.ylabel('normalized price')
plt.legend(loc='best');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
(2)预测结果可视化

左图:红色曲线是训练集的预测结果,橙色是验证集的预测结果,绿色是测试集的预测结果,右图显示的是测试集的预测结果与真实值之间的拟合关系,我们可以看到拟合效果是非常好的。

三、数据集与实验环境

(1)数据集下载链接

https://download.csdn.net/download/fencecat/85104287

(2)环境配置

本实验使用tensorflow环境为1.14,如果安装的是tensorflow2.0版本会报错。

四、总结

1.混淆矩阵

  • 实际上,我们可以通过模型的训练精度使用混淆矩阵可视化出来,基本上,混淆矩阵显示了有多少数据点实际上属于一个类,并且预测属于一个类。
  • 此外,还可以通过ROC曲线来判断模型是否有效。
  • 通过混淆矩阵的可视化结果,我们可以比较基于深度学习算法LeNet5结构的股票预测与基于LSTM的股票预测的准确度,有兴趣的可以实现一下,这也是我下一步的任务。

2.续前文LeNet5股票预测

原文链接:https://blog.csdn.net/fencecat/article/details/124072324?spm=1001.2014.3001.5501
LeNet5股票预测文末的混淆矩阵实现模型精度可视化:

#混淆矩阵绘制
def plot_confusion_matrix(cm, labels_name, title):
    cm = cm.astype(np.float64)
    if(cm.sum(axis=0)[0]!=0):
        cm[:,0] = cm[:,0] / cm.sum(axis=0)[0]   # 归一化
    if(cm.sum(axis=0)[1]!=0):
        cm[:,1] = cm[:,1] / cm.sum(axis=0)[1]   # 归一化
    plt.imshow(cm, interpolation='nearest')    # 在特定的窗口上显示图像
    plt.title(title)    # 图像标题
    plt.colorbar()
    num_local = np.array(range(len(labels_name)))
    plt.xticks(num_local, labels_name)    # 将标签印在x轴坐标上
    plt.yticks(num_local, labels_name)    # 将标签印在y轴坐标上
    plt.ylabel('True label')
    plt.xlabel('Predicted label')
cm=confusion_matrix(t,pre)
y_true = np.array(list(map(int,t)))
y_scores = np.array(list(map(int,pre)))

roc=str(roc_auc_score(y_true, y_scores))
precision, recall, _thresholds = precision_recall_curve(y_true, y_scores)
pr =str(auc(recall, precision))
title="ROC AUC:"+roc+"\n"+"PR AUC:"+pr
labels_name=["0.0","1.0"]
plot_confusion_matrix(cm, labels_name, title)
for x in range(len(cm)):
    for y in range(len(cm[0])):
        plt.text(y,x,cm[x][y],color='white',fontsize=10, va='center')
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

可视化结果:

可以看到实验准确率为68.9%,并不是很好,可以通过调整网络结构优化模型来提高准确度。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/465574
推荐阅读
相关标签
  

闽ICP备14008679号