人工智能与量化投资--使用机器学习预测股价的一般方法
机器学习和深度学习已经在金融机构中占据了一席之地,因为它们能够非常准确的预测时间序列数据,并且仍在被不断改进中以获得更好的模型。
本文中的项目基于AIAlpha,这是一个栈式神经网络架构,可以预测各个公司的股票价格。该项目也是iNTUtion 2018的入围者之一,iNTUtion 2018是新加坡本科生的黑客马拉松。
工作流程
该项目的工作流程基本上遵循以下步骤:
获取股票价格数据
使用小波变换对数据进行去噪处理
使用栈式自编码器提取特征
使用LSTM训练
测试模型的预测准确率
在这篇文章中,我将详细介绍每个步骤的实现以及一些细节以及为什么这样做。
1.数据采集
借助Yahoo Finance的pandas_datareader API,很容易获得股票价格数据。因此,只需使用以下命令即可完成。
stock_data = pdr.get_data_yahoo(self.ticker, self.start, self.end)
2.数据去噪
由于股票市场动态的复杂性,股票价格数据通常充满了可能影响机器学习算法分析趋势和结构的噪音。因此,删除一些噪声既符合我们的利益,同时也能保留数据中的趋势和结构。最初,我想使用傅里叶变换,但我认为小波变换可能是保留数据时间因素的更好选择,而不是仅产生基于频率的输出。
小波变换
小波变换与傅立叶变换非常相近,仅仅变换的函数不同,并且变换过程略有不同。
其过程如下:
使用小波变换来变换数据。
消除超过标准差的系数。
逆变换新系数得到去噪后数据。
以下是小波变换对时间序列数据进行去噪的示例:
如您所见,在去噪版本中不存在初始信号中存在的随机噪声。这正是我们要查看的股票价格数据。
以下是对数据进行去噪的代码:
x = np.array(self.stock_data.iloc[i: i + 11, j])
(ca, cd) = pywt.dwt(x, "haar")
cat = pywt.threshold(ca, np.std(ca), mode="soft")
cdt = pywt.threshold(cd, np.std(cd), mode="soft")
tx = pywt.idwt(cat, cdt, "haar")
pywt包非常适合小波变换,你可以完全不用关注小波变换本身。
3.提取特征
在通常的机器学习领域,提取特征需要专业知识。你可以尝试使用某种技术指标,如移动平均线或异同移动平均线(MACD)或动量指标,但盲目地使用它们可能不是最优的。
但是,我们可以通过使用栈式自编码器或其他机器学习算法(如受限Boltzmann机)来实现自动特征提取。由于编码的可解释性与受限Boltzmann机器的概率相比,我选择使用栈式自编码器。
栈式自编码器
从本质上讲,栈式自编码器非常适合压缩数据并再次重现数据。我们感兴趣的是压缩部分,因为它意味着重现数据所需的信息以某种方式被压缩编码。这表明这些压缩数据在某种程度上可能是我们试图从中提取特征的数据的特征。以下是栈式自编码器的网络结构:
输入数据被压缩到所需的许多神经元,并且网络会强行使用自编码器重建初始数据。这会强制模型提取数据的关键元素,我们可以将其解释为要素。需要注意的一点是,由于没有输入输出对,这个模型实际上属于无监督学习,但输入和输出都是相同的。
我们可以使用keras来构建这样的模型,建议大家使用functional API而不是sequential API。
class AutoEncoder:
def __init__(self, encoding_dim):
self.encoding_dim = encoding_dim
def build_train_model(self, input_shape, encoded1_shape, encoded2_shape, decoded1_shape, decoded2_shape):
input_data = Input(shape=(1, input_shape))
encoded1 = Dense(encoded1_shape, activation="relu", activity_regularizer=regularizers.l2(0))(input_data)
encoded2 = Dense(encoded2_shape, activation="relu", activity_regularizer=regularizers.l2(0))(encoded1)
encoded3 = Dense(self.encoding_dim, activation="relu", activity_regularizer=regularizers.l2(0))(encoded2)
decoded1 = Dense(decoded1_shape, activation="relu", activity_regularizer=regularizers.l2(0))(encoded3)
decoded2 = Dense(decoded2_shape, activation="relu", activity_regularizer=regularizers.l2(0))(decoded1)
decoded = Dense(input_shape, activation="sigmoid", activity_regularizer=regularizers.l2(0))(decoded2)
autoencoder = Model(inputs=input_data, outputs=decoded)
encoder = Model(input_data, encoded3)
# Now train the model using data we already preprocessed
autoencoder.compile(loss="mean_squared_error", optimizer="adam")
train = pd.read_csv("preprocessing/rbm_train.csv", index_col=0)
ntrain = np.array(train)
train_data = np.reshape(ntrain, (len(ntrain), 1, input_shape))
# print(train_data)
# autoencoder.summary()
autoencoder.fit(train_data, train_data, epochs=1000)
我使用2000年至2008年的去噪股票价格数据训练了自编码器。经过1000个epoch的训练后,RMSE降至0.9左右。然后,我使用该模型将剩余的股票价格数据编码为特征值。
4. LSTM模型
LSTM模型不需要介绍,因为它在预测时间序列中变得非常普遍和流行。它通过cell状态机制获得了非常好的预测能力,并且能够理解和学习数据的长期趋势。这对我们的股票价格数据尤为重要。我将在下面讨论我认为重要的设计和选择的一些细节。
优化
所使用的优化器类型可以极大地影响算法收敛到最优的速度。此外,重要的是随机性概念,可以避免收敛于局部最小值但不会达到全局最小值。有一些很不错的算法,但我选择使用Adam优化器。 Adam优化器结合了另外两个优化器ADAgrad和RMSprop的优点。
ADAgrad优化器基本上对每个参数和每个时间步使用不同的学习率。 ADAgrad背后的逻辑是,不频繁的参数必须具有较大的学习率,而频繁的参数必须具有较小的学习率。换句话说,ADAgrad的随机梯度下降更新成为如下公式:
其中:
我们基于每组参数计算梯度,然后根据历史梯度来计算学习率。因此,
其中:
G是历史梯度的平方和矩阵。这种优化的问题是随着迭代次数的增加,学习率开始迅速消失。
RMSprop通过仅使用一定数量的历史梯度来解决学习率消失过快。这可以表示为:
现在我们已经了解了这两个优化器的工作原理,我们可以了解一下Adam的工作原理。
Adam是另一种使用历史平方梯度的指数衰减平均值和历史梯度的指数衰减平均值来计算每个参数的自适应学习率的方法。这可以表示为:
v和m可以分别被认为是梯度的第一和第二矩的估计,自适应矩估计也因此得名。当这是第一次使用时,研究人员观察到和0存在一个固有偏差值,他们通过使用以下公式来抵消这个偏差:
这样梯度更新公式就变为:
这是我使用的优化器,其优点总结如下:
每个参数和每次迭代的学习率都不同。
与ADAgrad一样,学习并没有减少。
梯度更新使用某刻的权重分布,更符合统计性声波衰减规律。
正则
训练模型的另一个重要方面是确保权重不会太大并集中在一个数据点,导致过度拟合。所以我们应该总是对大的权重进行惩罚。我选择使用Tikhonov正则化,可以将其视为如下最小化问题:
函数空间在RKHS空间中可以保证Norm的存在,这就使得我们能将Norm编码到我们的正则化器中。
Dropout
它是一种防止过度拟合的方法,它就像一些神经元突然不起作用。这会让模型不过度依赖任何神经元组,而是考虑所有的神经元。Dropout可以使神经元更加健壮,从而使它们能够预测趋势,而不过度依赖于任何一个神经元。以下是使用Dropout的结果:
图中可以看到,当我们使用Dropout时,错误率会持续下降!
5.模型实现
感谢keras及其Functional API,上述所有分析都可以相对轻松地实现。如下是模型的代码(完整代码代码,请查看我的GitHub:AlphaAI)
class NeuralNetwork:
def __init__(self, input_shape, stock_or_return):
self.input_shape = input_shape
self.stock_or_return = stock_or_return
def make_train_model(self):
input_data = kl.Input(shape=(1, self.input_shape))
lstm = kl.LSTM(5, input_shape=(1, self.input_shape), return_sequences=True, activity_regularizer=regularizers.l2(0.003),
recurrent_regularizer=regularizers.l2(0), dropout=0.2, recurrent_dropout=0.2)(input_data)
perc = kl.Dense(5, activation="sigmoid", activity_regularizer=regularizers.l2(0.005))(lstm)
lstm2 = kl.LSTM(2, activity_regularizer=regularizers.l2(0.01), recurrent_regularizer=regularizers.l2(0.001),
dropout=0.2, recurrent_dropout=0.2)(perc)
out = kl.Dense(1, activation="sigmoid", activity_regularizer=regularizers.l2(0.001))(lstm2)
model = Model(input_data, out)
model.compile(optimizer="adam", loss="mean_squared_error", metrics=["mse"])
# load data
train = np.reshape(np.array(pd.read_csv("features/autoencoded_train_data.csv", index_col=0)),
(len(np.array(pd.read_csv("features/autoencoded_train_data.csv"))), 1, self.input_shape))
train_y = np.array(pd.read_csv("features/autoencoded_train_y.csv", index_col=0))
# train_stock = np.array(pd.read_csv("train_stock.csv"))
# train model
model.fit(train, train_y, epochs=2000)
结果
如下是预测结果。
很明显,使用这种神经网络架构的结果还是是不错的,如果应用到策略中应该是有利可图的。
在线学习
除了从历史数据中学习之外,我还想让模型始终学习,甚至从预测中学习。因此,我已经将它修改为一个学习和预测的在线模型。换句话说,它学习历史数据,预测明天的价格,明天,当实际价格已知时,它也会学习使用它。这样模型就会一直在改进。
除了使用实际价格来改善之外,我还考虑制作一个二级模型,该模型使用关于上市公司的新闻和Twitter的情绪值。我将首先概述如何获取这些数据。
Twitter数据
除了股票价格数据,我还想尝试一些自然语言处理。因此,我尝试深入研究使用来自Twitter和新闻的情绪数据来改进股票预测。
第一个要解决的问题是免费获取推文,因为获取全部数据的Twitter API不是免费的。但是,我找到了一个可以获取过去10天推文的API,然后我可以实现某种形式的NLP来从推文中提取情绪数据。这不是最优的,但对我的在线学习模型是有帮助的。
我使用twitter API来获取过去10天数据,然后使用TextBlob计算情绪分数,并通过众多推文进行求平均。
新闻数据
与Twitter类似,获取新闻数据也绝非易事。我分析彭博文章的URL,但手动获取从2000年开始的所有新闻几乎是不可能的。因此,我选择了强大的新闻抓取工具的Aylien API。
这些新闻文章筛选的条件是他们只包括股票和财经新闻,并只保留前150名Alexa网站,并且使用指数加权移动平均线来平均情绪分数,并使用最近的新闻而不是旧的新闻。
在线模型
鉴于我的情绪分数,我使用额外的神经网络层来更正我的预测误差。但是,在本文发布时无法获得此结果,因为生成一个数据点需要一天的时间。
结论
神经网络非常善于预测时间序列数据,并且当与情绪数据结合时,可以真正建立一个实用的模型。虽然这里的结果令人印象深刻,但我仍然想方设法改进它,也许实际上可以从中制定一个完整的交易策略。目前,我正在研究使用强化学习来开发一个使用预测模型结果的交易代理。
本文翻译自Vivek Palaniappan的文章!
评论