博客

量化套利入门 02|同一个币,为什么会有两个价格?

两个市场的价格不一样,通常是因为在它们之间搬东西很麻烦。套利者能赚的,是搬运成本付完以后还剩下的那一点。

约 12 分钟量化套利入门系列

2018 年 1 月,韩国交易所里的比特币比美国市场贵了一大截。Choi、Lehar 和 Stauffer 在论文的 2019 年工作稿里记录到,当月的价差最高约 54.48%。把时间拉长到 2016 年 1 月至 2020 年 1 月,论文 2022 年的修订版算出的平均溢价约为 2.27%。这个现象有个外号,叫泡菜溢价。

路线看上去一目了然。在美国用美元买币,转到韩国交易所卖成韩元,再把韩元换回美元。换回来的美元比出发时多,差额就是利润。可这条价差在几年里反复出现,并没有被全世界的交易员很快抹平。

这篇文章想回答的就是这个问题。同一个币为什么会有两个价格,屏幕上的价差里,又有多少能真的变成钱。先说结论。两地价格能分开,是因为在两地之间搬运资产和资金有成本、要时间、还可能被卡住。套利者赚的不是价差本身,而是价差减去搬运成本以后剩下的部分。前提还要加一条,两边的订单都得真的成交。

复古金融终端风插画:两座市场大厅用库存桥连接,同一种资产在两边处于不同价格高度
同一个资产,两座市场,两份价格。桥上能搬多少货,决定价差能赚多少。

两个价格是怎么来的,价差又是谁在付

每家交易所都是一个独立的集市。它的价格由在这里挂单的买家和卖家撮合出来。韩国交易所的买家看不见美国交易所的卖单,也不能直接跟他们成交。两边各自供需,各自出价,本来就没有理由天然相等。

把两个价格拉到一起的,只有那些愿意在两边同时买卖的人。他们在便宜的地方买,等于给那里添了买盘,价格被推高一点。在贵的地方卖,等于给那里添了卖盘,价格被压低一点。这样搬运的人越多,两边越接近。

所以价差可以看成一笔搬运费。它由谁支付,要看是谁在不便宜的地方成交了。在泡菜溢价里,付钱的是在韩国用韩元高价买币的人,以及在海外低价卖出的人。他们未必不知道别处便宜,只是自己去不了,或者去一趟的成本更高。

泡菜溢价的搬运费为什么这么高,论文给了具体的阻力。外国人想在韩国交易所开户,需要当地银行账户和当地手机号,短期去一趟几乎办不下来。韩国的外汇管理让资金进入韩国比离开容易,最后一步把韩元换回美元带出去,恰好是最难的一步。论文还发现,溢价高的时候,往往也是比特币转账确认慢、链上手续费高、价格波动大的时候。这是统计上的相关关系,论文用它支持一个解释,搬运越慢越贵,越少人愿意搬,价差就越能撑住。原文可以看论文的 SSRN 页面和2019 年工作稿。

有人把跨市场套利分成 CC、CD、DD。C 指中心化交易所,也就是币安、OKX 这类由公司记账、用户把钱存进去交易的平台。D 指链上交易市场,交易直接在区块链上由合约完成。CC 是两家交易所之间做价差,CD 是交易所和链上池子之间做价差,DD 是两个链上池子之间做价差。

这个分类对写程序有用。三种场景的账户、签名、确认方式和失败原因都不一样。交易所靠账户余额和订单簿,链上靠钱包、区块和合约。若按利润来源来分,它们却是同一类,都在收同一种搬运费。路换了,价差还是那条价差。

先确认两边卖的是同一样东西

搬运费能收,前提是两边真的是同一种资产。这一点比看上去容易出错。同名代币未必使用同一份合约。交易所里的 USDT 也可能分别对应 TRON、Ethereum 或其他网络的充提通道。若一侧只能提 TRC20,另一侧只收 ERC20,中间就多了一次跨链或换币。屏幕上只差一个后缀,交易链路里却多出一座桥,多一份费用和等待。

合约也不能拿来冒充现货。一个季度交割合约、一个永续合约和一枚真正能提走的币,价格可以很接近,持有的权利却不同。交割合约到期才按规则结算,永续合约要定期支付或收取资金费,现货才是你能提走的东西。它们之间的价差有自己的规律,后面讲基差和资金费的两篇会专门展开。

所以程序比较报价以前,要先给每个资产建一份身份档案。网络、合约地址、计价币、到期日和结算方式都对上,才算同一件东西。否则跑得再快,也只是把两件相似的东西当成了一件。

屏幕上的价差,有多少能成交

确认是同一件东西以后,下一个问题是能按什么价格成交。行情页面显示的通常是买一和卖一。卖一是此刻挂得最便宜的卖单,买一是此刻出价最高的买单。它们只是订单簿最前面的一小块。

订单簿可以想成一排按价格排好的货架。最便宜的货摆在最前面,但数量有限,拿完了就得往后拿更贵的。假设便宜市场卖一是 100,只有 0.1 枚。后面依次挂着 100.3、100.7 和 101 各 0.3 枚。买一整枚,要花 0.1 × 100 + 0.3 × 100.3 + 0.3 × 100.7 + 0.3 × 101 = 100.6。平均价已经不是 100 了,多出来的 0.6 就是滑点。

贵的一边也一样。买一写着 101,未必有人愿意按 101 接下你的全部数量。程序不能拿两个最好看的数字相减。它要沿着订单簿逐档累加,算出目标数量的平均成交价。链上池子没有订单簿,价格由池子里两种资产的数量按公式决定,买得越多价格越高,所以也要按公式算出平均价,再加上池子手续费和 gas。gas 是在链上执行交易付给网络的费用。

换一组完整的假设数字走一遍。A 市场卖一是 100,B 市场买一是 100.86,页面上的价差是 0.86%。程序要做 2 枚。沿着盘口算下来,A 市场买入 2 枚的平均价是 100.22,B 市场卖出 2 枚的平均价是 100.86,两边平均价每枚只差 0.64,2 枚的毛差价是 1.28。

接着扣成本。两边手续费合计 0.36。以后把库存调回原位要花钱,摊到这笔交易上算 0.18。从看到报价到订单到达交易所有延迟,价格可能已经变了,再预留 0.30 的安全垫。1.28 − 0.36 − 0.18 − 0.30 = 0.44。买入花了约 200.44,0.44 除以 200.44 约为 0.22%。页面上的 0.86%,真正允许程序下单的空间只剩 0.22%。

下单数量也不能先拍脑袋定好再塞给市场。程序通常从两边盘口同时往深处扫,找到扣完所有成本后仍为正的最后一档。比如前 0.4 枚可能很好赚,做到 1.7 枚刚好打平,再往后就是赔钱。机会有多大,是两个盘口一起决定的。

回测在这里最容易骗自己。回测是拿历史数据模拟策略过去会怎样。若历史数据只有一分钟 K 线,也就是每分钟的开盘价、最高价、最低价和收盘价,程序根本不知道当时的买一卖一和挂单数量,也不知道那笔成交发生在你之前还是之后。拿 K 线最低价当买价、最高价当卖价,会得到一条漂亮得不真实的收益曲线。跨市场策略至少需要同一时间轴上的盘口快照,最好还能重放每一次挂单和成交的变化。

为什么不能等看到价差再搬币

回到泡菜溢价那条路线。在美国买币,转到韩国再卖。问题出在中间那段转账。比特币从一个交易所转到另一个,要等区块确认,交易所还会要求多个确认才给入账。这段时间里,你手里拿着一枚正在路上的币,价格涨跌全由你承担。

论文专门指出了这一点。韩国那边通常没法先借币卖空,把高价提前锁住,币只能等到账以后再卖。于是在转账那段时间里,这笔交易其实是一笔方向押注。比特币波动又大,等币到账时,价差已经被行情吞掉并不稀奇。

所以跨市场套利的常见做法,是把库存提前放在两边。A 市场放现金,B 市场放币。机会出现时两边同时下单,A 买进,B 卖出。两笔都成交以后,手里币的总数没变,价格涨跌对你基本不再有影响,这就是方向风险关掉了。之后再找成本低的时候,把两边的现金和币慢慢调回原位,这一步叫再平衡。

这像两地经营的粮商。北仓有人要高价收粮,粮商不会等南仓的货车开三天再接单。两边仓库本来就有货,北边先卖,南边先买,货车之后再慢慢调。这个类比在先成交、后调货这一点上成立。

类比也有两处不成立。粮商的仓库是自己的,交易所里的余额却是交易所欠你的一笔账,交易所出事,货就未必拿得回来。2022 年 11 月 FTX 先暂停提现,几天后申请破产,存在里面的套利库存就和其他用户的钱一样被困住了。这种风险,两边买卖再对得齐也对冲不掉。另一处是,再平衡并没有省掉搬运费,只是把它挪到了后面,而且可以挑时机、攒成一批再搬。前面算例里那 0.18,就是这笔挪后支付的搬运费。

快,是为了缩短单边裸露的时间

复古金融终端风插画:一侧订单成交,另一座市场的闸门关闭,交易者留下单边仓位
最危险的不是没看见价差,而是第一条腿成交以后,第二扇门关了。

库存铺好以后,两笔订单仍然不是同一个动作。它们发往两家交易所,走不同的网络,被不同的撮合系统处理。一笔交易里的每一笔订单,业内叫一条腿。最糟的情况是只成交了一条腿,比如 A 市场买到了,B 市场的买单却在你到达前撤走了。这时你手里多了一份没有对冲的币,程序从套利系统变成了方向交易系统。价格若快速反向,几秒钟就能吃掉很多次的小利润。

把服务器部署在靠近交易所的机房,同时维护多地行情连接,把下单信号尽量同时发到各个市场,都是为了缩短两条腿之间的空档。架构做得复杂,为的就是让两边尽量同时收到指令。

可是快不等于莽。程序还要处理部分成交、撤单失败、重复回报、接口限频和网络抖动。上一篇提到的 Barry Johnson《Algorithmic Trading & DMA》,花了大量篇幅讲市场微观结构、订单类型、下单和执行策略,道理也在这里。套利想法往往只有一句话,可靠地成交才是大部分工作。

一套能活下来的系统,通常不会只有发现机会和下单两个状态。它至少要知道订单已发送、交易所已接收、部分成交、全部成交、撤单中、撤单成功和状态未知。最麻烦的是状态未知。网络断开时,本地不知道订单有没有到交易所。此时再发一笔可能变成重复下单,什么都不做又可能留下裸仓。

所以每条腿都要有唯一订单号,恢复连接后先向交易所查询事实,再决定补单或撤单。若一侧只成交 60%,另一侧成交 100%,系统面对的也不是一句套利失败。它要立刻在几条路里选一条,补齐剩下的 40%,反向平掉多出来的仓位,或者到第三个市场临时对冲。每条路的价格都比原计划差,选哪条取决于当时哪边盘口更厚。那一刻,风控代码比找价差的代码更值钱。

多地部署也有代价。机器越多,时钟同步、重复信号和主备切换越难。两台服务器同时以为自己是主节点,可能把同一个机会做两遍。机房画得再多也不解决这个问题。任何时刻都得说清谁有权发单,订单结果最后由谁记账。

最后只记一张账

前面说的每一种麻烦,最后都会落到账上。跨市场套利常用基点记账,1 个基点是 0.01%,100 个基点是 1%。换一组整数再算一次。假设两边表面价差是 80 个基点。双边手续费花掉 18 个,滑点花掉 16 个,下单期间行情变化花掉 12 个,再平衡和资金占用花掉 9 个。80 − 18 − 16 − 12 − 9 = 25,净剩 25 个基点。若只用最优报价回测,系统会把已经花掉的 55 个基点再算成一次利润。

这里有三个数字要分开看。80 个基点是理论收益,只存在于两个报价的减法里。两条腿成交那一刻,A 账户少了现金、B 账户多了现金,两边账户各看各的都像赚了,这是账面收益。等手续费结清、库存调回原位、占用资金的成本也算进去,剩下的 25 个基点才是净利润。单边成交、交易所冻结提现这类事故不会每笔都发生,但它们的损失也得按概率摊进这张账。

这张账还会随条件变化而失效。交易所调高手续费,盘口变薄,提现通道暂停,或者更多更快的对手盯上同一条价差,25 个基点都可能变成负数。所以一笔交易结束后,最该看的是两边资产折成同一计价单位后到底多了多少,抓到了几次机会倒在其次。没有完成对账的套利,只是让两边账户同时变得更复杂。

再回头看泡菜溢价。平均 2.27% 的价差能挂在那里几年,不是因为没人看见,而是因为对大多数人来说,开户、转账、等确认、把韩元换回美元带出去,这一整套搬运费比价差还贵。同一个币有两个价格,说明两地之间隔着一堵墙。价差有多高,大致就是翻这堵墙要付多少钱。能赚到钱的,是翻墙成本比别人低、而且两条腿都能踩稳的人。