价格冲击是你自己造成的,不是市场给你的

冲击、滑点、手续费是三种互相甩锅的成本。怎么分别算出来,以及怎么按这个区别行动。

BoltTx Team··14 min read
solana价格冲击滑点amm交易机器人执行

一笔交易成交得比预期差,然后被记成滑点。其中一部分确实是,一部分是池子手续费,而大头多半是这笔交易自己把价格推动了

★这三种成本原因不同、修法不同,而把它们混在一起,意味着你在修错的那个。★

三种成本

成本 由什么造成 修法
★价格冲击★ ★你自己的规模对上储备★ ★下小一点★
★滑点★ ★报价到执行之间别人在交易★ ★落得更快★
池子手续费 池子的费率 换一个更便宜的场所

★价格冲击是确定性的。★ 给定储备和规模,在你提交之前它就是一个已知量 —— 它不是不确定性,它是算术

★滑点才是不确定的那部分★,而它存在的唯一原因是:你的决策和你的执行之间有时间流逝

大多数机器人配的那个"滑点容忍度",其实在默默吸收这三样。 这能用,直到冲击那部分大到吃掉整个容忍度 —— 然后每一笔交易都开始 revert,而原因看起来像是行情波动

计算冲击

冲击是"你收到的"和"同样储备下一笔无穷小交易能收到的"之间的差:

function priceImpact(amountIn: bigint, reserveIn: bigint, reserveOut: bigint, feeBps: bigint) {
  const inAfterFee = amountIn * (10_000n - feeBps) / 10_000n;

  // ★你实际拿到的。★
  const actualOut = (inAfterFee * reserveOut) / (reserveIn + inAfterFee);

  // ★按当前价格、没有规模效应时你会拿到的。★
  const spotOut = (inAfterFee * reserveOut) / reserveIn;

  return Number(spotOut - actualOut) / Number(spotOut);
}

★注意手续费在两个分支里都套用了。★ 拿一个扣了费的输出去和一个没扣费的现价比,会把池子手续费混进你的冲击数字里 —— 而那正是本文要说的那种混淆。

结果是一个纯粹的规模效应 —— 你相对这个池子太大的代价,手续费单独计算

如果你的冲击计算是对的、交易还是会错过,免费领个 BoltTx key 改一行就能测测提交路径。

从冲击推出滑点

一旦两者分开,容忍度就自然推出来了:

const impact = priceImpact(amountIn, reserveIn, reserveOut, feeBps);

// ★容忍度覆盖的是"在途期间的移动",不是你自己的冲击。★
const tolerance = volatilityBuffer;

const expectedOut = amountOut(amountIn, reserveIn, reserveOut, feeBps);
const minOut = expectedOut * BigInt(Math.floor((1 - tolerance) * 10_000)) / 10_000n;

expectedOut 里已经包含了你的冲击,因为它就是从储备算出来的。★ 在此之上再把冲击加进容忍度,是重复计算 —— 而且会产出一个松到根本不再保护你的最小值。

这防住的那个失败是: 一个因为"这个池子薄"就把容忍度设成 5% 的机器人,不是在补偿冲击,而是在邀请任何抢在它前面的人给它一个差 5% 的成交

冲击是不对称的

同样的名义规模,两个方向的代价不同:

// ★买入:你抽走代币储备。★
const buyImpact  = priceImpact(solIn, reserveSol, reserveToken, fee);

// ★卖出:你抽走 SOL 储备 —— 而在你买入之后,它更薄了。★
const sellImpact = priceImpact(tokenIn, reserveToken, reserveSol, fee);

★一个来回要付两次冲击,而且是在一个被你自己的进场弄差了的池子上。★ 那才是该拿来定规模的数字 —— 而不是只看进场冲击,那是大多数机器人唯一检查的

这个数字会在哪里算错

陈旧的储备。 用好几个 slot 之前的储备算出的冲击,描述的是一个不再存在的池子。★用 getAccountInfoAndContext,让储备和它的 slot 一起到达。★

池子类型不对。 上面的公式是恒定乘积。集中流动性的行为不同,把这套算术套上去会产出一个自信的错误答案。

多跳路由。 冲击是复合的,不是相加的。 每一腿交易的都是上一腿已经推动过的储备。

忽略费率档位。 一个费率更高的池子改变的是输出、不是冲击 —— 把这个差额当成冲击,会让你去拉错的那根杠杆。

把它当筛子用

★最有价值的用法是拒绝交易,而不是给交易定价。★

const impact = priceImpact(size, reserveIn, reserveOut, feeBps);

if (impact > MAX_IMPACT) {
  const smaller = maxSizeForImpact(reserves, MAX_IMPACT);
  return smaller > MIN_SIZE
    ? { action: "resize", size: smaller }      // ★下小一点★
    : { action: "skip" };                      // ★这个池子对你太薄★
}

缩小规模通常比跳过更好,因为冲击增长快于线性 —— 规模减半,冲击减少超过一半,所以一笔在全额规模下不划算的交易,在几分之一规模下可能完全没问题

★对套利机器人来说,这个筛子就是"一个能赚钱的策略"和"一个把优势消耗在自己执行上的策略"之间的差别。★ 机会是按现价算的;成交是按冲击发生的。

上链应该是什么水平

我们投递节点上的真实交易:中位确认 336 毫秒 —— 不到一个 slot。

★冲击在执行那一刻就固定了;而滑点随它之前的每一个 slot 增长。★ 规模控制前者,落块速度控制后者 —— 把它们混淆,意味着你对着正在痛的那个用了错的药。

BoltTx 在这里的位置

我们负责提交。冲击计算和规模控制完全留在你的代码里

提交走我们自建的四区域投递节点,带 SWQoS 路由,不暴露公共 mempool —— 交易在落块之前、传输途中观察不到。这直接减少的是滑点那一部分,因为能在它执行之前对你的意图采取行动的人更少了

你在本地签名。我们不托管资金、不代签、不修改交易内容,包括你算出来的最小输出量。tip 带在交易里、从你自己的钱包链上支付,交易失败时跟着一起 revert —— 这是 Solana 原子交易的机制决定的。只有到达链上的交易才计费。

免费领 API key,没有月费:

const connection = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");

常见问题

Solana swap 的价格冲击是什么? 你的交易收到的,和同样储备下一笔无穷小交易能收到的之间的差。它由你自己的规模造成,不是市场给的。

价格冲击和滑点有什么区别? 冲击是确定性的、由你的规模对上储备造成。滑点是不确定的、由报价到执行之间别人的交易造成。 原因不同,修法不同。

价格冲击怎么算? 从储备算出实际输出,再算出没有规模效应的现价输出,取相对差。两边都要套用池子手续费,免得它污染这个数字。

该把冲击算进滑点容忍度吗? 不该。如果你是从储备算出的预期输出,它里面已经包含冲击了。 再加一次是重复计算,会产出一个不再保护你的最小输出量。

我的成交为什么比报价差? 是冲击、滑点、池子手续费的某种组合。把它们分开,是判断该"下小一点""落快一点"还是"换个场所"的唯一办法。

价格冲击随规模线性增长吗? 不是,在恒定乘积池上快于线性。这就是规模减半能让冲击减少超过一半、以及缩小规模常常胜过跳过的原因。

买和卖的冲击一样吗? 不一样。两个方向抽的是不同的储备,而你的进场让出场那一侧变薄了。 一个来回要付两次冲击,而且是在被你自己弄差了的池子上。

怎么设一个可接受的最大冲击? 为你的策略挑一个容忍度,然后从储备推导出最大规模,而不是直接挑一个规模。之后每个池子都会报出它自己的上限。

池子手续费算价格冲击吗? 不算,它们是两种独立的成本。把手续费混进冲击数字,是最常见的计算错误,而且会让你去拉错的杠杆。

多跳路由的冲击怎么算? 它是复合的而不是相加的,因为每一腿交易的都是上一腿已经推动过的储备。逐跳算完再求和会低估总量。

把交易拆开能减少冲击吗? 在同一个池子、同一个区块内不能,因为每一部分执行时储备都在动。拆到真正不同的池子上有帮助,因为每个吸收更小的一份。

价差明明是正的,我的套利为什么亏钱? 因为价差是按现价算的,而成交是按冲击发生的。两条腿都要付,而在一个薄池子上,它可以完全吃掉这份优势

集中流动性会改变冲击公式吗? 会。流动性在区间里而不是铺满曲线,所以恒定乘积的算术会给出一个自信的错误答案。先确认池子类型。

我的储备数据能有多陈旧? 只能陈旧到你还能承受出错的程度。 把储备连同它的 context slot 一起读,这样你能测量陈旧程度,而不是假设它

冲击太高该跳过还是缩小规模? 先缩小规模。 因为冲击增长快于线性,一笔全额下不划算的交易,在几分之一规模下往往没问题,而跳过是彻底放弃这个机会。

冲击阈值设多少合理? 取决于策略,但有用的纪律是"先有一个阈值、并从它推导规模" —— 而不是等成交之后在盈亏表里才发现冲击。

延伸阅读

返回博客列表