根据sqrtPriceX96计算当前Tick

本文解释了Uniswap V3协议中如何将sqrtPriceX96转换为tick,以及如何从tick转换回sqrtPriceX96,讨论了相关的数学公式和代码实现,以及如何在Python中进行计算,最后通过练习,帮助读者理解如何在实际的Uniswap V3池中进行这些转换。

在之前的章节中,我们看到协议存储的是价格的平方根而不是价格本身。因此,有必要将 tick 与固定点 Q64.96 格式的价格平方根联系起来。

在本章中,我们将探讨如何在 sqrtPriceX96 和 tick 之间进行转换。

协议存储了 tick 索引

一个 tick 是一个离散的价格,由公式 p(i)=1.0001i 给出,其中 i 称为 tick 索引或简称为 tick。有了 tick 索引,就可以唯一地确定 tick 价格,反之亦然。由于存储 tick 索引 i 比存储 p(i) 占用的位数更少,因此协议存储 tick 索引而不是 tick 价格。

在本书中,我们将交替使用术语 tick (价格)和 tick 索引。在代码库中,名为 tick 的变量始终指 tick 索引 i。

计算 tick 索引,给定 sqrtPriceX96

首先,我们回顾价格平方根与变量 sqrtPriceX96 之间的关系:

(sqrtPriceX96296)=p

因此,价格和 sqrtPriceX96 之间的关系是通过取两边的平方来给出的。

(sqrtPriceX96296)2=p

由于价格和 tick 索引之间的关系是 p=1.0001i,我们有

(sqrtPriceX96296)2=1.0001i

为了根据 sqrtPriceX96 确定 tick 索引 i,我们取上述等式两边的对数。

log⁡((sqrtPriceX96296)2)=log⁡(1.0001i)2log⁡(sqrtPriceX96296)=ilog⁡(1.0001)used thatlog⁡(ab)=blog⁡(a)i=2log⁡(sqrtPriceX96296)log⁡(1.0001)divided both sides by log⁡(1.0001)

对数总是相对于一个底数而言。例如,如果 ba=c,则 logb⁡c=a(log 以 b 为底)。但是,上面等式中的对数可以取任何底数。原因将在本章的最后一节中解释。

tick 索引是一个离散值

实际上,上述公式并不完全正确,原因之一是:sqrtPriceX96 是一个连续值,而 tick 索引 i 是离散的(一个整数)。因此,该值需要向下舍入。

这可以在下面的插图中看到,我们使用了一个可以在我们关于 tick 的文章中找到的工具。请注意,虽然价格不断变化,但该价格对应的 tick 始终是紧随其后的一个。

https://img.learnblockchain.cn/2025/05/07/lower-tick-anim.mp4

因此,tick 的准确公式是:

i=⌊2log⁡(sqrtPriceX96296)log⁡(1.0001)⌋

其中符号 ⌊…⌋ 表示向下舍入,例如,⌊3.14⌋=3。

计算 sqrtPriceX96 给定 tick 索引

要从 tick 索引计算价格的平方根,我们从公式开始

(sqrtPriceX96296)2=1.0001i

然后,取两边的平方根并乘以 296,

sqrtPriceX96296=1.0001isqrtPriceX96=1.0001i⋅296

从代码库中的 tick 到价格以及反之亦然

Solidity 中 tick 和 sqrtPriceX96 之间的转换由 TickMath 库 处理,由于在 Solidity 中实现 log 和平方根的复杂性,将在单独的章节中进行研究。

它包含两个函数:getSqrtRatioAtTickgetTickAtSqrtRatio,它们执行 sqrtPriceX96 和其对应的 tick 索引之间的转换,以及相反的转换。如下所示。

用于在 tick 和价格之间转换的函数

我们在上一节中看到了这些公式的数学原理。在本节中,我们将使用 Python 执行此计算。

getSqrtRatioAtTick 函数

Python 中的 getSqrtRatioAtTick 函数可以写成:

def getSqrtRatioAtTick(i):
    return math.sqrt(1.0001 ** i) * 2**96    

例如,可以使用 getSqrtRatioAtTick(887272) 计算上限价格的 sqrtPriceX96 的值,结果为 1.4614467034780703e+48,这(近似地)对应于 TickMath 库中的 MAX_SQRT_RATIO 常量。

TickMath 中的最大比率常量

使用 Decimal 库

为了获得更准确的结果,我们可以使用 Python 中的 Decimal 库。使用此库的相同公式编码如下,以及 MAX_SQRT_RATIO 的计算值。

import math
from decimal import Decimal, getcontext

getcontext().prec = 50 

def getSqrtRatioAtTick(i):
    base = Decimal("1.0001")
    exponent = Decimal(i)
    sqrt_value = base ** (exponent / 2) 
    multiplier = Decimal(2) ** 96
    return sqrt_value * multiplier

print(int(getSqrtRatioAtTick(887272)))  # 1461446703485210103244672773810124308346321380902

getTickAtSqrtRatio 函数

Python 中的 getTickAtSqrtRatio 函数可以写成:

def getTickAtSqrtRatio(sqrtPriceX96):
    return math.floor(2*math.log(sqrtPriceX96/2**96)/math.log(1.0001))

例如,可以使用 getTickAtSqrtRatio(4295128739) 计算与 sqrtPriceX96 的下限 4295128739 对应的 tick,结果值为 -887272,这是 tick 下限的预期值。

getTickAtSqrtRatio(4295128739) // -887272

改变对数的底数

当我们推导出公式

i=⌊2log⁡(sqrtPriceX96296)log⁡(1.0001)⌋

我们提到对数可以是任何底数。在 Python 中公式的实现中,我们使用了自然对数,但我们也可以使用以 10 为底的对数或任何其他底数,这将产生相同的结果。

原因是与不同底数的对数相关的对数的基本性质,

logb⁡(k)=loga⁡(k)loga⁡(b)

其中 a 和 b 是两个不同的底数,k 是我们要计算的对数的参数。例如,将 log 从自然底数 e 转换为底数 10,我们有

log10⁡(k)=loge⁡(k)loge⁡(10)

关键是除数 loge⁡(10) 仅取决于底数,而不取决于参数。假设我们有一个分数:

log10⁡(x)log10⁡(y)

如果我们要将对数转换为某个任意底数 b,我们将分子和分母都除以 logb⁡(10)。但是,将分数的分子和分母都除以相同的值对最终答案没有影响,因为它会抵消。

让我们通过将这种关系应用于我们的 tick 索引 i 公式并从自然底数转换为底数 10 来明确这一点:

i=⌊2loge⁡(sqrtPriceX96296)loge⁡(1.0001)⌋i=⌊2log10⁡(sqrtPriceX96296)/log10⁡(e)log10⁡(1.0001)/log10⁡(e)⌋from base e to base 10i=⌊2log10⁡(sqrtPriceX96296)/log10⁡(e)log10⁡(1.0001)/log10⁡(e)⌋i=⌊2log10⁡(sqrtPriceX96296)log10⁡(1.0001)⌋

正如我们所看到的,转换因子会抵消,并且计算结果与底数无关。

总结

  • 协议需要在 sqrtPriceX96 和 tick 索引之间进行转换。这可以使用 getSqrtRatioAtTickgetTickAtSqrtRatio 函数来完成,这些函数位于 TickMath 库中。
  • 要从 sqrtPriceX96 转换为 tick 索引,应使用以下公式:

i=⌊2log⁡(sqrtPriceX96296)log⁡(1.0001)⌋

  • 要从 tick 索引转换为 sqrtPriceX96,应使用以下公式:
  1. 0001i⋅296

练习

浏览 Uniswap V3 Pools 查找池地址,然后在区块浏览器中打开该地址。查找公共变量 slot0 并将 tick 转换为 price,反之亦然。

slot0 的 Etherscan 输出

检查你的计算是否接近 Uniswap 提供的值,然后将 sqrtPriceX96 转换为美元。

对以下池执行此操作:

我们稍后将学习为什么合约直接使用来自 slot0sqrtPriceX96(可以给我们价格)和 tick 数据是不安全的,这目前仅用于练习。

  • 原文链接: rareskills.io/post/unisw...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/