指定买入还是指定卖出:两种兑换订单的失败形态与成本归属 图 1
指定买入还是指定卖出:两种兑换订单的失败形态与成本归属 · 图 1

还有一组容易混淆的参数值得单独说清楚:不少界面在两种订单下都显示同一个「滑点容忍度」,但合约里真正生效的是两个不同的边界值——指定买入时是最小所得,指定卖出时是最大付出。从同一个百分比推导这两个边界,路由要做的换算并不相同:前者顺着当前报价向前推,后者要沿曲线反向解一个近似值,再叠上多跳路径的误差。这就是为什么同一笔单在同样滑点设置下,卖出方向的失败率经常高于买入方向——不是市场偏心眼,而是保护边界本身的构造更粗糙。遇到反复失败,先切换到相反口径试算一次,看失败落在哪一端,比盲目放大滑点更能定位问题,也更少给抢跑者送礼。

同一笔兑换需求,路由合约其实接受两种截然不同的表达方式:一种叫指定买入,我确定投入多少,接住市场推走价格之后的剩余;另一种叫指定卖出,我确定拿回多少,倒推自己最多要付出多少。界面上它们常常都缩在一个兑换框里,只靠一个方向箭头区分,但两种订单的失败形态、成本归属和对流动性的要求完全不同,混用是链上执行亏钱的常见起点。 先看计算方向。指定买入的链路很短:把投入量顺着池子曲线推演过去,算出预期产出,再按你的最小所得参数设一条下限,实际产出低于下限就整笔回滚。指定卖出的链路是反的:先定产出,合约要在曲线上解出需要消耗多少输入——而曲线的非线性意味着解对价格影响极度敏感,越是薄池、越是接近池子深度极限,倒推出来的输入量越像坐过山车,市场刚动一小格,你的「最多付出」可能已经不够覆盖。 失败形态因此不同。指定买入的失败通常是「到手少于我允许的底线」,语义清晰,价格被推太远就不做;指定卖出的失败则常常表现为「要的产出凑不齐」,在撮合型路由里,有的实现会把缺口部分成交、把余量退回,有的实现直接全部回滚,这两种行为对用户是两回事——前者会留下一个你计划外的部分仓位,后者是干净的不做。执行前翻一下所用路由与聚合器的文档,确认它对部分成交的处理,这一步多数人省略,但恰好是差错的来源。 成本归属的差别更微妙。指定买入下,价格影响直接吃进你的到手数量,你看到的每一分损耗都对应自己推动市场的那一下;指定卖出下,同样的市场冲击被翻译成「我为什么多付了这么多本金」,损耗藏在投入端,页面如果只强调你要的那个数,容易让人忽略自己实际按了多大的单。两种订单都需要滑点保护,只是保护参数的含义换了位置:指定买入设的是产出下限,指定卖出设的是投入上限,参数太松,都会把保护让给抢跑者。 选择逻辑可以按目标句式来定。如果你的真实目标是「花掉这笔预算」,比如拿固定金额去凑一个策略的入场门槛,用指定买入,让产出随行情浮动;如果目标是「凑出这笔数量」,比如还款需要精确的若干枚稳定币,用指定卖出,接受付出端的不确定性,并把投入上限留够余量。两头都要精确的时候,正确做法不是找一个神奇参数,而是拆单:先指定卖出凑出还款额,剩余仓位再走指定买入。 最后提醒两类连环坑。一是重复提交:指定卖出的单子在流动性不足时失败率高,重试前务必确认上一笔是回滚还是部分成交,链上余额对账之后再重发,否则很容易出现「缺的数量被两笔单凑超」。二是跨池拆单时,指定卖出在多跳路由里的解算精度低于单池场景,不同跳数、不同路径给出的倒推值可以互相矛盾,出现这种分歧本身就说明该笔单已经接近市场深度的舒适区边界,此时更该拆单或改口径。本文只讨论机制与执行纪律,不构成投资建议。