基于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')

     

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

    来源:_MaHao

    物联沃分享整理
    物联沃-IOTWORD物联网 » 基于LSTM的股票价格预测

    发表评论