深度学习量化交易---0.2.基于长短时记忆网络预测股票价格2

27 篇文章 1 订阅
22 篇文章 19 订阅

在上一篇博文中,我们介绍了长短时记忆网络的基本概念,在这一节中,我们将以长短时记忆网络(LSTM)为例,讲解深度学习算法在股票价预测中的应用。
我们要分析的数据如下所示:
在这里插入图片描述
各列依次为:股票代码、日期、开盘价、收盘价、最低、最高、交易量、金额、涨跌幅、第二天的最高价。
我们首先读入训练样本集,代码如下所示:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter, WeekdayLocator, DayLocator, MONDAY, date2num
from mpl_finance import candlestick_ohlc
from pylab import mpl
from datetime import datetime

class SdpsDs(object):
    ds_file = 'dataset_2.csv'
    
    def __init__(self):
        self.cls_name = 'SdpsDs'
           
    @staticmethod
    def initialize_data():
        '''
        从原始数据文件中读出股票数据
        '''
        with open(SdpsDs.ds_file) as fd:
            df = pd.read_csv(fd)     #读入股票数据
            data = df.iloc[:,2:10].values  #取第3-10列
        return data
           
    @staticmethod
    def get_train_ds(batch_size=60,time_step=20,train_begin=0,train_end=5800):
        '''
        获取训练样本集
        '''
        data = SdpsDs.initialize_data()
        batch_index = []
        data_train = data[train_begin:train_end]
        normalized_train_data=(data_train-np.mean(data_train,axis=0))/np.std(data_train,axis=0)  #标准化
        train_x,train_y=[],[]   #训练集
        for i in range(len(normalized_train_data)-time_step):
           if i % batch_size==0:
               batch_index.append(i)
           x=normalized_train_data[i:i+time_step,:7]
           y=normalized_train_data[i:i+time_step,7,np.newaxis]
           train_x.append(x.tolist())
           train_y.append(y.tolist())
        batch_index.append((len(normalized_train_data)-time_step))
        return batch_index,train_x,train_y

第30行:从CSV文件中读出第3至11列
第31行:定义迷你批次索引号数组,batch_index[2]=1008表示第3个迷你批次由第1008条记录开始;
第32行:定义0~5800条为训练样本集数据;
第33行:对数据进行标准化,公式为:
x ˉ = x − μ σ \bar{x}=\frac{x-\mu}{\sigma} xˉ=σxμ
即标准化后的值为原始值减去均值,再除以标准差;
第34行:用train_x保存训练数据集训练样本,用train_y保存训练数据集标签,即正确结果;
第35行:将训练样本集的记录,每一行(代表一天的数据),time_step条记录为一个迷你批次;
第36、37行:当读入time_step行数据形成一个迷你批次后,迷你批次序号加1,并将当前记录号记录到batch_index数组中;
第38行:第1~7列为训练样本;
第39行:第8列为第二天的最高价,也是我们要预测的正确结果;
第40行:形成训练数据集样本集;
第41行:形成训练数据集标签集(正确结果集);
第42行:在迷你批次索引号数组中添加最后一个迷你批次起始索引号。
测试样本集的处理与训练样本集的方法类似,如下所示:

    @staticmethod
    def get_test_ds(time_step=20,test_begin=5800):
        '''
        获取训练样本集
        '''
        data = SdpsDs.initialize_data()
        data_test=data[test_begin:]
        mean=np.mean(data_test,axis=0)
        std=np.std(data_test,axis=0)
        normalized_test_data=(data_test-mean)/std  #标准化
        size=(len(normalized_test_data)+time_step-1)//time_step  #有size个sample
        test_x,test_y=[],[]
        for i in range(size-1):
           x=normalized_test_data[i*time_step:(i+1)*time_step,:7]
           y=normalized_test_data[i*time_step:(i+1)*time_step,7]
           test_x.append(x.tolist())
           test_y.extend(y)
        test_x.append((normalized_test_data[(i+1)*time_step:,:7]).tolist())
        test_y.extend((normalized_test_data[(i+1)*time_step:,7]).tolist())
        return mean,std,test_x,test_y

接下来我们需要设计长短时记忆网络(LSTM),我们首先定义一些需要用到的变量,如下所示:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter, WeekdayLocator, DayLocator, MONDAY, date2num
from mpl_finance import candlestick_ohlc
from pylab import mpl
from datetime import datetime
import tensorflow as tf
from sdps_ds import SdpsDs

class Lstm(object):
    rnn_unit = 10         # 隐层神经元的个数
    lstm_layers = 2       # 隐层层数
    input_size = 7        # 输入层神经元个数
    output_size = 1       # 输出层神经元个数
    lr = 0.0006         #学习率
    weights={
         'in':tf.Variable(tf.random_normal([input_size,rnn_unit])),
         'out':tf.Variable(tf.random_normal([rnn_unit,1]))
        }
    biases={
            'in':tf.Variable(tf.constant(0.1,shape=[rnn_unit,])),
            'out':tf.Variable(tf.constant(0.1,shape=[1,]))
           }
    keep_prob = tf.placeholder(tf.float32, name='keep_prob')    

接下来我们看怎样定义在长短时记忆网络(LSTM)中使用的基本组件Cell,如下所示:

    @staticmethod
    def create_lstm(X):
        print('初始化LSTM网络')
        batch_size = tf.shape(X)[0]
        time_step = tf.shape(X)[1]
        w_in = Lstm.weights['in']
        b_in = Lstm.biases['in']
        input = tf.reshape(X, [-1, Lstm.input_size])  #需要将tensor转成2维进行计算,计算后的结果作为隐藏层的输入
        input_rnn = tf.matmul(input, w_in) + b_in
        input_rnn = tf.reshape(input_rnn, [-1, time_step, Lstm.rnn_unit])  #将tensor转成3维,作为lstm cell的输入
        cell = tf.nn.rnn_cell.MultiRNNCell([Lstm.create_lstm_cell() for i in range(Lstm.lstm_layers)])
        init_state = cell.zero_state(batch_size, dtype=tf.float32)
        output_rnn,final_states = tf.nn.dynamic_rnn(cell, input_rnn, initial_state=init_state, dtype=tf.float32)
        output = tf.reshape(output_rnn, [-1, Lstm.rnn_unit]) 
        w_out = Lstm.weights['out']
        b_out = Lstm.biases['out']
        pred = tf.matmul(output, w_out) + b_out
        return pred, final_states
        
    @staticmethod
    def create_lstm_cell():
        #basicLstm单元
        basicLstm = tf.nn.rnn_cell.BasicLSTMCell(Lstm.rnn_unit)
        # dropout
        drop = tf.nn.rnn_cell.DropoutWrapper(basicLstm, output_keep_prob=Lstm.keep_prob)
        return basicLstm

第2行:create_lstm函数中的参数X为Design Matrix,其每一行为一个样本,列代表样本的特征;
第4行:在这里一次性读入整个训练样本集,第0维代表迷你批次数量;
第5行:在每个迷你批次中,有time_step条记录,每一条记录代表长短时记忆网络(LSTM)中的一个时刻;
第6行:初始化输入层到隐藏层的连接权值矩阵w_in;
第7行:初始化隐藏层神经元偏置值b_in
第8行:将原始输入变为最后一维为7(输入变量特征数)的二维数组,例如我们假设迷你大小缺省为60,每个训练样本包括20行记录,则原始输入信号为 R 60 × 20 × 7 R^{60 \times 20 \times 7} R60×20×7,经过本步之后,input为 R 1200 × 7 R^{1200 \times 7} R1200×7
第9行:求出隐藏层的输出input_rnn,input为 R 1200 × 7 R^{1200 \times 7} R1200×7,w_in为 R 7 × 10 R^{7 \times 10} R7×10,b_in为 R 10 R^{10} R10,最后input_rnn的维度为 R 1200 × 10 R^{1200 \times 10} R1200×10
第10行:将input_rnn变为 R 60 × 20 × 10 R^{60 \times 20 \times 10} R60×20×10,其中60为缺省的迷你批次大小,20为一个训练样本中时刻数,10为隐藏层神经元个数;
第11行:生成两层由LSTM Cell组成的隐藏层,输入信号维度为10;
第12行:生成在 t = 0 t=0 t=0时刻隐藏层的初始状态,init_state为一个元组,由两个子元组构成,分别对应第11行生成的LSTM Cell,每个LSTM Cell的状态为: c 0 ∈ R 60 × 10 \boldsymbol{c}_0 \in R^{60 \times 10} c0R60×10 h 0 ∈ R 60 × 10 \boldsymbol{h}_0 \in R^{60 \times 10} h0R60×10
第13行:定义隐藏层的输出为网络输出 o u p u t r n n ∈ R 60 × 20 × 10 ouput_rnn \in R^{60 \times 20 \times 10} ouputrnnR60×20×10
第14行:将输出改为 o u t p u t ∈ R 1200 × 10 output \in R^{1200 \times 10} outputR1200×10
第15行:定义隐藏层到输出层的连接权值矩阵w_out;
第16行:定义输出层偏置值b_out;
第17行:求出输出层的输出;
下面我们来看长短时网络(LSTM)训练代码,如下所示:

    @staticmethod
    def train(batch_size=60, time_step=20, train_begin=2000, train_end=5800):
        X = tf.placeholder(tf.float32, shape=[None, time_step, Lstm.input_size])
        Y = tf.placeholder(tf.float32, shape=[None, time_step, Lstm.output_size])
        batch_index,train_x,train_y = SdpsDs.get_train_ds(batch_size, time_step, train_begin, train_end)
        with tf.variable_scope("sec_lstm"):
            pred,_=Lstm.create_lstm(X)
        loss = tf.reduce_mean(tf.square(tf.reshape(pred, [-1])-tf.reshape(Y, [-1])))
        train_op = tf.train.AdamOptimizer(Lstm.lr).minimize(loss)
        saver = tf.train.Saver(tf.global_variables(), max_to_keep=15)

        with tf.Session() as sess:
            sess.run(tf.global_variables_initializer())
            for i in range(10):     
                for step in range(len(batch_index)-1):
                    _,loss_= sess.run([train_op, loss],feed_dict={X:train_x[batch_index[step]:batch_index[step+1]],Y:train_y[batch_index[step]:batch_index[step+1]], Lstm.keep_prob:0.5})
                print("Number of iterations:",i," loss:",loss_)
            print("保存模型参数: ",saver.save(sess,'./model_save2/modle.ckpt'))
            print("模型训练结束")

第3行:定义训练样本集输入信号的设计矩阵 X ∈ R 60 × 20 × 7 X \in R^{60 \times 20 \times 7} XR60×20×7
第4行:定义训练样本集输出正确结果 Y ∈ R 60 × 20 × 1 Y \in R^{60 \times 20 \times 1} YR60×20×1
第5行:求出批次开始位置的索引号数组,训练样本集输入信号和训练样本集输出信号;
第6、7行:定义长短时记忆网络(LSTM);
第8行:设置代价函数为最小平方误差函数;
第9行:采用Adam优化算法;
第10行:为保存模型参数进行设置;
第12行:启动Tensorflow会话;
第13行:初始化变量;
第14~17行:对每个迷你批次进行训练,一共训练10次,通常情况下,训练遍数越多效果越好;
第18行:保存模型参数;
当模型训练好之后,我们需要在测试样本集上进行测试,看看我们的模型性能如何,代码如下所示:

    def predict(time_step=20):
        X = tf.placeholder(tf.float32, shape=[None, time_step, Lstm.input_size])
        mean,std,test_x,test_y = SdpsDs.get_test_ds(time_step)
        with tf.variable_scope("sec_lstm", reuse=tf.AUTO_REUSE):
            pred, _ = Lstm.create_lstm(X)
        saver = tf.train.Saver(tf.global_variables())
        with tf.Session() as sess:
            #参数恢复
            module_file = tf.train.latest_checkpoint('model_save2')
            saver.restore(sess, module_file)
            test_predict=[]
            for step in range(len(test_x)-1):
              prob = sess.run(pred, feed_dict={X:[test_x[step]], Lstm.keep_prob:1})
              predict = prob.reshape((-1))
              test_predict.extend(predict)
            test_y = np.array(test_y)*std[7]+mean[7]
            test_predict = np.array(test_predict)*std[7]+mean[7]
            acc = np.average(np.abs(test_predict-test_y[:len(test_predict)])/test_y[:len(test_predict)])  #偏差程度
            print("测试样本集精度:",acc)
            #以折线图表示结果
            plt.figure()
            plt.plot(list(range(len(test_predict))), test_predict, color='b',)
            plt.plot(list(range(len(test_y))), test_y,  color='r')
            plt.show()

第2行:生成测试样本集输入信号 X ∈ R 个 数 × 20 × 7 X \in R^{个数 \times 20 \times 7} XR×20×7,因为我们将所有测试样本作为一个迷你批次,我们针对每个时间点预测下一个时间点的最高价;
第3行:获取测试样本集均值、方差、测试样本集输入信号和测试样本集正确结果;
第4、5行:创建长短时记忆网络(LSTM)模型;
第6行:为恢复模型参数做准备;
第7行:启动TensorFlow会话;
第9行:找到最新的模型参数文件;
第10行:从最新模型文件中恢复网络参数;
第11行:定义存储模型预测结果的列表变量;
第12~15行:第测试样本集上每条记录进行循环,求出网络输出值,并将其添加到测试样本集预测结果列表中;
第16行:恢复测试样本集正确结果的真实值,因为我们在准备数据时做过预处理: x ~ = x − μ σ \tilde{x}=\frac{x - \mu}{\sigma} x~=σxμ
第17行:恢复测试本样集预测值的真实值,因为我们在准备数据时做过预处理: x ~ = x − μ σ \tilde{x}=\frac{x - \mu}{\sigma} x~=σxμ
第18、19行:计算并打印在测试样本集上的参数;
第20~24行:计算预测值和真实值曲线,预测值用蓝色,真实值用红色。
运行上面的程序,并产生如下所示的结果:
在这里插入图片描述
如图所示,我们所训练的模型,除了在开始位置有问题之外,大部分时间与正确结果(红色曲线)相关较小,而我们这个模型只训练了几分钟而已,如果加大训练时间,可以取得更好的结果。
截止目前为止,我们已经有了一个基本可用的模型,可以用于实际应用了。由于股市对一般人来讲,没有自动交易接口,只能用历史数据,比较枯燥乏味,不容易引起兴趣,我们将从下一节开始,以火币网比特币交易为例,向大家详细讲解类似长短时记忆网络(LSTM)怎样应用到实际金融业务中去。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值