神经网络在算法交易上的应用系列——简单时序预测

我们想从零实现只基于深度学习模型的交易系统,对于在研究过程中我们遇到的任何问题(价格预测,交易策略,风险管理)我们都将采用不同类型的人工神经网络(ANNS)来解决,同时也会检验它们在处理这些问题的效果到底如何。

在第一部分,我们想演示MLPs(多层感知机),CNNs(卷积神经网络)和RNN(递归或循环神经网络)是如何应用到时间序列预测上的。这部分中,我们不准备使用任何特征工程。而只考虑S&P500指数价格变化的历史数据。我们有1950年到2016年每天的开、高、低、收和成交量数据。首先,我们尝试预测下一个交易日最后的收盘价,然后,尝试预测收益率(收到开)。从Yahoo Finance下载数据。

神经网络在算法交易上的应用系列——简单时序预测

链接:

https://finance.yahoo.com/quote/%5EGSPC/history?ltr=1

问题定义

我们把我们问题看作:

1、回归问题(预测具体的收盘价格或第二天的收益率)

2、二分类问题(价格上涨[1;0]或下跌[0;1])

我们将使用Keras框架对NNs进行训练。

首先让我们准备训练数据。我们想根据N天前的信息来预测t+1的值。例如,有过去30天的行情数据,我们想预测明天,即第31天的价格是多少。

我们使用了90%的时间序列作为训练集(把它当作历史数据),剩下的10%作为模型评估的测试集。

这里是导入数据,将数据分成训练集和原始数据的预处理例子:

def load_snp_close():
 f = open('table.csv', 'rb').readlines()[1:]
 raw_data = []
 raw_dates = []
 for line in f:
 try:
 close_price = float(line.split(',')[4])
 raw_data.append(close_price)
 raw_dates.append(line.split(',')[0])
 except:
 continue
 return raw_data, raw_dates
def split_into_chunks(data, train, predict, step, binary=True, scale=True):
 X, Y = [], []
 for i in range(0, len(data), step):
 try:
 x_i = data[i:i+train]
 y_i = data[i+train+predict]
 if binary:
 if y_i > 0.:
 y_i = [1., 0.]
 else:
 y_i = [0., 1.]
 if scale: x_i = preprocessing.scale(x_i)
 else:
 timeseries = np.array(data[i:i+train+predict])
 if scale: timeseries = preprocessing.scale(timeseries)
 x_i = timeseries[:-1]
 y_i = timeseries[-1]
 except:
 break
 X.append(x_i)
 Y.append(y_i)
 return X, Y

回归问题 MLP

它只是含2个隐藏层的感知器。隐藏神经元的数量是根据经验选择的,我们将在下一个部分进行超参数的最优化。在两个隐藏层之间,我们添加一个退出层来防止过拟合。

编译器中重要的是Dense(1),Activation(‘Linear’) 和 ‘mse’。我们想得到一个可以在任意范围内的输出结果(我们预测真实价格),损失函数定义成均方差。

model = Sequential()
model.add(Dense(500, input_shape = (TRAIN_SIZE, )))
model.add(Activation('relu'))
model.add(Dropout(0.25))
model.add(Dense(250))
model.add(Activation('relu'))
model.add(Dense(1))
model.add(Activation('linear'))
model.compile(optimizer='adam', loss='mse')

让我们看看如果我们仅输入20天的收盘价来预测第21天的价格结果会是什么样的。最终MSE= 46.3635263557,但它不是非常具有代表性的信息。下面是测试集前150个点的预测图,黑线是实际数据,蓝线是预测数据。我们可以清楚地看到,我们的算法甚至都不接近真实值,但可以学习到趋势。

predicted = model.predict(X_test)
try:
 fig = plt.figure(figsize=(width, height))
 plt.plot(Y_test[:150], color='black')
 plt.plot(predicted[:150], color='blue')
 plt.show()
except Exception as e:
 print str(e)

神经网络在算法交易上的应用系列——简单时序预测

让我们使用sklearn的方法 preprocessing.scale() 把时间序列数据标准化为均值为0,方差为1的序列。然后用同样的MLP来训练。现在我们有了MSE = 0.0040424330518(但是它是基于标准化的数据)。在下面的图中,你可以看到标准化的时间序列(黑色)和我们的预测值(蓝色):

神经网络在算法交易上的应用系列——简单时序预测

实际中我们使用这个模型时,我们需要对时间序列进行去标准化。我们可以通过乘上用来预测的时间序列的20天标准差,然后加上它的均值来实现:

params = []
for xt in X_testp: 
 xt = np.array(xt)
 mean_ = xt.mean()
 scale_ = xt.std()
 params.append([mean_, scale_])
predicted = model.predict(X_test)
new_predicted = []
for pred, par in zip(predicted, params):
 a = pred*par[1]
 a += par[0]
 new_predicted.append(a)

这个例子中MSE等于937.963649937. 下图是还原的预测值(红色)和真实数据(绿色):

神经网络在算法交易上的应用系列——简单时序预测

是不是还可以? 但是,让我们尝试更加复杂的算法来解决这个问题。

回归问题 CNN

我们不打算深入讲解卷积神经网络理论,但你可以查看下列非常棒的资源:

1、Stanford CNNs for Computer Vision course

神经网络在算法交易上的应用系列——简单时序预测

链接:http://cs231n.github.io

2、Denny Britz的博客,内容真的超级棒!

神经网络在算法交易上的应用系列——简单时序预测

链接:http://www.wildml.com

让我们定义一个带一个全连接层的两层卷积神经网络(卷积层和池化层组合),输出和前面的相同:

model = Sequential()
model.add(Convolution1D(input_shape = (TRAIN_SIZE, EMB_SIZE), 
 nb_filter=64,
 filter_length=2,
 border_mode='valid',
 activation='relu',
 subsample_length=1))
model.add(MaxPooling1D(pool_length=2))
model.add(Convolution1D(input_shape = (TRAIN_SIZE, EMB_SIZE), 
 nb_filter=64,
 filter_length=2,
 border_mode='valid',
 activation='relu',
 subsample_length=1))
model.add(MaxPooling1D(pool_length=2))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(250))
model.add(Dropout(0.25))
model.add(Activation('relu'))
model.add(Dense(1))
model.add(Activation('linear'))

检验我们的结果。标准化的和恢复的数据MSE分别是0.227074542433和935.520550172.如图所示:

神经网络在算法交易上的应用系列——简单时序预测

神经网络在算法交易上的应用系列——简单时序预测

即便是看标准化数据的MSE,这个神经网络学习效果更差。最有可能的是,更深层的架构需要更多的数据来训练,否则只是大量过滤或层数造成的过拟合。

回归问题 RNN

作为循环架构,我想去用两个堆叠的LSTM层。

更多关于LSTM信息读这里:

神经网络在算法交易上的应用系列——简单时序预测

链接:

http://colah.github.io/posts/2015-08-Understanding-LSTMs/

model = Sequential()
model.add(LSTM(input_shape = (EMB_SIZE,), input_dim=EMB_SIZE, output_dim=HIDDEN_RNN, return_sequences=True))
model.add(LSTM(input_shape = (EMB_SIZE,), input_dim=EMB_SIZE, output_dim=HIDDEN_RNN, return_sequences=False))
model.add(Dense(1))
model.add(Activation('linear'))

预测图如下:

MSEs=0.0246238639582,939.948636707

神经网络在算法交易上的应用系列——简单时序预测

RNN预测看起来更像移动平均模型,他不能学习和预测所有的波动。

所以,这是一个有点出乎意料的结果,但我们可以看到,对于这个时间序列的预测,MLPs工作得更好。让我们看看如果我们从回归转变到分类问题的结果。现在我们不用收盘价,而用每天收益(收盘到开盘),我们想基于过去20天的日收益率来预测收盘价比开盘价高还是低。

神经网络在算法交易上的应用系列——简单时序预测

分类问题 MLP

代码只做了微调,我们改变了最后的Dense 层,令结果为[0;1]或[1;0],并增加逻辑回归使输出结果为期望概率。

为了得到二元输出,下面代码做修改:

split_into_chunks(timeseries, TRAIN_SIZE, TARGET_TIME, LAG_SIZE, binary=False, scale=True)
split_into_chunks(timeseries, TRAIN_SIZE, TARGET_TIME, LAG_SIZE, binary=True, scale=True)

同样,我们修改损失函数为二元交叉熵,并增加准确率指标。

model = Sequential()
model.add(Dense(500, input_shape = (TRAIN_SIZE, )))
model.add(Activation('relu'))
model.add(Dropout(0.25))
model.add(Dense(250))
model.add(Activation('relu'))
model.add(Dense(2))
model.add(Activation('softmax'))
model.compile(optimizer='adam', 
 loss='binary_crossentropy', 
 metrics=['accuracy'])

神经网络在算法交易上的应用系列——简单时序预测

不比随机猜测好到哪去(50%准确率),我们尝试些更好的。看看下面的结果。

分类问题CNN

model = Sequential()
model.add(Convolution1D(input_shape = (TRAIN_SIZE, EMB_SIZE), 
 nb_filter=64,
 filter_length=2,
 border_mode='valid',
 activation='relu',
 subsample_length=1))
model.add(MaxPooling1D(pool_length=2))
model.add(Convolution1D(input_shape = (TRAIN_SIZE, EMB_SIZE), 
 nb_filter=64,
 filter_length=2,
 border_mode='valid',
 activation='relu',
 subsample_length=1))
model.add(MaxPooling1D(pool_length=2))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(250))
model.add(Dropout(0.25))
model.add(Activation('relu'))
model.add(Dense(2))
model.add(Activation('softmax'))
history = TrainingHistory()
model.compile(optimizer='adam', 
 loss='binary_crossentropy', 
 metrics=['accuracy'])

神经网络在算法交易上的应用系列——简单时序预测

分类问题CNN

model = Sequential()
model.add(LSTM(input_shape = (EMB_SIZE,), input_dim=EMB_SIZE, output_dim=HIDDEN_RNN, return_sequences=True))
model.add(LSTM(input_shape = (EMB_SIZE,), input_dim=EMB_SIZE, output_dim=HIDDEN_RNN, return_sequences=False))
model.add(Dense(2))
model.add(Activation('softmax'))
model.compile(optimizer='adam', 
 loss='binary_crossentropy', 
 metrics=['accuracy'])

神经网络在算法交易上的应用系列——简单时序预测

结论

我们可以看到,将时间序列预测作为回归问题对待的方法更好,它可以学习到序列的趋势并且预测价格和真实值接近。

令我们吃惊的是,MLPs处理序列数据的效果比被认为更擅长处理时间序列数据的CNNs和RNNs更好。我是用非常小的数据集(16K时间序列)和虚拟超参数选择来解释的。

你可以使用文中代码来重现结果和获得更好的结果。

我们认为可以在回归和分类上得到更好的结果,通过使用不同的特征(不仅仅是标准化的时间序列),像一些技术指标等。我们还可以尝试更高频率的数据,比如说分钟数据,可以获得更多的训练数据。

原文链接:

https://medium.com/@alexrachnog/neural-networks-for-algorithmic-trading-part-one-simple-time-series-forecasting-f992daa1045a

原文发布于微信公众号 - 量化投资与机器学习(Lhtz_Jqxx)

相关推荐