Author Topic: 【升级投票】 BSIP35 挂单撮合细节改进(整除问题)  (Read 7563 times)

0 Members and 1 Guest are viewing this topic.

Offline abit

  • Committee member
  • Hero Member
  • *
  • Posts: 4664
    • View Profile
    • Abit's Hive Blog
  • BitShares: abit
  • GitHub: abitmore
2018年3月1日更新:已发起 worker 方式的投票,请在钱包内参与。

----原文----

英文链接在这里 https://github.com/bitshares/bsips/blob/bsip35/bsip-0035.md ,希望有人一起严肃讨论下。
讨论链接是 https://github.com/bitshares/bsips/pull/59

这个 BSIP 目的是缓解挂单撮合算法中的整除问题。基于目前设计,只能缓解,并不能完全解决。

什么是整除问题呢?举个例子。

假设 BTS 最小单位是 1, CNY 最小单位是 0.01 。

1. 首先, A 下单按 2.001 元价格卖 10 个 BTS,理想情况下他可以得到 2.005*10 = 20.01 元,符合最小单位要求。

2. 然后, B 下单按 2.1 价格买 7 个 BTS。 这两个单 到底是成交呢,还是不成交呢?如果成交,按什么价成交?

  你可能有答案了: 按2.001成交不满足最小单位需求,那么可以把价格向上取整,按 2.01成交,两个人都不亏。

  成交完,A的单子还剩3个BTS,价格还是2.001

3. 然后, C 下单按 2.002 每个,买 5 个 BTS。理想情况下他会付出10.01CNY得到5个BTS,符合最小单位要求。

  因为价格比A单高,所以理论上应该成交。但是C付多少CNY呢?

  按A的要求,6CNY太少(6/3=2<2.001);
  按C的要求,6.01CNY太多(6.01/3=2.003>2.002),特别是,付完6.01后,他只剩4CNY了,不够按2.002的价继续买2个BTS。

这个例子还比较简单,实际系统里有更复杂的情况,并且有些数额也很大,需要重视。
比如 BTTWY 资产一聪值几十块,整除一下出入就是几十块;水滴资本上万CNY一个,整除一下,几千块就没了。

针对上面的情况,有这么几个处理思路:

思路一:成交,具体价格照顾其中一方利益。
  优点是成交量大,实现不难;
  缺点是没被照顾的一方会不爽。

思路二:只成交能完全匹配的,不能完全匹配就挂着不成交,允许盘面上有买卖单价格重合。
  优点是看起来没人会不爽,因为能成交的都是满足了条件的;
  缺点是实际上会很不爽,因为价格重合的盘面很难看,一般交易者很难知道怎么样去完全满足条件,成交量会低;因为规则复杂,能完全成交的单子必定价格不会好;并且实现复杂。

思路三:取消其中一个单子,这样盘面上不会出现价格重合。
  优点是盘面清楚,并且能成交的必然满足了双方条件。
  缺点是交易者仍然很难知道怎么样去满足成交条件,下单失败率会很高,并且下单后会被取消,体验差,成交量会低;预计容易出现恶意攻击导致别人单子取消掉的情况。

思路四:下单价格必须保证整除
  优点:价格已经能整除,那么就没有整除问题了
  缺点:几千个资产可以两两交易,还可以翻转交易方向,要保证都能整除,还没有具体方案;强制整除必定要舍弃一些灵活性,值不值得还不一定;至于方案出来后的开发工作量,现在还都不用谈。
      说白了,这个思路,现在做不出来。谁想往这个方向推的,拿出详细方案来。


实际上,目前 BTS 系统里采用的是 1+3 的混合方案。

1. 成交时照顾大单。
  以普通限价单为例,下单时,要符合最小单位要求,单子包含的卖出金额和期望买入的数额必然都是整数。如果一个小单是完整的,那么匹配后,必然可以得到一个完整的数额(作为maker),没有整除吃亏的问题,甚至会得到更多(作为taker)。出现整除问题,必然是因为这个单子部分成交过了,也就是说至少和另一个小单匹配过了,也就是说,受到过照顾了。那么,即使最后一次匹配不被照顾,总体不亏。
  同时,照顾大单,那么大单部分成交后剩下的金额不会有亏空,利于后面继续撮合成交。

  上面例子里,A和B匹配时,因为A先挂单,所以价格按A的来,所以成交金额是 2.001*7=14.007;因为最小单位是0.01,而A单子大,所以照顾A,最优方案应该向上取整为14.01,精确成交价为 2.0014。

  A和C匹配时,还是按A的价格成交,成交金额是 2.001*3=6.003,因为C单子大,所以照顾C,也就是说,向下取整得到 6.00 ,A会获得6CNY。虽然看起来这次匹配亏了点,但从整体看,前面7BTS已经卖出14.01,14.01+6=20.01,和他预期的一样,总体是不亏的。

3. 如果一个单子小到匹配后会付出一些,但什么都得不到,也就是说出现 somthing-for-nothing 问题,那么就不成交,而是取消这个单子。
  上面说了,完整单是不会有整除问题,不会什么都得不到。不完整单一定是以前受过照顾了,那么,最后剩的一点卖不出最小单位,说明之前获得的已经足够了,取消也不会亏,剩下的都是赚的。
  这个主要解决的是感受问题,看到成交单里有付出N得到0总是很不爽的,这个做法是为了避免这种不爽。

所以,这样的方案兼顾了灵活性、最大成交量、一定程度上的公平。


那么,这个方案还有什么问题呢?

实际上,方向是不错的,但还有些小问题。

第一,拿前面A和B的匹配来说,现在系统并不是按照最优解来的。

这里先普及一个知识:现在系统里所有的单子都是按卖单来实现的,钱包里挂买单,实际是反向挂一个卖单。
那么,卖单和买单有什么区别呢?区别在于对超额的处理。

拿上面的B的例子,用2.1每个,买7个BTS,
* 如果是买单,那么含义是:最多买7个BTS(第一条件),最多付出2.1*7=14.7CNY(第二条件),如果买够了7个BTS,就停止(第三条件)。
* 如果是卖单,那么含义是:最多付出14.7CNY(第一条件),最少换7个BTS(第二条件),如果能换更多BTS,就换更多(第三条件)。

所以,实际上B是挂了个卖出14.7CNY的单。当和A成交时,按A的价格成交,应该换 14.7/2.001=7.3个BTS,由于A单子大,所以照顾A,把这7.3个BTS向下取整成了7个BTS,B实际付出14.7,精确成交价 2.1 。

呵呵,想不到吧?

BSIP 35 方案的其中一条,就是解决这个问题,按最优解来,也就是最小亏损原则。

那么,怎么得出最优解呢?做法就是在把收到的 7.3 BTS 向下取整成 7 后,反向算出应该付的 CNY 金额 2.001*7=14.007 再向上取整得出 14.01,剩下的0.69因为买不到1个BTS,就退给B,成交完成。这样可以保证A还是被照顾,但B不亏太多。

归纳成规则就是:按先下的单的价格成交,把小单收到的金额向下取整,再把小单应该付出的金额向上取整,多余的退还。


第二,虽然系统有取消极小单的设计,但现在有个BUG,导致某些情况下极小单并不会被取消,而是会送掉。

所以 BSIP 35 里还要修这个BUG。


第三,前面的例子是限价单。那么爆仓单怎么办?爆仓单如果很小,应该怎么取消?

答案是,爆仓单不能取消。

爆仓单,意味着借钱要还。爆仓单极小,意味着付不到 1 个BTS就够还借的所有债了(这里仍然假设BTS最小单位是1)。但是,欠钱就是欠钱,别想赖账,别想别人替你还、而自己什么都不付出。所以至少付 1 BTS。爆仓单还在,没有黑天鹅,说明抵押还在,那么 1 BTS 应该是付得起的。付完,平仓,不会留下什么问题。

也就是说,爆仓单的最后零头,应该是向上取整的来成交的。但其他部分,还是按照照顾大单+最小亏损的原则来。


第四,强清单怎么处理?

一部分答案是:极小的强清单也取消;强清单和债仓匹配时,也按照顾大单+最小亏损的原则来,债仓最后零头也是要向上取整。

需要考虑的一个情况是,强清有每小时的总量限制,因为这个限制,单次执行的强清大单会变成小单、甚至极小单。

处理办法是,仍然按照照顾大单+最小亏损的原则,但是,要识别出是真正的极小单、还是限制导致的临时极小单,
* 真正的极小单,取消
* 临时的极小单,留着等下次匹配

顺便说下,强清的代码逻辑本来就比较复杂,现在更复杂,改起来要费点功夫。


第五,出现黑天鹅,进行全局清算时的处理

参照爆仓,债仓别想赖账,一律按向上取整处理。

(现在系统里是向下取整,理论上会出现不需要还债的情况发生)


第六,黑天鹅后的强清

这种强清单,相对于全局抵押池来说,都是小单,所以属于不被照顾的。

但是要按最小损失原则处理,包含拒绝极小单。(现在系统里没有这个处理)


【差不多写完了,想到再补充】
« Last Edit: March 01, 2018, 04:40:55 pm by abit »
BitShares committee member: abit
BitShares witness: in.abit