在本文中,我将创建一个预测股票价格变动的完整流程。按照我们的思路走下去,我们将获得一些非常好的结果。为此,我们将使用生成对抗网络(GAN)与LSTM(一种递归神经网络)作为生成器,并使用卷积神经网络CNN作为裁决器。我们使用LSTM的原因很明显,我们正在尝试预测时间序列数据。为什么我们使用GAN,特别是CNN作为裁决器?这是一个很好的问题:稍后会有特别的部分来说明这个问题。
当然,我们将详细介绍每个步骤,但最困难的部分是GAN:成功训练GAN的非常困难的部分是获得正确的超参数集。出于这个原因,我们将使用贝叶斯优化(连同高斯过程)和深度强化学习(DRL)来决定何时以及如何改变GAN的超参数。在创建强化学习时,我将使用该领域的最新进展,例如Rainbow和PPO。
我们将使用许多不同类型的输入数据。除了股票的历史交易数据和技术指标,我们将使用NLP的最新进展(BERT迁移学习)来创建情绪分析(作为基本面分析的一部分),用于提取整体趋势方向的傅立叶变换,用于识别其他高级特征的栈式自编码器,用于查找相关资产的特征投资组合,用于股票函数近似的自回归积分移动平均值(ARIMA)等等,以便捕获尽可能多的关于股票的信息,模式,依赖关系等。众所周知,数据越多越好。预测股票价格变动是一项非常复杂的任务,因此我们对股票的了解越多(从不同的角度来看),我们的盈利就越高。
为了创建所有的神经网络,我们将使用MXNet及其高级API-Gluon,并在多个GPU上进行训练。
注意:虽然我试图详细了解了数学和几乎所有算法和技术背后的机制,但本文不会明确地解释机器/深度学习或股票市场如何运作。我们的目的是分享如何使用不同的技术和算法来准确预测股票价格变动,并且给出在每一步使用每种技术的原因和背后的理由。
目录
1、概述
2、数据
2.1、关联资产
2.2、技术指标
2.3、基本面分析
2.3.1、Transformer的双向嵌入表示-BERT
2.4、用于趋势分析的傅立叶变换
2.5、ARIMA作为特征
2.6、统计学检查
2.6.1、异方差性,多重共线性,序列相关性
2.7、特征工程
2.7.1、特征对于XGBoost的重要性
2.8、使用栈式自编码器提取高级特征
2.8.1、激活函数-GELU(高斯误差)
3、生成对抗网络(GAN)
3.1、为什么GAN用于股市预测
3.2、Metropolis-HastingsGAN和WassersteinGAN
3.3、生成器-单层RNN
3.3.1、LSTM还是GRU
3.3.2、LSTM的架构
3.3.3、学习率调度程序
3.3.4、如何防止过拟合和偏差-方差权衡
3.4、裁决器-一维CNN
3.4.1、为什么CNN可以做裁决器?
3.4.2、CNN的架构
3.5、超参数
4、超参数优化
4.1、针对超参数优化的强化学习
4.1.1、强化学习理论
4.1.1.1、Rainbow
4.1.1.2、PPO
4.1.2、进一步深入强化学习
4.2、贝叶斯优化
4.2.1、高斯过程
5、结果
6、接下来的研究内容?
7、免责声明
1、概述
准确预测股票市场是一项复杂的任务,因为特定股票在特定方向上有数百万个事件和前提条件。因此,我们需要能够捕获尽可能多的这些前提条件。我们还需要做出几个重要假设:1)市场不是%随机,2)历史会重演,3)市场遵循人们的理性行为,4)市场是“完美的”。不过,请阅读底部的免责声明。
我们将尝试预测高盛(纽约证券交易所代码:GS)的价格走势。为此,我们将使用年1月1日至年12月31日的每日收盘价(训练数据为7年,验证数据为2年)。
2、数据
我们需要了解影响GS的股价上涨或下跌的因素。这是人们所关心的问题。因此,我们需要尽可能多地合并信息(从不同方面和角度描绘股票)。(我们将使用天的日线数据来训练各种算法(我们拥有70%的训练数据)并预测接下来的天(测试数据)。然后我们将预测结果与测试数据分类进行比较(我们将其称为特征)在后面的章节中我们会详细介绍,我们将使用的特征包括:
关联资产-这些是其他资产(任何类型,不一定是股票,如商品,外汇,指数,甚至固定收益证券)。像高盛这样的大公司显然不会“生活”在一个孤立的世界中-它依赖于许多外部因素并与之互动,包括竞争对手,客户,全球经济,地缘*治形势,财*和货币*策,融资情况等。详情将在后面列出。
技术指标-很多投资者都遵循技术指标。我们将最受欢迎的指标作为独立特征。其中包括-7日和21日均线,指数均线,动量,布林通道,MACD。
基本面分析-一个非常重要的特征,表明股票是上涨还是下跌。基本面分析有两个方面可以为我们所用:1)使用10-K和10-Q报告分析公司业绩,分析ROE和市盈率等(我们不会使用此报告),2)新闻-可能新闻可以指示可能在特定方向上移动股票的即将发生的事件。我们将阅读高盛的所有每日新闻,并提取当天对高盛的总体情绪是正面的,中立的还是负面的(我们的打分会介于0-1之间)。由于许多投资者都会仔细阅读新闻并根据新闻做出投资决策(当然不是所有人),如果今天高盛的消息非常积极,那么股票将在明天激增。这里的重点在于,我们将以这些特征的权重作为我们以后判断股票趋势的依据。稍后会详细介绍。
为了创建准确的情绪预测,我们将使用神经语言处理(NLP)。我们将使用BERT-谷歌最近宣布的NLP方法用于情感分类股票新闻情绪提取的迁移学习。
傅立叶变换-除了每日收盘价,我们还将创建傅里叶变换,以概括多个长期和短期趋势。使用这些变换,我们将消除大量噪声(随机的)并创建真实股票移动的近似值。趋势近似可以帮助LSTM网络更准确地选择其预测趋势。
自回归整合移动平均线(ARIMA)-这是预测时间序列数据未来值的最流行技术之一(在神经网络流行之前)。我们把它也加上,看看它是否是一个重要的预测特征。
栈式自编码器-经过数十年的研究后,人们发现了大多数上述特征(基本面分析,技术分析等)。但也许我们错过了一些东西。也许由于大量的数据点,事件,资产,图表等,人们无法理解隐藏的相关性。使用栈式自编码器(神经网络),我们可以使用计算机的强大功能,可能找到新的影响股票走势的特征。即使我们无法用人类语言理解这些功能,我们也会在GAN中使用它们。
深度无监督学习用于期权定价中的异常检测。我们将再使用一项特征-每天我们都会为高盛股票增加90天看涨期权的价格。期权定价本身结合了大量数据。期权合约的价格取决于股票的未来价值(分析师也试图预测价格,以便为看涨期权提供最准确的价格)。使用深度无监督学习(自组织映射),我们将尝试发现每天定价中的异常情况。异常(例如定价的急剧变化)可能有利于LSTM来做股票价格的模式识别。
现在我们有了这么多的特征,接下来我们需要执行几个重要的步骤:
对数据的“质量”进行统计检查。如果我们创建的数据存在缺陷,那么无论我们的算法有多复杂,结果都不会很理想。检查包括确保数据不会受到异方差性,多重共线性或串行相关性的影响。
创建特征权重。如果某个特征(例如另一个股票或技术指标)对我们想要预测的股票没有权重,那么我们就不需要在神经网络的训练中使用它。我们将使用XGBoost(eXtremeGradientBoosting),一种增强树回归算法来创建权重。
作为我们数据准备的最后一步,我们还将使用主成分分析(PCA)创建Eigen投资组合,以减少自编码器创建的特征的维数。
2.1、关联资产
如前所述,我们将使用其他股票数据作为特征,而不仅仅是GS。
那么其他股票是否会影响GS的股票走势?良好地了解公司,其业务线,竞争格局,依赖关系,供应商和客户类型等对于选择正确的关联资产非常重要:
首先是与GS类似的公司。我们将把JPMorganChase和MorganStanley等添加到数据集中。
作为一家投资银行,高盛(GoldmanSachs)依赖于全球经济。经济不景气或波动意味着没有并购或首次公开募股,也可能是有限的自营交易收益。这就是为什么我们将包括全球经济指数。此外,我们将包括LIBOR(美元和英镑计价)利率,因为分析师可能会考虑经济的冲击来设定这些利率以及其他FI证券。
每日波动率指数(VIX)-理由同上。
综合指数-如纳斯达克和纽约证券交易所(来自美国),FTSE(英国),日经(日本),恒生和BSESensex(亚太指数)指数。
货币-全球贸易多次反映货币如何变动,因此我们将使用一揽子货币(如美元兑日元,英镑兑美元等)作为特征。
总的来说,我们在数据集中有72个其他资产-每个资产的日线数据。
2.2、技术指标
我们已经介绍了什么是技术指标以及我们使用它们的原因,让我们直接来看代码。我们将仅为GS创建技术指标。
Functiontocreatethetechnicalindicators
defget_technical_indicators(dataset):
#Create7and21daysMovingAverage
dataset[ma7]=dataset[price].rolling(window=7).mean()
dataset[ma21]=dataset[price].rolling(window=21).mean()
#CreateMACD
dataset[26ema]=pd.ewma(dataset[price],span=26)
dataset[12ema]=pd.ewma(dataset[price],span=12)
dataset[MACD]=(dataset[12ema]-dataset[26ema])
#CreateBollingerBands
dataset[20sd]=pd.stats.moments.rolling_std(dataset[price],20)
dataset[upper_band]=dataset[ma21]+(dataset[20sd]*2)
dataset[lower_band]=dataset[ma21]-(dataset[20sd]*2)
#CreateExponentialmovingaverage
dataset[ema]=dataset[price].ewm(