基于LSTM的股票价格预测

前言 

本文通过LSTM来对股票未来价格进行预测,并介绍一下数据获取、处理,pytorch的模型搭建和训练等等。

数据获取

这里我使用tushare的接口来获取平安银行(000001.SZ)股票的历史10年的数据

import tushare as ts

pro = ts.pro_api('your token')
df = pro.daily(ts_code='000001.SZ', start_date='20130711', end_date='20220711')

由于本文只用到股票的开盘价、收盘价、最高价、最低价,所以只用到了一个接口,tushare除了这个接口以外还有许多数据接口,感兴趣的读者可以去Tushare大数据社区查询。

用mplfinance库绘制一下获取的数据

import pandas as pd
import mplfinance as mpf
df.index=pd.to_datetime(df.trade_date)#索引转为日期
df = df.iloc[::-1]#由于获取的数据是倒序的,需要将其调整为正序
mpf.plot(df[-50:],type='candle')#绘制最近50天的数据

绘制结果如下

 数据处理

我们需要使用历史200天的数据来预测未来7天的数据,所以接下来需要对获取到的数据进行处理

dataX=[]#属性
dataY=[]#标签
k=0
tempX=[]#储存某个历史200天数据
tempY=[]#储存某个未来7天数据
for index, rows in df.iterrows():
    if k<200:
        k+=1
        tempX.append([rows['open'],rows['close'],rows['high'],rows['low']])
        continue
    if k<207:
        k+=1
        tempY.append([rows['open'],rows['close'],rows['high'],rows['low']])
        continue
    dataX.append(tempX[:])
    dataY.append(tempY[:])

    tempX=tempX[1:]+tempY[:1]

    tempY=tempY[1:]
    tempY.append([rows['open'],rows['close'],rows['high'],rows['low']])
dataX.append(tempX[:])#加上最后一项
dataY.append(tempY[:])#加上最后一项

这样我们就得到两个一一对应的列表,dataX对应某个时间节点的历史200天数据,dataY则是该时间节点的未来7天数据,接下来将他们划分为训练集和测试集,并转化为DataLoader

import torch
import torch.utils.data as Data

dataX=torch.tensor(dataX)#列表转Tensor
dataY=torch.tensor(dataY)#列表转Tensor

dataset=Data.TensorDataset(dataX,dataY)
train_size=int(0.8*len(dataset))
test_size=len(dataset)-train_size
train_dataset, test_dataset = torch.utils.data.random_split(dataset, [train_size, test_size])#以8:2比例划分训练集和测试集

train_loader = Data.DataLoader(
            dataset=train_dataset,
            batch_size=64,
            shuffle=True
        )
test_loader = Data.DataLoader(
            dataset=test_dataset,
            batch_size=64,
            shuffle=True
        )

模型搭建

我们使用torch.nn中的LSTM来作为预测模型

LSTM参数介绍如下

  • input_size:输入x的特征数量
  • hidden_size:隐藏层h的特征数量
  • num_layers:隐藏层层数
  • bias:是否使用偏置,默认为:True
  • batch_first:若为True,则输入形状为(batch, seq, feature),否则为(seq, batch,feature),默认为False
  • dropout: 如果非零,则在除最后一层之外的每个LSTM层的输出上引入Dropout层,概率等于dropout
  • bidirectional:若为True,则表示该LSTM为双向的
  • proj_size:若大于0,将使用具有相应大小的投影的LSTM,默认为0

搭建的模型如下

from torch.nn import LSTM,Module,Linear
class MyModel(Module):
    def __init__(self):
        super(MyModel,self).__init__()
        self.lstm=LSTM(input_size=4,hidden_size=4,num_layers=2,batch_first=True)
        self.linear=Linear(800,28)#将结果映射到7天的数据
    def forward(self,x):
        return self.linear(self.lstm(x)[0].reshape(-1,800))

模型训练

使用均方误差作为损失函数,Adam为优化器训练200轮

import torch.nn.functional as F
model=MyModel()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
lossList=[]#记录训练loss
lossListTest=[]#记录测试loss
for epoch in range(200):
    loss_nowEpoch=[]
    model.train()
    for step, (batch_x, batch_y) in enumerate(train_loader):
        out=model(batch_x)#模型输入
        Loss = F.mse_loss(out,batch_y.view(-1,28))#loss计算,将batch_y从(64,7,4)变形为(64,28)
        optimizer.zero_grad()#当前batch的梯度不会再用到,所以清除梯度
        Loss.backward()#反向传播计算梯度
        optimizer.step()#更新参数
        loss_nowEpoch.append(Loss.item())
        break
    lossList.append(sum(loss_nowEpoch)/len(loss_nowEpoch))

    loss_nowEpochTest = []
    model.eval()
    for step, (batch_x, batch_y) in enumerate(test_loader):
        out = model(batch_x)
        Loss = F.mse_loss(out, batch_y.view(-1, 28))  # 将batch_y从(64,7,4)变形为(64,28)
        loss_nowEpochTest.append(Loss.item())
        break
    lossListTest.append(sum(loss_nowEpochTest)/len(loss_nowEpochTest))

    print(">>> EPOCH{} averTrainLoss:{:.3f} averTestLoss:{:.3f}".format(epoch+1, lossList[-1],lossListTest[-1]))

绘制loss的下降图


import matplotlib.pyplot as plt
plt.plot(list(range(200)),lossList,label='Train')
plt.plot(list(range(200)),lossListTest,label='Test')
plt.legend()
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

loss下降图如下

可以看到在50轮左右其实就收敛了

再根据最近200天来预测未来7天的数据

X=torch.tensor(df[['open','close','high','low']][-200:].to_numpy())
Y=model(X.view(1,200,4).float()).reshape(7,4)
result=pd.DataFrame(torch.vstack((X,Y)).detach().numpy())
result.index=list(df.index[-200:])+[pd.Timestamp('2022-07-12 00:00:00'),pd.Timestamp('2022-07-13 00:00:00'),
                              pd.Timestamp('2022-07-14 00:00:00'),pd.Timestamp('2022-07-15 00:00:00'),
                              pd.Timestamp('2022-07-18 00:00:00'),pd.Timestamp('2022-07-19 00:00:00'),
                              pd.Timestamp('2022-07-20 00:00:00')]
result.columns=['open','close','high','low']
mpf.plot(result[-21:],type='candle')

 

后七天即为未来七天的预测结果 

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2023年5月28日
下一篇 2023年5月28日

相关推荐