查看原文
其他

比特币突破8000美元,我们找到了用DL预测虚拟货币价格的方法

2017-11-22 机器之心

选自GitHub

作者:David Sheehan

机器之心编译


截至 11 月 22 日,比特币的价格再创历史新高(约 1 比特币兑 8120 美元),在惊讶于虚拟货币「不可战胜」的同时,我们或许能可以从这一波热潮中学到些什么。本文中,博士毕业于伦敦大学学院(UCL)的 David Sheehan 为我们介绍了使用 Keras 基于 LSTM 预测比特币价格走势的详细方法。在测试中,这个机器学习预测法似乎有着不错的准确度。


如果要列出 2017 年最为荒谬的三样事物,则一定是指尖陀螺、人工智能,当然,还有加密虚拟货币(cryptocurrency)。以上是玩笑话,实际上我对虚拟货币的原理印象深刻,而且非常看好这种颠覆性技术的长期前景。我试图通过深度学习、机器学习或者说人工智能(是的,所有这三个!)成功预测虚拟货币的价格。


我认为把深度学习和虚拟货币结合起来是非常独特的想法,但是在写本文时,我发现了一些类似的内容(http://www.jakob-aungiers.com/articles/a/Multidimensional-LSTM-Networks-to-Predict-Bitcoin-Price)。这篇文章只关注比特币(最有名的虚拟货币),但是我还想讨论一下以太币。


我们打算使用 LSTM 模型,一种非常适合时序数据的深度学习模型。如果你希望真正了解理论或概念,那么推荐阅读:



  • 完整代码地址:https://github.com/dashee87/blogScripts/blob/master/Jupyter/2017-11-20-predicting-cryptocurrency-prices-with-deep-learning.ipynb


数据


在构建模型之前,我们需要先获取一些数据。Kaggle 上的数据集(https://www.kaggle.com/mczielinski/bitcoin-historical-data)非常详细地记录了近几年的比特币价格。在这个时间长度(数年)中,噪声可能盖住了信号,因此我们需要选择单日价格数据。问题在于我们可能没有充足的数据(我们需要数百行而不是数千行、数百万行)。在深度学习中,没有模型可以克服数据严重缺乏的问题。我同样不想使用静态文件,因为未来使用新数据更新模型时,这种做法会复杂化更新流程。于是,我们计划从网站和 API 中抓取数据。


我们将在一个模型中使用多种虚拟货币,因此从同一个数据源抓取数据或许是一个不错的主意。我们将使用 coinmarketcap.com。现在,我们只需要考虑比特币和以太币,但是使用这种方法添加最新火起来的山寨币(altcoin)就很难了。在输入数据之前,我们必须加载一些 Python 包,这样会容易一些。


  1. import pandas as pd

  2. import time

  3. import seaborn as sns

  4. import matplotlib.pyplot as plt

  5. import datetime

  6. import numpy as np


  7. # get market info for bitcoin from the start of 2016 to the current day

  8. bitcoin_market_info = pd.read_html("https://coinmarketcap.com/currencies/bitcoin/historical-data/?start=20130428&end="+time.strftime("%Y%m%d"))[0]

  9. # convert the date string to the correct date format

  10. bitcoin_market_info = bitcoin_market_info.assign(Date=pd.to_datetime(bitcoin_market_info['Date']))

  11. # when Volume is equal to '-' convert it to 0

  12. bitcoin_market_info.loc[bitcoin_market_info['Volume']=="-",'Volume']=0

  13. # convert to int

  14. bitcoin_market_info['Volume'] = bitcoin_market_info['Volume'].astype('int64')

  15. # look at the first few rows

  16. bitcoin_market_info.head()




以上代码的解释是,我们加载了一些 Python 包,然后导入这个网站(https://coinmarketcap.com/currencies/bitcoin/historical-data/)中的表格。经过少量的数据清理操作,我们获得了上面的表格。我用同样的操作为以太币也制作了一个表格,只需要把 url 中的『bitcoin』替换为『ethereum』就可以了(代码省略)。


为了证明数据是准确的,我们将两种虚拟币的价格和成交量按时间作图:



训练、测试和随机游走


有了数据,接下来就该建立模型了。深度学习中,通常把数据分为训练集和测试集。模型建立在训练集上,随后用未见过的测试集评估。在时间序列模型中,我们通常使用一段时期的数据训练,然后用另一段时期的数据进行测试。我把时间界限定为 2017 年 6 月 1 日(即模型将使用该日期之前的数据进行训练,用该日期之后的数据进行测试)。



从上图可知,大部分的训练时期内虚拟货币都是相对更低价的。因此,训练数据可能对于测试数据来说没有代表性,这会削弱模型泛化到未知数据上的能力。不过请先保持乐观,在实际应用我们的深度模型之前,讨论一下更简单的模型也是有意义的。最基础的模型是设定明天的价格等于今天的价格(可以简单粗暴地称之为滞后模型,lag model),数学公式:


通过扩展滞后模型,我们一般会使用随机游走(random walk)算法拟合股票价格,用数学公式定义即:



我们将从训练集中确定 μ 和 σ,然后将随机游走模型应用到比特币和以太币测试集上。



结果很不错!除了一些缺陷,该模型基本上追踪到了两种货币的实际收盘价。它甚至捕捉到了六月中旬和八月下旬的以太币价格上升(和随后的下跌)。正如在其他博客中提到的,由于误差无法传递到随后的预测中,单点预测的模型通常是有误导性的。由于将真实价格馈送到模型中,无论误差有多大,都会在下一个时间点被重新设置。比特币随机游走其实特别具欺骗性,因为 y 轴的分布范围很宽,才使得预测线看起来很平滑。


不幸的是,使用单点预测评估时间序列模型很普遍。使用多点预测测量准确率可能会更好,用这种方法,之前预测的误差不会被重设,而会组合到后续的预测中。因此,性能较差的模型将得到更多的惩罚。用数学公式定义即:

接下来我会使用随机游走模型对整个测试集进行预测。


模型的预测对随机种子非常敏感。我选择了一个随机种子,其中整个区间内的随机游走对于 Ethereum 来说几乎都是降低的。在相应的 Jupyter notebook 完整代码中,你可以交互地控制种子的值,看看它表现的有多糟糕,如下图所示:



注意单点随机游走看起来多么准确,即使其背后没有任何实质性内容。幸运的是,你会对任何声称能够准确预测价格的文章持怀疑态度的。


长短期记忆(LSTM)


如果读者对 LSTM 的理论比较感兴趣,可以查看上文机器之心发过的教程与解释。在本文中,我们并不需要从头构建一个 LSTM 网络,我们甚至都不需要理解它就能通过如 Keras 或 PyTorch 那样的深度学习框架完成实现。本文选择的是 Keras 框架,因为它只需要很少的理论知识,并且是目前最直观的深度学习框架。



我创建了一个称之为 model_data 的数据框架,我们删除了前面的一些列(开盘价格、日最高价和最低价),并重新制定一些新的列。close_off_high 列表示收盘价与日最高价之间的距离,-1 和 1 分别表示收盘价等于日最低或日最高价。volatility 列表示日最高价与最低价之间的差除以开盘价。model_data 按从早到晚的顺序排列,因此实际上我们并不需要日期列,所以这些信息并不会输入到模型中。


我们的 LSTM 模型将使用前面的数据(Bitcoin 和 eth)来预测特定虚拟货币第二天的收盘价格。我们必须确定模型能访问之前多少天的数据,这里简单地设置为 10,当然该超参数还能进一步优化。因此我们构建了一个由连续 10 天数据(即窗口)组成的小数据框,即第一个窗口(window)将由训练集中 0-9 行数据组成,第二个窗口由 1-10 行数据组成等。选择较小的窗口规模意味着我们的模型可以使用更多的窗口,但缺点是模型没有足够的信息检测复杂的长期行为。


深度学习模型对输入的格式要求比较高,而原数据中有一些列的值范围非常广,可能取值范围能达到数百万的量级。所以首先我们就需要归一化这些数据,因此每一个特征的取值都会服从均值为 0、方差为 1 的属性。一般来说,我们会令取值处于-1 到 1 之间,off_high 和 volatility 列基本已经符合条件,剩下的特征可以使用归一化方法。



这个表格代表我们的 LSTM 模型输入数据的一个样本,这 10 条数据可以组成一个窗口,并且我们总共有数百个类似的窗口。我们已经归一化了一些列以令它们的值在第一个时间点等于 0,所以我们的目标是预测该时间点的价格变化。我们现在已经准备建立 LSTM 模型了,Keras 贯序模型非常简单,我们只需要将不同的层级叠加在一起就行了。


  1. # import the relevant Keras modules

  2. from keras.models import Sequential

  3. from keras.layers import Activation, Dense

  4. from keras.layers import LSTM

  5. from keras.layers import Dropout

  6. def build_model(inputs, output_size, neurons, activ_func = "linear",

  7.                dropout =0.25, loss="mae", optimizer="adam"):

  8.    model = Sequential()

  9.    model.add(LSTM(neurons, input_shape=(inputs.shape[1], inputs.shape[2])))

  10.    model.add(Dropout(dropout))

  11.    model.add(Dense(units=output_size))

  12.    model.add(Activation(activ_func))

  13.    model.compile(loss=loss, optimizer=optimizer)

  14.    return model



那么,build_model 函数构建了一个模型,名为 model(model= Sequential),该模型添加了一个 LSTM 层和全连接层。该层的形态已经调整以适合输入(n x m 的矩阵,n 和 m 分别代表时间点/行和列)。该函数还包括更通用的神经网络特征,如 dropout 和激活函数。现在,我们只需指定 LSTM 层中神经元的数量(我选择了 20 个以保证合理的运行时)和训练数据。


  1. # random seed for reproducibility

  2. np.random.seed(202)

  3. # initialise model architecture

  4. eth_model = build_model(LSTM_training_inputs, output_size=1, neurons = 20)

  5. # model output is next price normalised to 10th previous closing price

  6. LSTM_training_outputs = (training_set['eth_Close'][window_len:].values/training_set['eth_Close'][:-window_len].values)-1

  7. # train model on data

  8. # note: eth_history contains information on the training error per epoch

  9. eth_history = eth_model.fit(LSTM_training_inputs, LSTM_training_outputs,

  10.                            epochs=50, batch_size=1, verbose=2, shuffle=True)

  11. #eth_preds = np.loadtxt('eth_preds.txt')


  12. --------------------------------------------------------------------------


  13. Epoch 50/50

  14. 6s - loss: 0.0625



我们刚才构建了一个 LSTM 模型来预测明天的以太币收盘价。现在我们来看一下效果如何。首先检查训练集性能(2017 年 7 月之前的数据)。代码下面的数字代表 50 次训练迭代后该模型在训练集上的平均绝对误差。我们可以看到模型输出就是每日收盘价。



我们不应对它的准确率感到惊讶。该模型可以检测误差来源并进行调整。事实上,获取趋近于零的训练误差并不难。我们只需要数百个神经元和数千个训练 epoch。我们应该对它在测试集上的性能更感兴趣,因为测试集中是模型未见过的全新数据。


注意单点预测具备误导性,而我们的 LSTM 模型似乎可以在未见过的测试集上实现良好的性能。最显著的缺点是单点预测无法检测出当以太币突然上涨时必然会下跌(如六月中和十月)。事实上,它一直都是失败的,只不过在这些波动点更加明显而已。预测价格一般更接近一天后的实际价格(如七月中的下跌)。我们还可以构建一个适用于比特币的类似的 LSTM 模型,测试集预测结果见下图(完整代码见上文地址)。



如前所述,单点预测具有一定误导性。我们现在构建一个 LSTM 模型来预测接下来 5 天的虚拟货币价格。



从视觉效果上来看,预测结果没有其单点预测更加鲜明。但是,我很高兴,该模型返回了一些细微的行为(如以太币图的第二条线);它不仅仅预测价格在一个方向的移动轨迹。因此,该模型还有很多优化空间。


现在回到单点预测,我们的深度机器人工神经模型看起来还不错,但是随机游走模型看起来也还行。与随机游走模型类似,LSTM 模型对随机种子的选择很敏感(模型权重最初是随机分配的)。那么,如果我们想对比这两种模型,就需要把每个模型运行多次(比如,25 次)来评估模型误差。误差可以作为测试集中真实和预测收盘价的绝对差。



或许 AI 完全值得这些炒作!这些图显示了在进行 25 次不同的初始化之后,每个模型在测试集上的误差。LSTM 模型对比特币和以太币价格的预测误差分别是 0.04 和 0.05,完胜相应的随机游走模型。


只是为了打败随机游走模型的话也太 low 了。对比 LSTM 模型和更合适的时序模型(加权平均值,ARIMA 或 Facebook 的 Prophet)岂不是更加有趣!另外,我确定很难再提升我们的 LSTM 模型了(添加更多层和/或神经元,改变批量大小、学习率等)。可能虚拟货币价格变化没有规律吧,可能没有一个模型可以把信号和噪声分离开(类似于使用深度学习预测地震的优点)。以后的文章中可能会讨论这些话题。


幸运的是,你已经察觉到我对使用深度学习预测虚拟货币价格变化的怀疑态度。原因在于我们忽略了最优的框架:人类智能。很明显,预测虚拟货币价格的完美模型是:



我确定他们最终最终会找到深度学习的使用案例的。同时,你可以下载完整的 Python 代码构建自己的模型。


原文链接:https://dashee87.github.io/deep%20learning/python/predicting-cryptocurrency-prices-with-deep-learning/



本文为机器之心编译,转载请联系本公众号获得授权。

✄------------------------------------------------

加入机器之心(全职记者/实习生):hr@jiqizhixin.com

投稿或寻求报道:content@jiqizhixin.com

广告&商务合作:bd@jiqizhixin.com

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存