我也想躺着收钱——一个比特币套利系统的实现

记得在很早的时候就在知乎日报上看过青铜时代:中本聪之惑这篇文章,当时的我完全没有搞懂作者在说什么,只是觉得很厉害,于是在添加完收藏之后也没有在多想这件事,也没有精力去想这件事。

大约在11月的时候,我终于忙完了手头所有的事情,一下子闲了下来,再一次重新整理收藏夹的时候再次发现了这篇文章,于是我又聚精会神地读了一遍,这次依然没有搞懂整个系统是怎么盈利的,但是我记住了一个数字:280%,作者估计的系统年化利率,虽然没有理解这篇文章的意思,但是我还是着手开始设计一个平台,因为即使因为各种原因,只能达到作者十分之一的收益率,28%,也是极其可观的。

平台的第一步肯定是先抓去一部分数据进行分析,同时这也是这个系统中最简单的一个部分,当时发现中国三大比特币交易平台 火币,btcc,okcoin 都有开放的查询接口,而且接口比较稳定,所以没有必要自己去页面爬取数据了,同时我也发现,各个平台也开放了交易接口,虽然不是特别稳定,稳定性也可以凑合凑合,这是我和青铜时代:中本聪之惑作者所处环境非常不一样的第一点:

  • 技术门槛大幅度降低

第二个不同点在抓取三个平台数据开始后不久就显现出来,

上面这张图是火币和btcc的价差实时监控,可以发现的是价差非常非常的小,接近没有,而且波动幅度也不是很大,总结起来就是:

  • 套利空间大幅度减小

真的是特别大幅度的减小,知乎文章的作者提到的价差空间在几十甚至上百的范围内,而仅仅夏天到冬天,价差就已经缩小到了几乎看不到的地步,非常恐怖。

这两个消息一好一坏,一下动摇了我的决心,但是经过大概0.5秒的纠结,金钱的诱惑还是战胜了理性,我决定继续把项目进行下去。

由于当时又找了实习,所以白天实习,晚上心情好的时候就写一点,不久抓取平台就完成了,没多少工作量,然后就是漫长的数据积累阶段了,没有一定的数据,我是没法凭空设计一个模型出来的,但是平台在抓取的同时也可以做一些其他的事情,于是我开始恶补一些金融的入门级知识,比如股票的实时成交价格是怎么产生的,order book是怎么一回事,什么是盘口,市价单,现价单,冰山委托都是什么东西,交易所是怎么赢利的,什么是做市商,什么是对冲,这些东西其实都相当入门级,但是对于一个计算机系的学生来说就是天书了。

在吃透了这些概念之后,我终于完全理解了套利的操作是怎么进行的:

  • 首先在两个比特币交易平台分别部署现金,并且借入一定数量的比特币
  • 在两个平台价差拉大时在价位较高的平台卖出,在较低价位平台买入,确保数额相同
  • 在两个平台价差缩小甚至逆转时再做逆向操作

大家也可以参考一下知乎文章上的“两个苹果”的解释,这三步操作其实描述的就是一个对冲,对冲是一种规避风险的方法,这里被对冲掉的就是比特币本身的价值,也就是说,本来我们在投资比特币本身,通过对冲,我们实际上在投资的是比特币市场之间的价差:

这个行为有一个学术点的名字:

统计套利

整个统计套利的基石就在于把比特币币值变化的风险给对冲掉,所以我们必须做到以下几点:

  • 平台上部署的比特币必须是借来的(或者说是融币融来的)
  • 必须保证价差计算准确,不能有太多的滑点(实际成交价格和意向成交价格的偏差)
  • 同时整个系统的延迟必须做到最小,否则在两个交易所的下单会受到币值波动的影响

但是这里就有一个问题了,投资价差和投资比特币本身有什么区别呢?区别只有一个,就是价差收敛,什么叫价差收敛呢?就是说价差虽然会有变化,但是始终是稳定在某个值附近,实际导致这个现象的原因是不同比特币交易所买卖的实际上是同一个东西——比特币。就像不同地方的麦当劳一样,价格可能会有不同,但总体上这种价差不会发生太大变化,总是在某个值上下变化。利用这个特点我们就可以做出一些有意思的策略了。

但是想要对冲掉比特币本身的价值就意味着需要融币,融币意味着每天千分之一左右的利息,就是说如果今天你的策略获得的利润小于千分之一,那么即使你的策略能够产生利润,也是没有价值的。

在对比特币的不断了解中,我也发现了比特币的魅力之处:

  • 所有交易所全天候24小时交易
  • 国内三大交易所的比特币人民币现货交易完全没有手续费,但是提现的时候会有手续费和延迟
  • 完全没有涨幅和跌幅的限制,也就是说在一分钟之内理论上来说完全有可能1个比特币会变成不如一张厕纸值钱,也可能变得比一吨黄金还贵
  • 监管很少,交易所有整个跑路的风险(参考Mt.Gox

抛开比特币本质不谈,比特币交易的这些性质简直就是金融的一朵奇葩,所以比特币交易的数据也是非常有特点,或者说非常有价值的,这也更加激发了我对比特币的兴趣。

在收集数据的同时,我也开始了套利平台的一些基础建设,根据设计,平台划分为几个大的并且互相几乎完全独立的模块:

哈勃(hubble)


hubble 模块的计划功能是图形化的数据抓取和展示平台,作用是数据可视化,提供平台的价格和差价的可视化功能。当时的希望是能够通过hubble来目测发现一些市场的基本规律。最后hubble整个是用web2py框架写的,抓取则用的是crontab,提供市场分钟级的数据展示,用来观察市场走势。

南柯(Nanke)


取名自南柯一梦,作用是市场数据的回测,为了回测方便,我把策略逻辑和框架逻辑分离,最后南柯模块可以直接在网页上编辑和回测策略,并且查看报告。取名南柯其实也是警示自己,回测再美好也是南柯一梦。

黄粱(Huangliang)

计划中南柯的姊妹模块,提供比南柯更精细的回测功能,但是目前并没有开发。

矩阵(matrix)

是的,矩阵取名自黑客帝国,这个模块很有意思,是一个根据即时交易所价格模拟策略在交易所行为的模块,在南柯初期验证过的策略代码在上线之前都需要经过matrix的模拟,但是matrix目前的功能比较有限,只能模拟交易所的市价单行为,因为市价单只需要再查一遍order book就可以了,但这对于我来说已经足够,matrix还可以模拟交易所的交易延迟和交易失败造成的影响,并且也支持在线编辑策略代码和热加载,热重载,和同时模拟多个策略的行为。

但是,matrix这个模块的名字也时刻提醒着我,再真实,也是假的,matrix不能也不可能模拟市场的全部行为,一切以线上为准。实际上也由于种种原因,市场的行为在中高频的情况下也和matrix有相当的差异。

斯叶特(sjet)

先说一下命名吧,卡伦·斯叶特是一款非常老的游戏《homeworld》中库申人的精神领袖,是一个女科学家,把自己嵌入到了库申人的巨大飞船mothership中作为生物cpu,这个游戏也是第一款让我感动的游戏,有兴趣大家可以了解下。把这个传奇作为模块的名字,模块的作用也很明显了:sjet是整个平台的核心,是线上策略运行的地方,也运用了和matrix相近的技术,支持策略脚本的线上编辑和热重载,理论上sjet和matrix的策略脚本可以通用,就是说在matrix经过验证的策略理论上可以无缝直接在线上运行,但是实际操作的时候还是有一些策略需要经过一些小修改才能上线到sjet。

还有一些小模块不表

框架开发中遇到的一些技术问题Q&A

如何让程序持续抓取?

这个问题有两种解决方案:

  • crontab定时抓取
  • demon进程中循环抓取

其中hubble模块使用了第一种而matrix和sjet模块使用了第二种。

如何实现热加载,热重载python策略脚本?

初始化时直接import 策略模块,循环判断策略脚本是否发生变化,如果发生变化,则重新加载,唯一需要注意的一点是在重载是不能直接再次import模块,而要使用python的reload语句。这里还有一点就是由于需要在线上程序运行的时候热重载,所以最好要把策略做成无状态的,就算有状态的话最好也要用文件,或者数据库,或者redis的形式存储下来,否则策略一重载状态就没了。另一个需要注意的地方是由于程序常驻内存,所以不当的策略会导致内存泄漏,稍微注意一下就行。

程序需要在两方下单,要是一方失败了怎么办?

需要对双方的下单进行事务化处理,但是这种事务和数据库的事务完全不同,而是类似于分布式事务,对于fail的处理需要谨慎,在一次套利开始时纪录下两个市场账户中的比特币分布和期望中交易完成后时称中的比特币分布情况,接下来分别发送两个下单请求,然后锁住整个交易系统,接下来在市场账户中的比特币分布达到成功条件或失败条件时解锁交易系统继续交易,在其他情况下判断交易应该继续进行还是回滚,走相应的逻辑就行。

交易受滑点的影响太大怎么办?

这个也是目前交易中遇到的最大问题,策略经常在南柯和矩阵中运行非常良好,但是一到sjet就开始亏钱,揪其原因就是滑点太大,这个问题目前来看几乎是无解的,只能设计一些策略来减少滑点造成的损失。

目前自动化交易的利润空间有多大?

我手头上也没有具体数据,但是就目前这个策略上线这几天的运行情况来看,是一个数学期望大于30%的年化收益率,但是风险(方差)非常大,而且需要更多时间来验证,但是不排除今后设计更好的策略能够提升。

为什么使用市价单而不考虑限价单这种不会产生滑点的手段?

也考虑过,限价单并不是立即成交的,有可能一直不成交,会大大增加套利事务的复杂性,不是不想用,是没想好怎么用才合适。

交易策略

在解决了这些框架开发的问题之后,我终于可以将注意力集到交易策略上了,按照知乎文章上的思路,首先是找出两个市场价差分布的均值E和方差σ,然后再确定一个大于0的参数α,然后在价差大于E+ασ时做正向搬运,当价差小于E-ασ时做反向搬运,这是一个简单而有效的策略,唯一可能导致亏损的点就是交易时的滑点了。

这里唯一需要确定的参数是α,一个较小的α意味着更多的交易次数,但是也意味着每次交易的利润会变小,然而南柯和matrix的模拟显示这也意味着更多的总利润,这是比较耐人寻味的一点。然而减小α的代价就是系统受滑点的影响也就更大,如果没有较强的高频交易能力,一个较小的α会让你亏成翔。抛开其他问题不谈,我们肯定是希望有一个尽可能小的α,但是由于这个系统的交易延迟有1~2秒之久,比一个高频系统的最低要求都差太多了,只能算是一个中低频的自动交易系统,所以说α就不能选的很小了。绝对不要小看这一两秒,这一两秒足够让一个在matrix和南柯上爆赚的策略在实盘亏成翔,所以说

回测很丰满,现实很骨感

这句话绝对非常非常有道理。

我们不妨把上面这个策略称为simple sigma,整个simple sigma策略的假设就有这几点:

  • 两个市场的价差不恒定,而是在某个数值(E)附近上下波动
  • 两个市场的价差大体上符合正态分布

这两个假设都是基本上正确的,所以说理论上这个策略是可以做到盈利的。

深入思考两个假设

虽然上面两个假设都是正确的,但是实际上微观的价差的分布并不总是围绕平均值波动,并且如果根据历史数据计算出一个价差的平均值,那么谁也没法保证这个平均值在将来也会适用,我们观察一下下面这张图:

这张图显示的是火币和btcc两个市场1月4日到1月6日三天的价差数据,在前一个红框里,价差围绕着3.5左右波动,而在后一个红框里,价差围绕着0上下波动,如果我们按照simple sigma策略的思路,那么我们就会失去1月6号几乎一整天的套利空间。

我们需要的,是一个能够动态反应价差“均值”的标志,它不能变化得太快,否则会失去“均值”的作用,也不能太慢,否则难以跟上价差的变化幅度,所以必须有一个参数来确定这一点。

也就是在这个时候,我想到了之前做智能车的时候运用到的一个数学工具,互补滤波,整个智能车项目对于我来说就是一场巨大的悲剧,但是我却记住了互补滤波,互补滤波原本的作用是过滤掉一些信号中的高频杂音,从而提取出有用的低频信号,但是在不同的场景下也有一些其他的用途,但是是否适合运用在这里,效果如何呢?

不了解互补滤波的同学可以戳这里

接着首先,我修改了simple sigma策略,将其中的E(均值)换成了互补滤波的输出,并且在南柯和matrix上进行了回测和模拟,回测和模拟都显示这种新的策略比simple sigma的盈利多30%以上,那么理论上,这个策略还不错。

(后来看《统计套利》这本书才知道,这种方法早也被人发明出来了,叫指数加权平均移动模型,所以说多读一点书还是可以少走一些弯路的)

总的来说,用上了互补滤波的策略之所以比simple sigma表现得更好,还是因为它正确地精细化了市场价格差波动的模型,现在模型的假设是这样的:

  • 两个市场的价差不恒定,在某个特定时间段内会在某个数值(E)附近上下波动
  • 两个市场的价差大体上符合正态分布
  • 一个时间段内市场的价差大体也符合正态分布

是否还有能更加正确或者更加精细市场行为的模型呢?我认为肯定是有的,只是我没有发现而已,如果大家觉得自己发现了一些有意思的市场规律,一定要告诉我。但在发现更好的模型前,就用它上线了。

上线那些事

由于本人技术太渣,上面这些事情做完时,时间已经从11月中旬到达了12月末,除了sjet之外的模块都已经上线,只剩下最重要的实盘策略模块sjet了。于是我挑了一个好日子上线,12月31日晚上,这样一来,系统第一次盈利就会在1月1日这样一个好日子,以后装逼的时候就可以说在2016年的第一天我上线了一个牛逼的系统,然后如何如何,想想也有些小激动呢。其实真正的原因是平时要实习,也只有元旦假期才能确保我有充分的时间处理刚上线系统中的各种bug。

上线的时候,我选择了一个非常保守的仓位,0.01比特币,大概是30块钱,所以就算我的系统爆炸,也就是半天饭钱而已。果不其然,系统完全被各种bug所困扰,只进行了一两次有效交易,而且由于各种bug,系统完全在贴钱,新年第一天的也时不时的需要查看一下系统的稳定性,我也是醉了。

新年的第一天不仅没有盈利,系统反而因为稳定性原因亏掉了1毛钱,但是上线还是勉勉强强上去了。装逼失败。:cry:

1号2号基本上解决了系统的各种bug,3号把收益的图形化模块上线了,终于从图形化界面上看到系统第一次盈利:

然而还没来得及高兴多久,刚刚盈利的money马上给亏回去了:

调查原因发现策略本身没有问题,是滑点造成的利润损失,于是6,7号两天我开始尝试调整模型参数(调大α),并且加入一些策略(在开始交易前考虑价差变化方向和速度),希望能够有效遏制滑点,结果是滑点没有消失,但是严重程度有所减轻,经过一周多的验证,系统可以盈利:

后几天的时间慢慢把系统的监控模块titan也上线了,系统收益和稳定性报警都能够通过短信形式直接发送到手机上,实现了半个自动化运维。

当然系统中还有很多非常不完善的地方,并且算法还存在非常大的继续优化的空间,也希望对交易算法有了解或者感兴趣的同学email我或者私信我,我们可以一起改进这个系统。

参考资料