<>一、需求

给定几个已知的股市因素(开盘、收盘、最高、最低、成交量、成交额)及各因素对应的大量数据,训练一个该股票的涨跌趋势的预测模型。并在给定的测试数据的条件下求出接下来的涨跌趋势。即得到下图中的label值。-1代表跌、1代表涨。

<>二、分析

<>1、LSTM简单介绍

LSTM这个算法是专门训练有时间序列信息的数据的,即这些数据不仅按照时间递增的顺序排布,并且前后的数据都有着很强的联系。个人认为与马尔可夫的思想差不多,即后面的值由前面的值来决定。本次需求是要根据已知的股市数据来分析某个时间段的涨跌趋势,并预测接下来该股票是涨还是跌,但是这里的股票预测存在一些问题:
(1)股票的涨跌不仅仅依赖上图中所给的几个因素,还有很多很多,所以预测的结果会有些偏差。
(2)LSTM算法本身就存在一个只考虑整体和前置信息的算法,没有考虑一些突发事件(比如马斯克宣布比特币不能购买特斯拉之后,比特币暴跌。。。)造成的偏差。

(3)LSTM算法默认所有的因素互相都是正相关的,比如A因素值在接下来一段时间内增加,B减少,如果将这两个因素结合起来训练的话得到的效果还不如只考虑一个A因素得到的效果好。(这里不是空说,我将每个因素都带入到网络中进行了训练和测试,得到的结果差异很大,就是说得到的模型预测趋势和测试数据完全不一样)

但是。。。这个算法还是更够以一个稍微大的概率预测股票趋势的。

<>2、代码

代码包分为几个部分:
1、run.py:主要运行代码
2、core.model.py:主要模型代码
3、core.dataprocessor.py:数据处理代码
4、config.json:配置文件

本代码需要的修改地方其实只是配置文件中的一些参数,参数的意思我在下面代码里作了标注。
{ "data": { "filename": "StockData.csv", //这是保存数据集地址 "columns": [ "close_1500"
//这里是数据集中决定股票涨跌的因素,可以写多个因素,因素之间用逗号相隔。 //这里改完之后要把下面的imput_dim改成因素的个数 ],
"sequence_length": 50, //步长,就是处理数据的时候按照步长50来取值,比如100条数据的话,就为成两个50条进行处理。
"train_test_split": 0.5,//将数据集按照0.5的比例分为训练集和测试集 "normalise": true //是否归一化 },
"training": { "epochs":1, "batch_size": 32 //训练的时候一次性加载的数据,可以大一点 }, "model": {
"loss": "mse", "optimizer": "adam", "save_dir": "saved_models", "layers": [ {
"type": "lstm", "neurons": 100, "input_timesteps": 49,//这里就是上面的步长-1,输入到lstm中
"input_dim": 1, "return_seq": true }, { "type": "dropout", "rate": 0.2 }, {
"type": "lstm", "neurons": 100, "return_seq": true }, { "type": "lstm",
"neurons": 100, "return_seq": false }, { "type": "dropout", "rate": 0.2 }, {
"type": "dense", "neurons": 1, "activation": "linear" } ] } }
配置好参数后,接下来就是运行run.py
这里面有三个函数需要着重解释一下:
predictions_multiseq = model.predict_sequences_multiple(x_test, configs['data']
['sequence_length'], configs['data']['sequence_length']) predictions_fullseq =
model.predict_sequence_full(x_test, configs['data']['sequence_length'])
predictions_pointbypoint= model.predict_point_by_point(x_test)
(1)model.predict_point_by_point:单点预测
效果如下:

这个函数代码如下:
def predict_point_by_point(self, data): #Predict each timestep given the last
sequence of true data, in effect only predicting 1 step ahead each time
#预测给定的最后一个真实数据序列的每个时间步,实际上每次只预测1步 print('[Model] Predicting Point-by-Point...')
predicted= self.model.predict(data) predicted = np.reshape(predicted, (predicted
.size,)) return predicted

data是测试数据,将测试数据直接代入模型中得到预测值,每次只预测一个值,也就是它只根据前一条数据来预测后一条数据,由于股票的数据本就是因为认为因素而瞬息万变的,所以这样的预测方式完全没有任何的参考价值。预测股票趋势的时候如果只按照一个值进行预测,得到的会是一个非常不确定的预测趋势。

(2)predictions_fullseq:全局预测
def predict_sequence_full(self, data, window_size): #Shift the window by 1 new
prediction each time, re-run predictions on new window #每次移动窗口1个新的预测,重新运行新窗口的预测
print('[Model] Predicting Sequences Full...') curr_frame = data[0] predicted = [
] for i in range(len(data)): predicted.append(self.model.predict(curr_frame[
newaxis,:,:])[0,0]) curr_frame = curr_frame[1:] curr_frame = np.insert(
curr_frame, [window_size-2], predicted[-1], axis=0) return predicted
这里的window_size就是步长,data是测试数据。
predicted.append(self.model.predict(curr_frame[newaxis,:,:])[0,0])
作用就是将测试整体数据都代入到模型中得到一个预测值,将这个预测值加到列表predicted中,然后下面这个函数
curr_frame = np.insert(curr_frame, [window_size-2], predicted[-1], axis=0)
作用就是把预测值列表中的最后一个值赋值给curr_frame的最后一条数据的所有维度(维度就是你一开在配置文件中设置的input_dim)。
例如:
predicted=[1,2,3,4]
curr_frame=[[5,6,7,8][9,10,11,12]]变成了[[9,10,11,12][4,4,4,4]]
这样的话原始的curr_frame就有了前面的预测信息4,依次类推
下一个predicted增加之后如下:
predicted=[1,2,3,4,5]
curr_frame=[[5,6,7,8][9,10,11,12]]变成了[[4,4,4,4][5,5,5,5]



这样进行下去之后,所有的curr_frame的各维度信息都一样了,预测曲线也就趋于平均值了。

综上

本函数的作用就是把所有的测试数据都丢到模型中预测出一个值,然后用这一个值来更新原来的测试数据,以此类推,循环进行len(data)次,即可得到全局的涨跌趋势,当然,结果表明,很差劲!!!

**(3)predict_sequences_multiple:**多序列预测
def predict_sequences_multiple(self, data, window_size, prediction_len):
#Predict sequence of 50 steps before shifting prediction run forward by 50 steps
#预测顺序50步之前,移动预测运行前50步 print('[Model] Predicting Sequences Multiple...')
prediction_seqs= [] for i in range(int(len(data)/prediction_len)): curr_frame =
data[i*prediction_len] predicted = [] for j in range(prediction_len): predicted.
append(self.model.predict(curr_frame[newaxis,:,:])[0,0]) curr_frame = curr_frame
[1:] curr_frame = np.insert(curr_frame, [window_size-2], predicted[-1], axis=0)
prediction_seqs.append(predicted) return prediction_seqs

这里相比较于(2)全局检测,多了一部分割,即先将所有的测试数据平均分成若干段,每一段的长度就是配置文件中设置的步长。每一段采用的方法与(2)中一样,最终这样的检测方式就可以捕获到局部和全局的趋势(单点检测只根据一条数据来预测,过于偏向局部;全局检测根据所有的数据来预测,过于偏向全局)

该方法效果如下:


上图中蓝色线是测试数据中第一个因素的数值图。彩色的每一段是预测的趋势,即当曲线向上表示这一段区间之后的股票可能会涨,曲线向下表示这一区间之后的股票可能会跌,当然,曲线的幅度也决定了涨跌的幅度。还有一个要强调的是,
这个模型的分段预测曲线只能预测接下来一小段时间内的涨跌情况,不能够预测的很长远,也不能预测某一个值

备注:
(1)如果我给定了一些数据,怎么预测涨跌?

首先模型训练前要确定好步长,步长决定了你需要输入的数据数。比如你模型的步长是50,那么你在测试的时候输入的数据数必须要大于50(否则无法代入到lstm模型中,因为这个模型对输入的数据有要求,可在配置文件的layers中进行查看)。这样才能在图中显示出涨跌曲线,这些涨跌曲线不是任何的因素值(不是钱也不是交易额),而是一个抽象的描述各股票决定因素之间关系的量。
(2)表述可能不太清楚,有疑问请在评论区说明,我会补充到备注里。

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信