前言
这学期选了一门网络信息体系结构课,本来以为是讲网络的,结果是讲如何炒股的,上课的内容,基本就是介绍github上的这个项目。这个项目是介绍如何写一个程序来预测股票价格的走势。下面来翻译一下这个项目的readme。
标题:使用AI中的最新成果来预测股票市场的变化
创建一个完整的程序来预测股票价格的变动。为此,我们将使用生成对抗性网络(GAN),其中LSTM是一种递归神经网络,它是生成器,而卷积神经网络CNN是鉴别器。我们使用LSTM的原因很明显,我们试图预测时间序列数据。为什么我们使用GAN,特别是CNN作为鉴别器?这是一个好问题,后面会有专门的部分介绍。
当然,我们将对每个步骤会进行详细的介绍,但最难的部分是GAN:成功训练GAN非常棘手的部分是获得正确的超参数集。因此,我们将使用贝叶斯优化(以及高斯过程)和深度强化学习(DRL)来决定何时以及如何改变GAN的超参数(探索与开发的两难境地)。在创建强化学习时,我们将使用该领域的最新进展,如Rainbow和PPO。
我们将使用许多不同类型的输入数据。随着股票的历史交易数据和技术指标,我们将使用NLP最新的进展(使用Bidirectional Embedding Representations from Transformers,BERT,一种传输学习NLP)创建情绪分析(作为基本分析的来源),傅里叶变换提取总体趋势方向,stacked autoencoders识别其他高级特征,寻找相关资产的特征组合,ARIMA用于股票函数的近似度等等,以便尽可能多地获取关于股票的信息、模式、相关性等。我们都知道,数据越多越好。预测股价走势是一项极其复杂的任务,所以我们对股票(从不同的角度)了解得越多,我们的变化就越大。
目录
- 介绍
- 数据
- Generative Adversarial Network - GAN
- Hyperparameters optimization
- The result
- What is next?
- Disclaimer
1. 介绍
准确预测股票市场是一项复杂的任务,因为有数百万的事件和特定股票在特定方向上移动的前提条件。 因此,我们需要能够尽可能多地捕获这些前置条件。 我们还需要做出几个重要的假设: 1) 市场不是100%随机 2) 历史可以重演 3) 市场遵循人们的理性行为 4) 市场是’完美的’
我们将尝试预测高盛的价格走势。 为此,我们将使用2010年1月1日至2018年12月31日的每日收盘价(训练集7年,测试集2年)。 我们将互换使用“Goldman Sachs”和“GS”这两个术语。后面可以换成A股的某个股票,大家可以尝试。
2. 数据
我们需要了解是什么影响了GS的股价是上涨还是下跌。这是人们的整体想法。因此,我们需要整合尽可能多的信息(从不同的方面和角度来描述股票)。我们将使用每天的数据—1585天来训练各种算法(70%的数据),并预测接下来的680天(测试数据)。然后我们将把预测结果与测试数据进行比较。每种类型的数据(我们将其称为特征)将在后面的章节中进行更详细的解释,但是,作为一个高层次的概述,我们将使用的特性是:
-
相关资产 - 这些是其他资产(任何类型,不一定是股票,如大宗商品、外汇、指数,甚至是固定收益证券)。高盛这样的大公司显然不是“生活”在一个孤立的世界里——它依赖并与许多外部因素相互作用,包括竞争对手、客户、全球经济、地缘政治形势、财政和货币政策、资本获取渠道等。
-
技术指标 - 很多投资者遵循技术指标。我们将包括最受欢迎的指标作为独立的功能。其中7和21天移动平均线,指数移动平均线,动量,波林格带,MACD。
- 基本面分析 - 一个非常重要的特征,表明股票是否可能上涨或下跌。基本面分析有两个特点: 1) 使用10-K和10-Q报告分析公司业绩,分析ROE和P/E,等等。 2) 我们将为高盛和阅读每日新闻提取总情绪是否对高盛在那一天是正的,中性的,还是消极的(如得分从0到1)。像许多投资者密切阅读新闻和做出投资决策基于新闻,如果机会高盛今天是非常积极的消息明天股票飙升。关键的一点是,我们将在以后对每个特性执行特性重要性(这意味着它对GS的移动有多么具有指示性),并决定是否使用它。稍后将对此进行详细介绍。
- 傅立叶变换 - 随着每日收盘价,我们将创建傅立叶变换,以概括几个长期和短期趋势。使用这些变换,我们将消除许多噪音(随机漫步),并创建真实股票运动的近似。采用趋势逼近可以帮助LSTM网络更准确地选取预测趋势
- Autoregressive Integrated Moving Average (ARIMA) - 这是(在前神经网络时代)预测时间序列数据未来值最流行的技术之一。让我们看看它是否是一个重要的预测方法。
- 栈式自动编码器 - 上面提到的大部分特性(基础分析、技术分析等)都是人们经过几十年的研究发现的。但也许我们错过了什么。也许有一些隐藏的相关性,人们无法理解,因为有大量的数据点、事件、资产、图表等。通过栈式自动编码器,我们可以利用计算机的力量,可能会发现影响股票走势的新类型的特征。即使我们无法理解人类语言中的这些特性,我们也将在GAN中使用它们。
- 深度无监督学习. 期权定价中异常检测的深度无监督学习。我们还将使用一个新功能——每增加一个高盛股票90天看涨期权的价格。期权定价本身结合了大量数据。期权合约的价格取决于股票的未来价值(分析师也试图预测价格,以便得出最准确的看涨期权价格)。利用深度无监督学习,我们将试图发现每天定价中的异常。异常(例如价格的剧烈变化)可能表明一个事件可能对LSTM了解整个股票模式有用。
有这么多特性,接下来,我们需要执行几个重要步骤:
- 对数据的“质量”进行统计检查。如果我们创建的数据有缺陷,那么无论我们的算法多么复杂,结果都不会是正面的。检查包括确保数据不受异方差、多重共线性或序列相关性的影响。
- 创建特征的重要性。如果一个特征(如另一只股票或一个技术指标)对我们想预测的股票没有解释力,那么我们就没有必要在神经网络的训练中使用它。我们将使用XGBoost(eXtreme Gradient boost),一种增强树回归算法。作为数据准备的最后一步,我们还将使用主成分分析(PCA)创建特征投资组合,以减少自编码器创建的特征的维数。
3.1. 相关资产
As explained earlier we will use other assets as features, not only GS.
如前所述,我们将使用其他资产作为特性,而不仅仅是GS。那么,还有哪些资产会影响高盛的股价走势呢?对公司、业务线、竞争环境、依赖关系、供应商和客户类型等的良好理解对于选择正确的相关资产集非常重要:
-
首先是类似于GS的公司。我们将把摩根大通和摩根士丹利等公司加入数据集。
- 作为一家投资银行,高盛依赖于全球经济。糟糕或不稳定的经济意味着没有并购或IPO,可能限制自营交易收入。这就是我们将纳入全球经济指数的原因。此外,我们还将包括LIBOR(以美元和英镑计价)利率,因为分析师设定这些利率可能会考虑到经济中的冲击。
- 每日波动率指数(VIX).
- 综合指数。例如纳斯达克和纽约证券交易所、FTSE100指数、Nikkei225指数、恒生指数和BSE Sensex指数。
- 货币。全球贸易经常反映在货币的走势上,因此我们将使用一篮子货币(如美元兑日元、英镑兑美元等)作为特征。
总结,我们在数据集中有其他72个资产,对每个资产,我们都有它的每日价格。
3.2. 技术指标
我们已经讨论了什么是技术指标以及为什么使用它们,现在让我们直接跳到代码。我们将只为GS创建技术指标。
def get_technical_indicators(dataset):
# Create 7 and 21 days Moving Average
dataset['ma7'] = dataset['price'].rolling(window=7).mean()
dataset['ma21'] = dataset['price'].rolling(window=21).mean()
# Create MACD
dataset['26ema'] = pd.ewma(dataset['price'], span=26)
dataset['12ema'] = pd.ewma(dataset['price'], span=12)
dataset['MACD'] = (dataset['12ema']-dataset['26ema'])
# Create Bollinger Bands
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)
# Create Exponential moving average
dataset['ema'] = dataset['price'].ewm(com=0.5).mean()
# Create Momentum
dataset['momentum'] = dataset['price']-1
return dataset
dataset_TI_df = get_technical_indicators(dataset_ex_df[['GS']])
dataset_TI_df.head()
所以我们有每个交易日的技术指标(包括MACD、布林带等)。我们总共有12个技术指标。
Date | price | ma7 | ma21 | 26ema | 12ema | MACD | 20sd | upper_band | lower_band | ema | momentum | log_momentum | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2010-02-01 | 153.130005 | 152.374285 | 164.220476 | 160.321839 | 156.655072 | -3.666767 | 9.607375 | 183.435226 | 145.005726 | 152.113609 | 152.130005 | 5.024735 |
1 | 2010-02-02 | 156.940002 | 152.777143 | 163.653809 | 160.014868 | 156.700048 | -3.314821 | 9.480630 | 182.615070 | 144.692549 | 155.331205 | 155.940002 | 5.049471 |
2 | 2010-02-03 | 157.229996 | 153.098572 | 162.899047 | 159.766235 | 156.783365 | -2.982871 | 9.053702 | 181.006450 | 144.791644 | 156.597065 | 156.229996 | 5.051329 |
3 | 2010-02-04 | 150.679993 | 153.069999 | 161.686666 | 158.967168 | 155.827031 | -3.140137 | 8.940246 | 179.567157 | 143.806174 | 152.652350 | 149.679993 | 5.008500 |
4 | 2010-02-05 | 154.160004 | 153.449999 | 160.729523 | 158.550196 | 155.566566 | -2.983631 | 8.151912 | 177.033348 | 144.425699 | 153.657453 | 153.160004 | 5.031483 |
让我们来看看这些指标的最后400天的走势:
def plot_technical_indicators(dataset, last_days):
plt.figure(figsize=(16, 10), dpi=100)
shape_0 = dataset.shape[0]
xmacd_ = shape_0-last_days
dataset = dataset.iloc[-last_days:, :]
x_ = range(3, dataset.shape[0])
x_ =list(dataset.index)
# Plot first subplot
plt.subplot(2, 1, 1)
plt.plot(dataset['ma7'],label='MA 7', color='g',linestyle='--')
plt.plot(dataset['price'],label='Closing Price', color='b')
plt.plot(dataset['ma21'],label='MA 21', color='r',linestyle='--')
plt.plot(dataset['upper_band'],label='Upper Band', color='c')
plt.plot(dataset['lower_band'],label='Lower Band', color='c')
plt.fill_between(x_, dataset['lower_band'], dataset['upper_band'], alpha=0.35)
plt.title('Technical indicators for Goldman Sachs - last {} days.'.format(last_days))
plt.ylabel('USD')
plt.legend()
# Plot second subplot
plt.subplot(2, 1, 2)
plt.title('MACD')
plt.plot(dataset['MACD'],label='MACD', linestyle='-.')
plt.hlines(15, xmacd_, shape_0, colors='g', linestyles='--')
plt.hlines(-15, xmacd_, shape_0, colors='g', linestyles='--')
plt.plot(dataset['log_momentum'],label='Momentum', color='b',linestyle='-')
plt.legend()
plt.show()
plot_technical_indicators(dataset_TI_df, 400)
3.3. 基本面分析
对于基本面分析,我们将对所有关于GS的每日新闻进行情绪分析。最后使用sigmoid,结果将在0到1之间。得分越接近0,负面消息就越多(接近1表示正面情绪)。对于每一天,我们将创建平均每日分数(作为0到1之间的数字),并将其添加为一个特征。
3.3.1. Bidirectional Embedding Representations from Transformers - BERT
为了将新闻分类为积极的或消极的(或中性的),我们将使用BERT,这是一种预先训练的语言表示。
已经在MXNet/Gluon中提供了训练有素的BERT模型。我们只需要实例化它们并添加两个(任意数字)Denselayers,到softmax—分数从0到1。
# just import bert
import bert
3.4. Fourier transforms for trend analysis
Fourier transforms 傅里叶变换取一个函数并创建一系列正弦波(具有不同的振幅和帧)。当这些正弦波合在一起时,就近似于原始函数。从数学上讲,变换是这样的:
我们将使用傅里叶变换来提取GS股票的整体和局部趋势,并对其进行降噪。我们来看看它是如何工作的。
data_FT = dataset_ex_df[['Date', 'GS']]
close_fft = np.fft.fft(np.asarray(data_FT['GS'].tolist()))
fft_df = pd.DataFrame({'fft':close_fft})
fft_df['absolute'] = fft_df['fft'].apply(lambda x: np.abs(x))
fft_df['angle'] = fft_df['fft'].apply(lambda x: np.angle(x))
plt.figure(figsize=(14, 7), dpi=100)
fft_list = np.asarray(fft_df['fft'].tolist())
for num_ in [3, 6, 9, 100]:
fft_list_m10= np.copy(fft_list); fft_list_m10[num_:-num_]=0
plt.plot(np.fft.ifft(fft_list_m10), label='Fourier transform with {} components'.format(num_))
plt.plot(data_FT['GS'], label='Real')
plt.xlabel('Days')
plt.ylabel('USD')
plt.title('Figure 3: Goldman Sachs (close) stock prices & Fourier transforms')
plt.legend()
plt.show()