博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用tensorflow:LSTM神经网络预测股票(一)
阅读量:4284 次
发布时间:2019-05-27

本文共 9331 字,大约阅读时间需要 31 分钟。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wlzzhcsdn/article/details/78203991

基础理论知识

关于深度学习和LSTM神经网络在网上有很多内容,这里不再赘述,只列举几个优质的资源:

1. 深度学习入门: 百度前首席科学家吴恩达创立的网站,旨在传播深度学习的基础知识。他的视频课程通俗易懂,有助于理解和学习到算法的本质。
2. 深度学习进阶: github上进行的对《Deep Learning》的中文翻译(提供PDF下载)。个人感觉阅读有一定难度,但内容完整且全面,适合当成工具书以进行更加细致地研究。
3. tensorflow入门: 这是偶然发现的一套讲tensorflow的优酷课程,播主以非常通俗的方式,并不怎么长的时间讲述了tensorflow的入门和不少代码构建过程,很适合入门。虽然有些细节讲的有点粗糙,需要费点心思去理解和查询,但也比官网强太多了。

股票预测相关代码

数据部分

喂给LSTM的数据初始为 60 * 7 = 420 的矩阵,其中 60 代表60个交易日,7 代表日线的数据:后复权开盘价、后复权最高价、后复权最低价、后复权收盘价、换手率、交易量、流通市值。对该矩阵按列标准化:(原始数据 - 平均值 )/ (标准差),再将标准化后的矩阵化成一列:[ 第一行的7个日线数据 , 第二行的7个日线数据 , … , 第60行的7个日线数据 ]。这样所得到的420个长度的一行数据,即为最终喂给LSTM的输入数据。

该输入数据对应了3个预测数据:收益率(通过第二个交易日开盘买入,第三个交易日开盘卖出求得)、日期(60个交易日当中最新的那天)、股票代码。在实际使用时,这三个数据只会使用收益率作为训练目标。

最终的数据,一行大概是这么个样子: [ -0.5933948819380339, …(省略418个数据)…, -0.6378356237378542]、[-1.27, ‘2009-01-12’, 10]

tensorflow 代码

数据部分

class get_stock_data():    """    获得股票分类数据,用以深度学习。格式为按照时间顺序,由小到大排序的:    [开盘价, 最高价, 最低价, 收盘价,换手率,成交量, 流通市值, 真实收益, 日期]    真实收益定义:下一个交易日开盘买入,再下一个交易日开盘卖出所得到的收益,算法为 100 * (open_next_next / open_next - 1)。    > 如果真实收益的回归预测效果一般,可以再试试分类预测:真实收益>= n 和 

tf代码

def stock_lstm(self,):    """    使用LSTM处理股票数据    直接预测收益    """    #获取当前python文件运行在哪个目录下并去掉最后的文件名,如:F:/deeplearning/main.py --> F:/deeplearning    #在linux下同样起作用    basic_path = os.path.dirname(os.path.abspath(__file__))    #定义存储模型的文件路径    #os.path.join(basic_path, "stock_rnn_save.ckpt")表示在运行的python文件路径下保存,文件名为stock_rnn.ckpt,在我环境下运行总是提示“另一个程序正在使用此文件,进程无法访问”,换到其他路径就OK    model_save_path = "F:\\123\\save\\stock_rnn_save.ckpt"#os.path.join(basic_path, "stock_rnn_save.ckpt")    #定义训练集的文件路径,当前为运行的python文件路径下,文件名为train_data.csv    train_csv_path = os.path.join(basic_path, "train_data.csv")    #定义测试集的文件路径,当前为运行的python文件路径下,文件名为test_data.csv    test_csv_path = os.path.join(basic_path, "test_data.csv")    #学习率    learning_rate = 0.001    #喂数据给LSTM的原始数据有几行,即:一次希望LSTM能“看到”多少个交易日的数据    origin_data_row = 60    #喂给LSTM的原始数据有几列,即:日线数据有几个元素    origin_data_col = 7    #LSTM网络有几层    layer_num = 2    #LSTM网络,每层有几个神经元    cell_num = 256    #最后输出的数据维度,即:要预测几个数据,该处只预测收益率,只有一个数据    output_num = 1    #每次给LSTM网络喂多少行经过处理的股票数据。该参数依据自己显卡和网络大小动态调整,越大 一次处理的就越多,越能占用更多的计算资源    batch_size = tf.placeholder(tf.int32, [])    #输入层、输出层权重、偏置。    #通过这两对参数,LSTM层能够匹配输入和输出的数据    W = {     'in':tf.Variable(tf.truncated_normal([origin_data_col, cell_num], stddev = 1), dtype = tf.float32),     'out':tf.Variable(tf.truncated_normal([cell_num, output_num], stddev = 1), dtype = tf.float32)     }    bias = {    'in':tf.Variable(tf.constant(0.1, shape=[cell_num,]), dtype = tf.float32),    'out':tf.Variable(tf.constant(0.1, shape=[output_num,]), dtype = tf.float32)    }    #告诉LSTM网络,即将要喂的数据是几行几列    #None的意思就是喂数据时,行数不确定交给tf自动匹配    #我们喂得数据行数其实就是batch_size,但是因为None这个位置tf只接受数字变量,而batch_size是placeholder定义的Tensor变量,表示我们在喂数据的时候才会告诉tf具体的值是多少    input_x = tf.placeholder(tf.float32, [None, origin_data_col * origin_data_row])    input_y = tf.placeholder(tf.float32, [None, output_num])    #处理过拟合问题。该值在其起作用的层上,给该层每一个神经元添加一个“开关”,“开关”打开的概率是keep_prob定义的值,一旦开关被关了,这个神经元的输出将被“阻断”。这样做可以平衡各个神经元起作用的重要性,杜绝某一个神经元“一家独大”,各种大佬都证明这种方法可以有效减弱过拟合的风险。    keep_prob = tf.placeholder(tf.float32, [])    #通过reshape将输入的input_x转化成2维,-1表示函数自己判断该是多少行,列必须是origin_data_col    #转化成2维 是因为即将要做矩阵乘法,矩阵一般都是2维的(反正我没见过3维的)    input_x_after_reshape_2 = tf.reshape(input_x, [-1, origin_data_col])    #当前计算的这一行,就是输入层。输入层的激活函数是relu,并且施加一个“开关”,其打开的概率为keep_prob    #input_rnn即是输入层的输出,也是下一层--LSTM层的输入    input_rnn = tf.nn.dropout(tf.nn.relu_layer(input_x_after_reshape_2, W['in'], bias['in']), keep_prob)    #通过reshape将输入的input_rnn转化成3维    #转化成3维,是因为即将要进入LSTM层,接收3个维度的数据。粗糙点说,即LSTM接受:batch_size个,origin_data_row行cell_num列的矩阵,这里写-1的原因与input_x写None一致    input_rnn = tf.reshape(input_rnn, [-1, origin_data_row, cell_num])    #定义一个带着“开关”的LSTM单层,一般管它叫细胞    def lstm_cell():        cell = rnn.LSTMCell(cell_num, reuse = tf.get_variable_scope().reuse)        return rnn.DropoutWrapper(cell, output_keep_prob = keep_prob)    #这一行就是tensorflow定义多层LSTM网络的代码    lstm_layers = tf.contrib.rnn.MultiRNNCell([lstm_cell() for _ in range(layer_num)], state_is_tuple = True)    #初始化LSTM网络    init_state = lstm_layers.zero_state(batch_size, dtype = tf.float32)    #使用dynamic_rnn函数,告知tf构建多层LSTM网络,并定义该层的输出    outputs, state = tf.nn.dynamic_rnn(lstm_layers, inputs = input_rnn, initial_state = init_state, time_major = False)    h_state = state[-1][1]    #该行代码表示了输出层    #将LSTM层的输出,输入到输出层,输出层最终得出的值即为预测的收益    y_pre = tf.matmul(h_state, W['out']) + bias['out']    #损失函数,用作指导tf    #loss的定义为:(使用预测的收益 - 喂给LSTM的这60个交易日对应的真实收益)的平方,如果有多个(即:batch_size个且batch_size大于1),那就求一下平均值(先挨个求平方,再整个求平均值)    loss = tf.reduce_mean(tf.square(tf.subtract(y_pre, input_y)))    #告诉tf,它需要做的事情就是就是尽可能将loss减小    #learning_rate是减小的这个过程中的参数。如果将我们的目标比喻为“从北向南走路走到菜市场”,我理解的是    #learning_rate越大,我们走的每一步就迈的越大。初看似乎步子越大越好,但是其实并不能保证每一步都是向南走    #的,有可能因为训练数据的原因,导致我们朝西走了一大步。或者我们马上就要到菜市场了,但是一大步走过去,给    #走过了。。。综上,这个learning_rate(学习率参数)的取值,无法给出一个比较普适的,还是需要根据实际情况去    #尝试和调整。0.001的取值是tf给的默认值    #上述例子是个人理解用尽可能通俗易懂地语言表达。如有错误,欢迎指正    train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss)    #这块定义了一个新的值,用作展示训练的效果    #它的定义为:选择预测值和实际值差别最大的情况并将差值返回    accuracy = tf.reduce_max(tf.abs(tf.subtract(y_pre, input_y)))    #tf要求必须如此定义一个init变量,用以在初始化运行(也就是没有保存模型)时加载各个变量    init = tf.global_variables_initializer()    #用以保存参数的函数(跑完下次再跑,就可以直接读取上次跑的结果而不必重头开始)    saver = tf.train.Saver()    #获取数据(这是我们自己定义的类)    data_get = get_stock_data()    #设置GPU按需增长,在多个GPU时,能更多地占用资源    config = tf.ConfigProto()    config.gpu_options.allow_growth = True    #使用with,保证执行完后正常关闭tf    with tf.Session(config = config) as sess:        try:            #定义了存储模型的文件路径,即:当前运行的python文件路径下,文件名为stock_rnn.ckpt            saver.restore(sess, model_save_path)            print ("成功加载模型参数")        except:            #如果是第一次运行,通过init告知tf加载并初始化变量            print ("未加载模型参数,文件被删除或者第一次运行")            sess.run(init)        #给batch_size赋值        _batch_size = 200        for i in range(20000):            try:                #读取训练集数据                train_x, train_y = data_get.get_train_test_data_new(batch_size = _batch_size, file_path = train_csv_path)            except StopIteration:                print ("训练集均已训练完毕")                train_accuracy = sess.run(accuracy, feed_dict={                    input_x:train_x, input_y: train_y, keep_prob: 1.0, batch_size: _batch_size})                print ("step: {0}, training_accuracy: {1}".format(i + 1, train_accuracy))                saver.save(sess, model_save_path)                print("保存模型\n")                break            if (i + 1) % 20 == 0:                train_accuracy = sess.run(accuracy, feed_dict={                    input_x:train_x, input_y: train_y, keep_prob: 1.0, batch_size: _batch_size})                #输出                print ("step: {0}, training_accuracy: {1}".format(i + 1, train_accuracy))                saver.save(sess, model_save_path)                print("保存模型\n")                ############################################                #这部分代码作用为:每次保存模型,顺便将预测收益和真实收益输出保存至show_y_pre.txt文件下。熟悉tf可视化,完全可以采用可视化替代                _y_pre_train = sess.run(y_pre, feed_dict={                    input_x: train_x, input_y: train_y, keep_prob: 1.0, batch_size:  _batch_size})                _loss = sess.run(loss, feed_dict={                    input_x:train_x, input_y: train_y, keep_prob: 1.0, batch_size: _batch_size})                a1 = np.array(train_y).reshape(1, _batch_size)                b1 = np.array(_y_pre_train).reshape(1, _batch_size)                with open (os.path.join(basic_path, "show_y_pre.txt"), "w") as f:                    f.write(str(a1.tolist()))                    f.write("\n")                    f.write(str(b1.tolist()))                    f.write("\n")                    f.write(str(_loss))                ############################################            #按照给定的参数训练一次LSTM神经网络            sess.run(train_op, feed_dict={input_x: train_x, input_y: train_y, keep_prob: 0.6, batch_size: _batch_size})        #计算测试数据的准确率        #读取测试集数据        test_size = 100        test_x, test_y = data_get.get_train_test_data_new(batch_size = test_size, file_path = test_csv_path)        print ("test accuracy {0}".format(sess.run(accuracy, feed_dict={            input_x: test_x, input_y: test_y, keep_prob: 1.0, batch_size:test_size}))) 
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159

借鉴资料

代码部分借鉴了 博主 和 的文章。在此表达谢意!

交流方式、完整数据和代码

欢迎加入qq群: 一起探索量化分析股票的方法。

示例数据(训练集10W,测试集1W)及完整的代码可在获得。

更加详尽的训练集数据(2006年至2017年10月,文件名:stock_data_for_dl_1.01.rar 解压缩后约42个G)可在qq群里下载获得(不方便直接上传至github)。

你可能感兴趣的文章
蓝牙 (七) 蓝牙数据
查看>>
蓝牙 (八) SDP
查看>>
蓝牙 (九)
查看>>
计算机组成
查看>>
MTD nor flash (一) 硬件
查看>>
MTD nor flash (二) linux mtd 架构
查看>>
内存 (一) linux 内存
查看>>
JTAG (一)杂谈
查看>>
I2S (一)杂谈
查看>>
技术教程网址
查看>>
使用GDB调试程序
查看>>
使用core dump查看程序运行异常
查看>>
Linux应用程序在内存地址布局
查看>>
Linux应用编程之静态库和动态库
查看>>
静态链接库设计
查看>>
动态链接库设计
查看>>
文件编程之库函数方式
查看>>
与时间相关的函数编程
查看>>
Linux进程控制相关概念
查看>>
c标准中的预定义宏
查看>>