概述
LSTM(长短期记忆神经网络)是一种善于处理和预测时间序列相关数据的RNN。本文初步探究了LSTM在股票市场的应用,进而将LSTM对沪深300未来五日收益率的预测作为择时器。
说明
- 前端采用keras
- 数据采用tushare
- 后端采用TensorFlow中实现,改编自Google的PTB级别 RNN预测示例
- 收益使用标准偏差进行归一化(可配置回测)
- 训练/验证/测试集 按时间序列组织。
依赖
- TensorFlow
- Tushare
- numpy
- sklearn
- keras
LSTM Networks(长短期记忆神经网络)简介
LSTM Networks是递归神经网络(RNNs)的一种,该算法由Sepp Hochreiter和Jurgen Schmidhuber在Neural Computation上首次公布。后经过人们的不断改进,LSTM的内部结构逐渐变得完善起来(图1)。在处理和预测时间序列相关的数据时会比一般的RNNs表现的更好。目前,LSTM Networks已经被广泛应用在机器人控制、文本识别及预测、语音识别、蛋白质同源检测等领域。基于LSTM Networks在这些方面的优异表现,本文旨在探究LSTM是否可以应用于股票时间序列的预测。
image.pngLSTM Networks处理股票时间序列的流程
本文使用的LSTM处理股票序列的流程如图2。本文构建LSTM模型使用库主要为Keras。
数据获取与处理:对于时间序列,我们通常会以[X(t-n),X(t-n+1),…,X(t-1),X(t)]这n个时刻的数据作为输入来预测(t+1)时刻的输出。对于股票来说,在t时刻会有若干个features,因此,为了丰富features以使模型更加精确,本文将n(time series)×s(features per time series)的二维向量作为输入。LSTM对于数据标准化的要求很高,因此本文所有input数据均经过z-score标准化处理。
LSTM模型构建:作为循环层的一种神经网络结构,只使用LSTM并不能构建出一个完整的模型,LSTM还需要与其他神经网络层(如Dense层、卷积层等)配合使用。此外,还可以构建多层LSTM层来增加模型的复杂性。
LSTM应用股票市场初探
使用方法为利用沪深300前100天的收盘价预测下一天的收盘价。从结果来看,LSTM对未来20天的预测基本上是对过去100天收盘价变化的趋势的总括,因此最终的预测结果以及回测结果都不是很理想。 之后尝试增加了features(每日Open,High,Low,Close,Amount,Volume),效果依然不是很好。
通过对结果进行分析以及阅读研究一些研报,得到的初步结论为:一是input时间跨度太长(100天的价格走势对未来一天的价格变化影响很小),而待预测数据时间跨度太短;二是收盘价(Close)是非平稳数据,LSTM对于非平稳数据的预测效果没有平稳数据好。
LSTM对沪深300未来五日收益率预测
综合以上两点,本文所使用的输入和输出为利用过去30天的数据预测将来五天的收益。
-
测试对象:沪深300
-
数据选择和处理:
-
input的时间跨度为30天,每天的features为['close','open','high','low','amount','volume']共6个,因此每个input为30×6的二维向量。
-
output为未来5日收益future_return_5(future_return_5>0.2,取0.2;future_return_5<-0.2,取-0.2),为使训练效果更加明显,output=future_return_5×10; features均经过标准化处理(在每个样本内每个feature标准化处理一次)。
-
训练数据:沪深300 2005-01-01至2014-12-31时间段的数据;测试数据:沪深300 2015-01-01至2017-05-01时间段数据。
-
模型构建:鉴于数据较少(训练数据约2500个,预测数据约500个),因此模型构建的相对简单。模型共四层,为一层LSTM层+三层Dense层(图3)。
-
回测(待续):得到LSTM预测结果后,若LSTM预测值小于0,则记为-1,若大于0,记为1。
# 导入包
import matplotlib.pyplot as plt
from sklearn.preprocessing import scale
from keras.layers import Input, Dense, LSTM, merge
from keras.models import Model
import pandas as pd
import numpy as np
import talib as ta
import tushare as ts
import matplotlib.pyplot as plt
from matplotlib import rc
rc('mathtext', default='regular')
import seaborn as sns
sns.set_style('white')
from matplotlib import dates
import matplotlib as mpl
%matplotlib inline
#plt.rcParams["figure.figsize"] = (20,10)
# 基础参数配置
class conf:
instrument = '600600' #股票代码
#设置用于训练和回测的开始/结束日期
start_date = '2005-01-01'
split_date = '2015-01-01'
end_date = '2017-05-01'
fields = ['close', 'open', 'high', 'low','volume','amount'] # features
seq_len = 30 #每个input的长度
batch = 100 #整数,指定进行梯度下降时每个batch包含的样本数,训练时一个batch的样本会被计算一次梯度下降,使目标函数优化一步
# 数据导入以及初步处理
data = ts.get_k_data(conf.instrument, conf.start_date, conf.end_date)
del data["code"]
data["amount"] = data["close"]*data["volume"]
data['return'] = data['close'].shift(-5) / data['open'].shift(-1) - 1 #计算未来5日收益率(未来第五日的收盘价/明日的开盘价)
data.dropna(inplace=True)
datatime = data['date'][data.date>=conf.split_date] #记录predictions的时间,回测要用
data['return'] = data['return'].apply(lambda x:np.where(x>=0.2,0.2,np.where(x>-0.2,x,-0.2))) #去极值
data['return'] = data['return']*10 # 适当增大return范围,利于LSTM模型训练
data.reset_index(drop=True, inplace=True)
scaledata = data[conf.fields]
traindata = data[data.date<conf.split_date]
# 数据处理:设定每个input(30time series×6features)以及数据标准化
train_input = []
train_output = []
test_input = []
test_output = []
for i in range(conf.seq_len-1, len(traindata)):
a = scale(scaledata[i+1-conf.seq_len:i+1])
train_input.append(a)
c = data['return'][i]
train_output.append(c)
for j in range(len(traindata), len(data)):
b = scale(scaledata[j+1-conf.seq_len:j+1])
test_input.append(b)
c = data['return'][j]
test_output.append(c)
# LSTM接受数组类型的输入
train_x = np.array(train_input)
train_y = np.array(train_output)
test_x = np.array(test_input)
test_y = np.array(test_output)
# 自定义激活函数
import tensorflow as tf
def atan(x):
return tf.atan(x)
# 构建神经网络层 1层LSTM层+3层Dense层
# 用于1个输入情况
lstm_input = Input(shape=(30,6), name='lstm_input')
lstm_output = LSTM(128, activation=atan, dropout_W=0.2, dropout_U=0.1)(lstm_input)
Dense_output_1 = Dense(64, activation='linear')(lstm_output)
Dense_output_2 = Dense(16, activation='linear')(Dense_output_1)
predictions = Dense(1, activation=atan)(Dense_output_2)
model = Model(input=lstm_input, output=predictions)
model.compile(optimizer='adam', loss='mse', metrics=['mse'])
model.fit(train_x, train_y, batch_size=conf.batch, nb_epoch=10, verbose=2)
# 预测
predictions = model.predict(test_x)
# 预测值和真实值的关系
data1 = test_y
data2 = predictions
fig, ax = plt.subplots(figsize=(14, 8))
ax.plot(data2,data1, 'o', label="data")
ax.legend(loc='best')
image.png
# 如果预测值>0,取为1;如果预测值<=0,取为-1.为回测做准备
for i in range(len(predictions)):
if predictions[i]>0:
predictions[i]=1
elif predictions[i]<=0:
predictions[i]=-1
# 将预测值与时间整合作为回测数据
cc = np.reshape(predictions,len(predictions), 1)
databacktest = pd.DataFrame()
databacktest['date'] = datatime
databacktest['direction'] = np.round(cc)
原文地址更改了接口和部分参数
网友评论