之前给大家介绍了一下三角套利的原理,现在为大家奉上考虑交易成本的三角套利方法和代码。
一、考虑交易成本情况下的策略调整
我们以第一个策略(正循环套利_挣CNY策略为例)。
图:正循环套利(挣CNY)策略示意图
我们设计的套利策略是被动套利策略,具体来讲,我们在LTC/BTC,LTC/CNY,BTC/CNY三个市场上都是作为taker去吃单。
在LTC/BTC市场上下买单,就必须使用该市场的卖一价格(ltc_btc_sell1_price)加上一定的滑点(ltc_btc_slippage,以百分比表示)来作为买单价格,即:
P3 = ltc_btc_sell1_price*(1+ltc_btc_slippage)
同理,在BTC/CNY市场下买单,就必须使用该市场的卖一价格(btc_cny_sell1_price)加上一定的滑点(btc_cny_slippage,以百分比表示)来作为买单价格,即:
P1= btc_cny_sell1_price*(1+btc_cny_slippage)
同理,可以推导出在LTC/CNY市场下卖单的价格如下:
P2 = ltc_cny_buy1_price*(1-ltc_cny_slippage)
假设各个市场的费率情况如下(以百分比表示):
LTC/BTC: ltc_btc_fee
BTC/CNY: btc_cny_fee
LTC/CNY: ltc_cny_fee
在LTC/BTC市场净买入1个LTC,实际上需要买入1/(1-ltc_btc_fee)个LTC,其中的ltc_btc_fee比例部分,是被交易平台收走的手续费。买入1/(1-ltc_btc_fee)个LTC需要花费的BTC数量是:
ltc_btc_sell_1_price*(1+ltc_btc_slippage)/(1-ltc_btc_fee)
在LTC/CNY市场,卖出1个LTC,得到的CNY是:
ltc_cny_buy_1_price*(1-ltc_cny_slippage)*(1-ltc_cny_fee)
在BTC/CNY市场,净买入
ltc_btc_sell_1_price*(1+ltc_btc_slippage)/(1-ltc_btc_fee)
个BTC,实际上需要买入
ltc_btc_sell_1_price*(1+ltc_btc_slippage)/[(1-ltc_btc_fee)*(1-btc_cny_fee)]
个BTC,其中btc_cny_fee比例部分,是被平台收走的手续费,而对应需要花费的CNY是:
btc_cny_sell_1_price*(1+btc_cny_slippage)*ltc_btc_sell_1_price*(1+ltc_btc_slippage)/[(1-ltc_btc_fee)*(1-btc_cny_fee)]
套利的前提条件是:得到的CNY > 花费的CNY,即:
ltc_cny_buy_1_price*(1-ltc_cny_slippage)*(1-ltc_cny_fee)> btc_cny_sell_1_price*(1+btc_cny_slippage)*ltc_btc_sell_1_price*(1+ltc_btc_slippage)/[(1-ltc_btc_fee)*(1-btc_cny_fee)]
调整一下,对应的套利条件就是:
ltc_cny_buy_1_price >btc_cny_sell_1_price*ltc_btc_sell_1_price*(1+btc_cny_slippage)*(1+ltc_btc_slippage) /[(1-btc_cny_fee)*(1-ltc_btc_fee)*(1-ltc_cny_fee)*(1-ltc_cny_slippage)]
考虑到各市场费率都在千分之几的水平,做精度取舍后,该不等式可以进一步化简成:
(ltc_cny_buy_1_price/btc_cny_sell_1_price-ltc_btc_sell_1_price)/ltc_btc_sell_1_price
>btc_cny_slippage+ltc_btc_slippage+ltc_cny_slippage+btc_cny_fee+ltc_cny_fee+ltc_btc_fee
基本意思就是:只有当公允价和市场价的价差比例大于所有市场的费率总和再加上滑点总和时,做三角套利才是盈利的。
如果价差满足条件,交易数量上的计算规则如下:
先计算以下几个值:
1. LTC/BTC卖方盘口吃单数量:ltc_btc_sell1_quantity*order_ratio_ltc_btc,其中ltc_btc_sell1_quantity 代表LTC/BTC卖一档的数量,order_ratio_ltc_btc代表本策略在LTC/BTC盘口的吃单比例
2. LTC/CNY买方盘口吃单数量:ltc_cny_buy1_quantity*order_ratio_ltc_cny,其中order_ratio_ltc_cny代表本策略在LTC/CNY盘口的吃单比例
3. LTC/BTC账户中可以用来买LTC的BTC额度及可以置换的LTC个数:
btc_available - btc_reserve,可以置换成
(btc_available – btc_reserve)/ltc_btc_sell1_price个LTC
其中,btc_available表示该账户中可用的BTC数量,btc_reserve表示该账户中应该最少预留的BTC数量(这个数值由用户根据自己的风险偏好来设置,越高代表用户风险偏好越低)。
4. BTC/CNY账户中可以用来买BTC的CNY额度及可以置换的BTC个数和对应的LTC个数:
cny_available - cny_reserve, 可以置换成
(cny_available-cny_reserve)/btc_cny_sell1_price个BTC,
相当于
(cny_available-cny_reserve)/btc_cny_sell1_price/ltc_btc_sell1_price
个LTC
其中:cny_available表示该账户中可用的人民币数量,cny_reserve表示该账户中应该最少预留的人民币数量(这个数值由用户根据自己的风险偏好来设置,越高代表用户风险偏好越低)。
5. LTC/CNY账户中可以用来卖的LTC额度:
ltc_available – ltc_reserve
其中,ltc_available表示该账户中可用的LTC数量,ltc_reserve表示该账户中应该最少预留的LTC数量(这个数值由用户根据自己的风险偏好来设置,越高代表用户风险偏好越低)。
拿到上面5个值之后,对它们取最小值,得到LTC的数量,作为LTC/BTC市场的下单数量。然后,根据LTC/BTC成交的数量,得到需要对冲的LTC数量和BTC数量,分别在LTC/CNY和BTC/CNY市场下对冲单,所有市场先下限价单进行对冲,超时之后补市价单,确保完全对冲。
对最小交易单位的处理规则如下:
如果欲下单的LTC数量小于最小LTC交易单位(取LTC/BTC和LTC/CNY两个市场的最小LTC交易数量的最大值)的某个倍数(比如2倍),则放弃本次套利;
如果欲下单的LTC数量对应的BTC数量( LTC数量乘上系数 ltc_btc_sell1_price)小于最小BTC交易单位(取LTC/BTC和BTC/CNY两个市场的最小BTC交易数量的最大值)的某个倍数(比如2倍),则放弃本次套利。
二、 三角套利策略流程
(1) 初始化:
a) 在BTC/CNY市场放入如下资产:
i. BTC:1个BTC, 最少预留20% (btc_reserve = 20%)
ii. CNY:2万元,最少预留20% (cny_reserve = 20%)
b) 在LTC/CNY市场放入如下资产:
i. LTC:100个LTC,最少预留20% (ltc_reserve = 20%)
ii. CNY:2万元,最少预留20% (cny_reserve = 20%)
c) 在LTC/BTC市场放入如下资产:
i. LTC:100个LTC,最少预留20% (btc_reserve = 20%)
ii. BTC:1个BTC,最少预留20% (ltc_reserve = 20%)
(2) 套利条件:
如果
(ltc_cny_buy_1_price/btc_cny_sell_1_price-ltc_btc_sell_1_price)/ltc_btc_sell_1_price
>btc_cny_slippage+ltc_btc_slippage+ltc_cny_slippage+btc_cny_fee+ltc_cny_fee+ltc_btc_fee
则进行正循环套利:
图:正循环套利(挣CNY)策略示意图
正循环套利的顺序如下:
先去LTC/BTC吃单买入LTC,卖出BTC,然后根据LTC/BTC的成交量,使用多线程,同时在LTC/CNY和BTC/CNY市场进行对冲。LTC/CNY市场吃单卖出LTC,BTC/CNY市场吃单买入BTC。
如果
(ltc_btc_buy_1_price-ltc_cny_sell_1_price/btc_cny_buy_1_price)/ltc_btc_buy_1_price
> btc_cny_slippage+ ltc_btc_slippage+ ltc_cny_slippage+btc_cny_fee+ltc_cny_fee+ltc_btc_fee
则进行逆循环套利:
图:逆循环套利(挣CNY)策略示意图
逆循环套利的顺序如下:
先去LTC/BTC吃单卖出LTC,买入BTC,然后根据LTC/BTC的成交量,使用多线程,同时在LTC/CNY和BTC/CNY市场进行对冲。LTC/CNY市场吃单买入LTC,BTC/CNY市场吃单卖出BTC。
如果不满足以上两个条件,则继续等待套利机会。
(3)账户内划转条件:
BTC/CNY, LTC/CNY, LTC/BTC各个市场的计价货币和基础货币的存量降到最少预留比例(比如20%)或以下,触发账户内划转,划转的流程如下:
1) 撤销LTC/BTC市场中尚未成交的委托
2) 撤销BTC/CNY市场中尚未成交的委托,对委托未成交部分进行市价补单
3) 跟2)并行,撤销LTC/CNY市场中尚未成交的委托,对委托未成交部分进行市价补单
4) 进行账户内划转,划转结果如下:
BTC/CNY市场中的BTC = LTC/BTC市场中的BTC
LTC/CNY市场中的LTC = LTC/BTC市场中的LTC
BTC/CNY市场中的CNY = LTC/CNY市场中的CNY(这个目前是合并在一起的,暂时没问题,如果是ETH,则需要保证ETH账户中的CNY = BTC账户中的CNY)
三、 策略监控和异常处理
我们先定义一个异常的处理方法,称为操作1,具体如下:
操作名:操作1
操作简介:停止LTC/BTC下单,完成LTC/CNY及BTC/CNY的对冲,发报警,停止程序。
操作流程:
a) 第一步:停止在LTC/BTC盘面下单,撤销该盘面未完全成交的委托单;
b) 第二步:对于LTC/CNY及BTC/CNY盘面的未完全成交的委托单,进行轮询等待,超时之后,撤销未成交的部分,并用市价单进行补单,保证完全对冲;
c) 第三步:发出相应的报警邮件
d) 停止策略
再定义一个异常处理方法,称为操作2,具体如下:
操作名:操作2
操作简介:停止LTC/BTC下单,完成LTC/CNY及BTC/CNY的对冲,发报警。
操作流程:
a) 第一步:停止在LTC/BTC盘面下单,撤销该盘面未完全成交的委托单;
b) 第二步:对于LTC/CNY及BTC/CNY盘面的未完全成交的委托单,进行轮询等待,超时之后,撤销未成交的部分,并用市价单进行补单,保证完全对冲;
c) 第三步:发出相应的报警邮件
再定义几个参数,如下:(注意:以下所有资产的总量包含可用部分和冻结部分,包括LTC/BTC市场、LTC/CNY市场以及BTC/CNY市场)
CNY净头寸 =当前CNY总量 – 初始CNY总量
BTC净头寸 =当前BTC总量 – 初始BTC总量
LTC净头寸 =当前LTC总量 – 初始LTC总量
策略的盈亏计算公式 = (当前CNY总量 – 初始CNY总量)+ (当前BTC总量 – 初始BTC总量)* 当前BTC/CNY价格 + (当前LTC总量 – 初始LTC总量)* 当前LTC/CNY价格
CNY头寸偏度 = ABS(BTC/CNY市场中的CNY - LTC/CNY市场中的CNY)/(BTC/CNY市场中的CNY + LTC/CNY市场中的CNY),因为LTC和BTC市场共享统一的CNY,所以本策略暂时不存在CNY头寸偏度这个问题。
BTC头寸偏度 = ABS(BTC/CNY市场中的BTC - LTC/BTC市场中的BTC)/( BTC/CNY市场中的BTC + LTC/BTC市场中的BTC)
LTC头寸偏度 = ABS(LTC/CNY市场中的LTC - LTC/BTC市场中的LTC)/( LTC/CNY市场中的LTC + LTC/BTC市场中的LTC)
需要监控的指标和相应流程如下:
1. 当次盈亏监控:如果策略亏损超过一定额度,进行“操作1”,然后调查亏损原因,明确之后再手动重启策略。
2. 净头寸监控
a) CNY净头寸监控:如果CNY净头寸的绝对值超过一定额度,进行“操作1”,然后调查产生净头寸的原因,明确之后再手动重启策略。
b) BTC净头寸:如果BTC净头寸的绝对值超过一定额度,进行“操作1”,然后调查产生净头寸的原因,明确之后再手动重启策略。
c) LTC净头寸:如果LTC净头寸的绝对值超过一定额度,进行“操作1”,然后调查产生净头寸的原因,明确之后再手动重启策略。
3. 头寸偏度监控
a) CNY头寸偏度监控:因为LTC和BTC市场共享统一的CNY,所以本策略不存在这个问题。
b) BTC头寸偏度监控:如果BTC头寸偏度超过一定幅度,进行“操作1”,然后进行手动头寸调整,使得头寸偏度为0,之后再手动重启策略
c) LTC头寸偏度监控:如果LTC头寸偏度超过一定幅度,进行“操作1”,然后进行手动头寸调整,使得头寸偏度为0,之后再手动重启策略
4. 未成交的对冲单数量监控:如果未成交的对冲单(LTC/CNY市场未成交的委托单数量+BTC/CNY市场未成交的委托单数量之和)数量超过一定额度,进行“操作2”
四、 需要注意的问题
1. LTC/BTC市场的单子是整个套利循环的起点,在LTC/BTC市场中成交的单子,一定要到LTC/CNY和BTC/CNY市场同时进行对冲。LTC/CNY和BTC/CNY市场的对冲单,先尝试以限价单挂出,不成交则逐渐修改价格至可以成交的价位,多次尝试之后(超时)如果仍有未成交部分,则以市价单补单,保证完全对冲。
2. 整个套利过程,为了简化价格转换运算,没有考虑BTC/CNY市场的盘口深度,所以在估计BTC/CNY的对冲成本(btc_cny_slippage)时,需要结合最近BTC/CNY盘口的深度情况进行调整。如果BTC/CNY盘口太薄,则建议设置一个比较大的对冲成本(btc_cny_slippage)。
3. 本文中所有的买一卖一价格,都是指进行了盘口深度合并之后的价格。盘口深度合并的规则是:
a) LTC/BTC市场,按照0.0001的价格进行合并(即一个价格档位对于的比特币为0.0001个,约2元)。买单向下合并,卖单向上合并。用数据表示如下:
合并前深度:
(asks)
0.010413 12
0.010412 20
0.010312 33
0.010112 13
(bids)
0.010109 45
0.009812 22
0.009812 10
0.009712 2
0.009612 30
合并后深度:
(asks)
0.0105 32
0.0104 33
0.0102 13
(bids)
0.0101 45
0.0098 32
0.0097 2
0.0096 30
所以本策略中的买一卖一的价格和数量,是已经包含了未合并之前好几档的深度。这样的合并规则,保证我们在计算套利机会的时候,是偏保守的。
以上就是在有成本的情况下进行三角套利的全过程。代码已上传GitHub。