You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Go计算Uniswap V3与SushiSwap的价格冲击?

SushiSwap(Uniswap V2 模型)价格冲击计算

核心逻辑

基于恒定乘积公式x*y=k,模拟交易前后的储备变化,对比交易前后的代币价格差计算冲击,需注意扣除0.3%的交易手续费。

计算步骤

  1. 确定交易方向:比如用token0兑换token1,输入金额为amountIn
  2. 计算扣除手续费后的实际输入金额:adjustedAmountIn = amountIn * 0.997
  3. 推导交易后的储备:
    • 若输入token0:newReserve0 = reserve0 + adjustedAmountIn,newReserve1 = reserve1 - (adjustedAmountIn * reserve1) / newReserve0
    • 若输入token1:newReserve1 = reserve1 + adjustedAmountIn,newReserve0 = reserve0 - (adjustedAmountIn * reserve0) / newReserve1
  4. 计算价格冲击:
    • 原价格:priceBefore = 目标代币储备 / 输入代币储备
    • 交易后价格:priceAfter = 新目标代币储备 / 新输入代币储备
    • 冲击值:((priceAfter - priceBefore) / priceBefore) * 100%

Go 代码示例

package main

import "fmt"

// calculateSushiSwapPriceImpact 计算SushiSwap的价格冲击
// reserve0/reserve1: 池中的代币储备
// amountIn: 输入的代币数量(已转换为代币单位,比如USDC直接输100代表100个)
// isToken0In: 是否输入的是token0
func calculateSushiSwapPriceImpact(reserve0, reserve1, amountIn float64, isToken0In bool) float64 {
	const feeRate = 0.997 // 0.3%手续费
	var priceBefore, priceAfter float64

	if isToken0In {
		priceBefore = reserve1 / reserve0
		adjustedAmount := amountIn * feeRate
		newRes0 := reserve0 + adjustedAmount
		newRes1 := reserve1 - (adjustedAmount * reserve1) / newRes0
		priceAfter = newRes1 / newRes0
	} else {
		priceBefore = reserve0 / reserve1
		adjustedAmount := amountIn * feeRate
		newRes1 := reserve1 + adjustedAmount
		newRes0 := reserve0 - (adjustedAmount * reserve0) / newRes1
		priceAfter = newRes0 / newRes1
	}

	return ((priceAfter - priceBefore) / priceBefore) * 100
}

func main() {
	// 示例:USDC/WETH池,reserve0=10000 USDC,reserve1=5 WETH,输入100 USDC兑换WETH
	impact := calculateSushiSwapPriceImpact(10000, 5, 100, true)
	fmt.Printf("价格冲击: %.2f%%\n", impact)
}

Uniswap V3 价格冲击计算

Uniswap V3采用集中流动性模型,定价基于sqrtPriceX96(即sqrt(token1/token0)乘以2^96的整数编码值),流动性liquidity代表当前活跃价格区间内的流动性总量。你之前的错误主要是忽略了编码单位转换,以及误用了V2的恒定乘积模型。

问题1:从sqrtPrice和liquidity推导代币储备

核心公式

假设当前价格P = token1/token0,sqrtP = sqrt(P),则:

  • token0储备:reserve0 = liquidity / sqrtP
  • token1储备:reserve1 = liquidity * sqrtP

关键注意事项

  1. sqrtPriceX96需要先转换为实际的sqrtP:sqrtP = sqrtPriceX96 / 2^96
  2. 需处理代币小数位数,将计算结果转换为人类可读的代币单位(比如从wei转换为USDC的6位小数单位)

Go 代码示例(推导储备)

package main

import (
	"fmt"
	"math/big"
)

// calculateUniswapV3Reserves 从sqrtPriceX96和liquidity计算代币储备
// sqrtPriceX96: API返回的sqrtPrice(X96编码)
// liquidity: API返回的流动性值
// decimals0/decimals1: 对应代币的小数位数
func calculateUniswapV3Reserves(sqrtPriceX96, liquidity *big.Int, decimals0, decimals1 uint8) (*big.Float, *big.Float) {
	pow96 := new(big.Int).Lsh(big.NewInt(1), 96)
	// 转换sqrtPriceX96为实际的sqrtP
	sqrtP := new(big.Float).Quo(new(big.Float).SetInt(sqrtPriceX96), new(big.Float).SetInt(pow96))
	L := new(big.Float).SetInt(liquidity)

	// 计算reserve0和reserve1(wei单位)
	reserve0Wei := new(big.Float).Quo(L, sqrtP)
	reserve1Wei := new(big.Float).Mul(L, sqrtP)

	// 转换为代币单位
	div0 := new(big.Float).SetFloat64(float64(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals0)), nil)))
	div1 := new(big.Float).SetFloat64(float64(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals1)), nil)))
	reserve0 := new(big.Float).Quo(reserve0Wei, div0)
	reserve1 := new(big.Float).Quo(reserve1Wei, div1)

	return reserve0, reserve1
}

func main() {
	// 示例:WETH/USDC池,sqrtPriceX96对应价格约1800 USDC/WETH
	sqrtPriceX96, _ := new(big.Int).SetString("1461446703485210103287273052203988822378723970342", 10)
	liquidity := big.NewInt(1000000000000000000) // 1e18流动性

	res0, res1 := calculateUniswapV3Reserves(sqrtPriceX96, liquidity, 6, 18)
	fmt.Printf("Reserve0 (USDC): %.2f\n", res0)
	fmt.Printf("Reserve1 (WETH): %.6f\n", res1)
}

问题2:计算Uniswap V3的价格冲击

核心逻辑

模拟交易对sqrtP的影响,推导交易后的价格,再计算冲击值,需使用高精度整数运算避免精度丢失。

计算步骤

  1. 扣除手续费后的实际输入金额:adjustedAmountIn = amountIn * 手续费率(比如0.3%手续费用0.997)
  2. 根据交易方向计算新的sqrtP:
    • 输入token0:newSqrtP = sqrtP + (adjustedAmountIn * sqrtP²) / liquidity
    • 输入token1:newSqrtP = sqrtP - adjustedAmountIn / (liquidity * sqrtP)
  3. 计算交易前后的价格:priceBefore = sqrtP²,priceAfter = newSqrtP²
  4. 价格冲击:((priceAfter - priceBefore) / priceBefore) * 100%

Go 代码示例(计算价格冲击)

package main

import (
	"fmt"
	"math/big"
)

const feeRate03 = 0.997 // 0.3%手续费

// calculateUniswapV3PriceImpact 计算Uniswap V3的价格冲击
// amountIn: 输入的代币金额(wei单位)
func calculateUniswapV3PriceImpact(sqrtPriceX96, liquidity, amountIn *big.Int, isToken0In bool, decimals0, decimals1 uint8) float64 {
	pow96 := new(big.Int).Lsh(big.NewInt(1), 96)
	sqrtP := new(big.Float).Quo(new(big.Float).SetInt(sqrtPriceX96), new(big.Float).SetInt(pow96))
	L := new(big.Float).SetInt(liquidity)

	// 处理手续费
	adjustedAmount := new(big.Float).Mul(new(big.Float).SetInt(amountIn), new(big.Float).SetFloat64(feeRate03))
	priceBefore := new(big.Float).Mul(sqrtP, sqrtP)
	var newSqrtP *big.Float

	if isToken0In {
		sqrtPSq := new(big.Float).Mul(sqrtP, sqrtP)
		deltaSqrtP := new(big.Float).Mul(new(big.Float).Mul(adjustedAmount, sqrtPSq), new(big.Float).Quo(big.NewFloat(1), L))
		newSqrtP = new(big.Float).Add(sqrtP, deltaSqrtP)
	} else {
		denominator := new(big.Float).Mul(L, sqrtP)
		deltaSqrtP := new(big.Float).Mul(new(big.Float).Quo(adjustedAmount, denominator), big.NewFloat(-1))
		newSqrtP = new(big.Float).Add(sqrtP, deltaSqrtP)
	}

	priceAfter := new(big.Float).Mul(newSqrtP, newSqrtP)
	delta := new(big.Float).Sub(priceAfter, priceBefore)
	impact := new(big.Float).Mul(new(big.Float).Quo(delta, priceBefore), big.NewFloat(100))

	impactFloat, _ := impact.Float64()
	return impactFloat
}

func main() {
	sqrtPriceX96, _ := new(big.Int).SetString("1461446703485210103287273052203988822378723970342", 10)
	liquidity := big.NewInt(1000000000000000000)
	amountIn := big.NewInt(100000000) // 100 USDC(wei单位,6位小数)

	impact := calculateUniswapV3PriceImpact(sqrtPriceX96, liquidity, amountIn, true, 6, 18)
	fmt.Printf("Uniswap V3价格冲击: %.4f%%\n", impact)
}

内容的提问来源于stack exchange,提问作者Bongodev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 11:07:05