作者|亚当金
译者|国玺
编辑| Aholiab
出品|区块链大本营(区块链_营地)
股市里的人都知道,天天盯着大盘做决策,不仅让人累,还会让人秃顶。于是一堆顶尖数学家开始用数学手段预测股市。
加密货币市场也是一样,加密货币市场波动更加频繁和剧烈。为解决这一问题,国外加密货币开发商亚当金(Adam King)提出了新的解决方案。
结合人工智能在预测方面的独特优势,亚当提出使用深度强化学习来构建自动加密货币交易程序。同时这位小哥还做了一个真的可以交易比特币的展示模型。他是怎么做到的?这个自动交易程序能达到什么效果?让我们在文中找到答案。
在本文中,我们将使用深度强化学习来构建一个加密货币自动交易代理(agent),并训练它通过交易比特币来获利。
为了避免重复制作轮子,本教程中我们将使用人工智能研究机构OpenAI开发的包。
目前人工智能已经在很多领域超越了人类,从谷歌DeepMind团队开发的AlphaGo,到围棋世界冠军李世石,再到后来在《星际争霸》中以10: 1击败两名职业选手的同门AlphaStar。近日,开放AI战队OpenAI Five在Dota2比赛中以2: 0击败世界冠军OG。
Google DeepMind团队的星际人工智能产品AlphaStar的训练过程
人工智能给我们带来了许多激动人心的成果。虽然我们不会打造出AlphaGo这样令人印象深刻的产品,但在日常的比特币交易中盈利并不容易。
所以,与其冒着脱发的风险去探索比特币价格的规律,为什么不让人工智能大显身手呢?
本文将通过人工智能技术做三方面的尝试:为我们的agent创建一个测试和强化学习的健身房环境;以简单优雅的方式可视化我们的测试环境;培训我们的代理学习有利可图的比特币交易策略。
这里的一些操作可能会比较麻烦,比如从头开始搭建健身房测试环境,可视化测试环境,但是不用担心,这些细节我会仔细介绍的,跟上我的节奏就好。
库安装
在本教程中,我们将使用Zielak提供的Kaggle数据集。如果您需要这些数据,可以下载。我的Github仓库中的csv数据文件。
首先,让我们导入所有必需的Python库。如果您的计算机上没有安装这些库,您可以使用pip install命令来安装它们。
接下来,我们创建一类比特币交易环境。我们需要传入一个pandas数据框、一个检查窗口大小(lookback_window_size)以指示代理需要分析每个时间步中前几个时间步的数据,以及一个可选的代理帐户初始余额(initial_balance)。
在代码中,我们将佣金设置为每笔交易的0.075%,即加密货币期货交易所Bitmex的当前费率。同时,我们默认将串行参数设置为no (false),这意味着默认情况下,我们的数据帧将以随机方式遍历每个段。
此外,我们还调用了dropna函数删除非数字(NaN,不是数字)所在的行,以及reset_index函数在删除数据后重置数据帧的索引。
代码action_space的第一位数字表示三个可选选项,即买入、卖出或持有,第二位数字表示操作比例。最小单位是10%,也就是说这个数中的1、2、3分别代表10%、20%、30%。选择买入操作时,具体买入的比特币数量将是第二个数(金额)乘以当前账户的比特币余额(self.balance)。对于卖出操作,卖出比特币的具体数量也是第二个数(金额)乘以当前账户的比特币余额(self.balance)。
当然,如果你选择持有,你的账户里就不会买卖比特币,所以第二个数字是没有意义的。
我们的observation_space定义为一组0到1之间的连续浮点数,其大小为(10,lookback_window_size的大小)1)。这里的1操作是考虑当前时间步长的操作。对于窗口中的每一步,我们都会观察它的收盘价持仓值(OHCLV),我们当时的资产总价值,买入或卖出的比特币数量,以及我们买入或卖出这些比特币所花费的美元数量。
接下来,我们需要写一个reset函数来初始化比特币交易环境。
在代码中,我们使用重置会话控件(self。_reset_session)函数和下一次数据观测(self。_next_observation)函数,但是这些函数还没有定义。接下来我们来定义一下。
事务会话控制
会话控制是比特币交易环境的重要组成部分。如果我们将这个代理部署到外部,我们可能永远不会让它一次运行几个月。为此,我们将在数据帧参数(self.df)中限制代理可以连续看到的数据帧的数量。
在我们的重置会话控制(_reset_session)函数中,我们首先将当前时间步长(current_step)重置为0。接下来,我们将剩余时间步长(steps_left)设置为1和最大交易会话控制数(MAX_TRADING_SESSION)之间的一个随机数。当然,最大交易会话控制数需要在文件顶部定义。
接下来,如果我们需要连续遍历数据帧,我们应该设置遍历所有数据帧。否则,我们需要在数据帧参数(self.df)中设置一个随机的数据帧起始位置(frame_start),创建一个新的数据帧,命名为活动数据帧(active_df)。它是由从起始位置(frame_start)到起始位置的剩余时间步长(frame_start steps_left)的数据帧(self.df)的连续帧组成的切片。
使用数据帧切片的一个重要影响是,代理将获得更多用于长期训练的唯一数据。例如,如果我们只按顺序遍历数据帧(即从数据帧0到最后一帧(len(df)),那么我们就只有这么多唯一的数据点。我们的观测空间在每个时间步只能观测到少数状态。
然而,通过随机遍历数据帧的切片,我们有效地将原始数据集中每个时间点的账户余额、交易数据和当前比特币价格结合起来,从而创建更多唯一的数据点。接下来,我们用一个例子来说明。
我们的代理在每个时间步有三个选择:买入、卖出或持有。对于这三个选项中的每一个,还需要指定要操作的比特币数量,比如当前比特币余额的10%、20%或100%。这意味着我们的代理在每个时间步有30个不同的选择(当然,对于持有操作来说,这10个选择的效果是一样的),它从其中选择最好的一个。
回到我们随机切片后的比特币交易环境。在第10个时间步中,我们的代理可以在任何数据帧长度(len(df))的时间步中的数据帧内。考虑到代理在每个时间步长中可以做出30个选择,这意味着代理可以在10个时间步长的任何间隔中经历数据帧长度的30次方(len(df))。
虽然这样的操作可能会给大数据集带来相当大的噪音,但我相信这是一把双刃剑,可以让我们的代理从有限的数据量中学习到更多。但是对于测试数据集,我们还是会按顺序遍历,更接近“实时”的交易数据,这样可以更好更准确的检测我们的代理。
比特币交易代理都学到了什么?
为了更好地理解代理看到和学习到的特征,我们需要将比特币交易环境的观察空间可视化。比如下面是使用OpenCV进行可视化渲染后的观察空间。
OpenCV可视化渲染后的观察空间
图像中的每一条线代表我们观察空间(observation_space)中的一条线。前四行中类似于frequency的红线代表OHCL数据,底部的橙色和黄色点代表数量,底部波动的蓝色条代表代理商拥有的资产总值,底部较亮的点代表代理商的交易。
如果你眯着眼睛看这张图,你可以看到一个k线图,上面有一个指示条代表数量,还有一个类似莫尔斯码的界面显示交易历史。看来我们的智能体应该可以从观察空间(observation_space)的数据中学到一些东西。这里,我们将定义next observation(_ next _ observation)函数,在该函数中,我们将把观察到的数据缩放到0到1之间。
重要的是只对代理到目前为止观察到的数据进行缩放,以避免前瞻偏差(前瞻偏差是指在策略的制定中采取了一些未来的信息,这些信息在实际操作中基本上不可能获得)。
书写步骤
现在我们已经建立了观察空间,是时候写我们的阶跃函数了,它可以指导代理的行为。
每当当前交易时段的剩余操作步骤(self.steps_left)等于0时,我们将卖出所持有的所有比特币,调用重置时段控制(_reset_session)函数。
否则,我们将代理的报酬设置为当前持有的资产的总价值,只有在代理资金用完的情况下,才将done设置为True。
实际上,采取行动的过程非常简单,只有三个步骤:
第一步,获取当前比特币价格(current _ price);
第二步,确定是买入、卖出还是持有,以及要操作的份额;
第三步是实际买卖这些比特币。现在让我们编写take action (_take_action)函数,以便测试我们的比特币交易代理。
最后,在这个函数中,我们将交易添加到交易记录参数(self.trades)中,并更新我们的总资产值和帐户交易历史。
在这里,我们的代理人可以开始一个新的环境,学习新环境下比特币交易的特点,并采取行动获取利润。比特币交易代理人该大显身手了。
查看比特币交易代理的交易记录。
如上所述,我们需要将智能体的学习和决策过程可视化。当然,只通过最简单的方法输出代理人持有的资产总价值(print(self.net_worth))也不是不可以,但是这样做的乐趣会少很多。因此,我们决定绘制一个简单的比特币价格数据k线图,其中包含数量列和我们资产总价值的单独图表。
在代码中,我们需要为可视化定义一个StockTradingGraph函数。在函数初始化过程中,我们需要调用python可视化库matplotlib.pyplot,指出每一个需要可视化的数据。
为了更好地显示数据,我们需要在可视化方法中引入Python日期时间处理模块,并在数据上标注人类可读的日期和时间。
导入完成后,我们需要使用utcfromtimestamp函数将时间戳转换成UTC,然后使用计算机时间函数(strftime)以“年-月-日小时:分钟”的格式显示这个UTC时间。
至此,可视化函数的所有部分都已编写完成。回到比特币交易环境,我们现在可以总结出一个渲染函数来显示图形。
好吧!现在我们可以看到代理商在交易比特币。
利用Matplotlab库的可视化代理进行比特币数据交易
图中绿色竖条代表代理商在买入比特币,红色竖条代表代理商在卖出比特币。右上角的白框是代理人持有的资产总价值,下面的白框是当前的比特币价格。
允许我在这里自恋一下。我觉得这种可视化的效果简单而优雅。现在,是时候训练我们的比特币交易代理了,看看它能帮我们赚多少钱!
培训比特币交易代理
因为我们在训练代理人的时候使用的是时间序列数据,所以在交叉验证方面没有太多的选择。
拿一个常见的交叉验证形式来说:k倍(k组)交叉验证。在K重交叉验证中,你需要把数据分成K个相等的组,把每个组作为一个测试组,剩下的k-1组数据作为训练组。
但是时间序列数据对时间的依赖性很强,也就是说后面的数据对前面的数据依赖性很强。所以k-fold在这种情况下是行不通的,因为它会让我们的代理商提前知道未来的数据。即使有利可图,我们也不知道是因为代理商预测准确,还是因为代理商作弊。
当应用于时间序列数据时,大多数其他交叉验证策略也有相同的缺陷。所以我们只需要在完整的数据框架中给出一个分界点,第一部分的数据作为训练集,其余部分作为测试集。
接下来,由于我们的比特币交易环境被设置为仅处理单个数据帧,因此我们需要创建两个比特币交易环境,一个用于训练数据,一个用于测试数据。
在这里,我们可以训练模型。如下面的代码所示,我们只需要在比特币交易环境中创建代理,然后调用model.learn命令开始训练。
在这里,我们将使用机器学习框架tensorflow的可视化工具tensorboard,这样我们就可以方便地可视化tensorflow的数据流图,查看关于我们代理的一些量化指标。
例如,下图显示了200,000个时间步长后座席代表的盈利能力:
看来我们的代理商收获了不少好处啊!经过20万个时间步,最好的代理的总资产值增长了1000倍,而其他代理的总资产值平均增长了30多倍!
然而,就在这时,我意识到比特币交易环境出现了错误.修复错误后,这是新的收入图表:
正如你所看到的,我们的一些代理商做得很好,而另一些做得很差。一般来说,业绩好的代理人最多能让总资产价值增长10倍甚至60倍。
我必须承认,所有这些代理都是在虚拟的比特币交易环境中训练和测试的,因此将这种比特币交易代理直接应用于比特币区块链还为时过早。但至少这个结果告诉我们,利用人工智能进行加密货币交易决策是可行的。
接下来,让我们在比特币交易测试环境中测试代理。在测试环境中,我们将使用代理人从未见过的全新数据,来看看这些代理人是否学会了比特币的交易策略。
结果表明,我们训练有素的比特币交易代理人在新的测试环境中争先恐后地破产。
这并不奇怪,因为我们还有很多工作要做。只需将模型从当前的近似策略优化(PPO2)代理切换到稳定基线库中的A2C(优势行动者-批评家),就可以大大提高我们在该数据集上的性能。
同时也可以更新奖励功能,鼓励那些总资产值递增的操作,防止某些比特币交易代理在总资产值达到较高水平时懈怠。
仅仅是做这两个改动,就可以大大提高比特币交易代理在当前数据集上的性能。如下图所示,我们终于在新的数据测试环境中盈利了。
此外,我们可以做得更好。为了提高这些比特币交易代理的准确性,我们可以对超参数进行优化,对代理进行更长时间的训练。是时候给你的显卡施加一点压力了(深度学习代码在上面运行)!
如果你想继续优化,这里可以给你一些思路。可以使用贝叶斯优化在问题空间中寻找最佳超参数,使用显卡CUDA计算平台优化训练环境和测试环境。
结论
在本教程中,我们使用深度强化学习来创建一个可以从零开始获得收入的比特币交易代理。
具体来说,我们完成了以下任务:
OpenAI团队开发的测试强化学习算法的工具包Gym,从零开始创造了比特币交易环境;使用Python可视化库Matplotlib可视化比特币交易环境;我们已经用简单的交叉验证对我们的比特币交易代理进行了培训和测试;虽然还有很多工作要做,但现在我们已经看到了成功的曙光。
最后,虽然我们的比特币交易代理在新的数据测试环境下无法一直盈利,但我们离成功已经不远了。