这篇文章带大家过一遍DeFi里常见的自动做市商模型。
视频版本可以看这里。ppt内容可以看这里。Mirror上会持续分享一下crypto scientist & analyst 相关的内容,我的mirror主页,我的twitter链接,BuidlerDAO链接,欢迎大家关注。
下面是全文内容。
此文从无常损失和滑点两个方面,分析 Uniswap 和 Curve (主流自动做市商) 稳定币做市曲线。
滑点有2种定义。本文采用第一种定义方法,反映交易者成交的真实平均损失。(!!视频里用的第二种定义方式,因为觉得成交后的当时的价格作为市场价格会更有参考意义吧!!)
(成交平均价格-初始价格)/ 初始价格
(成交后价格-初始价格)/ 初始价格
无常损失定义:
有两种选项
参加流动性挖矿 ==> w10(参与挖矿的资产市值)
持有资产,不参加流动性挖矿 ==> W11(不参与挖矿的资产市值)
无常损失 = (w10 - w11) / w11
选择什么样的做市曲线,这是一个滑点(交易者)和无常损失(流动性提供者)的权衡利弊。就稳定币而言,我们追求更低的滑点,且绝大多数情况下价格会在1附近波动。Uniswap v3 和 Curve 曲线会是更好的选择,因为他们相当于加个杠杆的uniswap v1/v2 曲线,同样的成交量可以带来更低的滑点。而Uniswap v3 和 Curve 曲线可以通过调整参数(价格区间和A值)达到相似的效果。就现在市场而言(P=[0.9986, 1.0014], A=5000),Curve 能够在价格在1附近提供更好的滑点,而无常损失和Uniswap v3 基本一致。假设稳定币价格不会脱钩,Curve 会是更好的选择。
假设我们从价格为1的点开始做交易
相同的成交量,Curve上的滑点低于Uniswap v1/v2。如果我们单次交易池子里一个币对的99.9999%存量,Curve上的滑点也低于Uniswap v1/v2。对交易者来说,Curve 确实会带来更好的用户体验。
Uniswap v3 采用了设置区间的方式来放大流动性。在区间范围内,Uniswap v3上的滑点始终低于Uniswap v1/v2。但只要超出区间,Uniswap v3交易对就失去了流动性,无法交易。
Uniswap v3的价格区间的宽窄就类似于Curve曲线中A值带来的杠杆。Uniswap v3所对应的滑点和我们想要的成交数量和资产效率乘数是线性相关的。Curve曲线会随着A值的变大,滑点由线性变得更弯曲。不同的价格区间和不同的A值会带来不同的滑点:
Uniswap v3: [0.8, 1.25]; Curve A =2 (图1)==> Uniswap v3 滑点低
Uniswap v3: [0.8, 1.25]; Curve A =8 (图2)==> 成交量比较小,Curve 滑点低;成交量比较大,Uniswap v3 滑点低
Uniswap v3: [0.8, 1.25]; Curve A =50 (图3)==> 成交量比较小,Curve 滑点低;成交量比较大,Uniswap v3 滑点低
Uniswap v3: [0.9986, 1.0014]; Curve A = 5000【现在市场情况】 (图4)==> 成交量比较小,Curve 滑点低;成交量比较大,Uniswap v3 滑点低。绝大多数情况,同样成交量,Curve 滑点更低。
就现在市场而言 (图4),成交量较小时,Curve 滑点 < Uniswap v3 < Uniswap v1/v2。如果出现出现巨额成交量(超90%)或者池子内一个币的数量偏移90%以上或者严重脱钩(稳定币价格远离1),Uniswap v3 滑点 < Curve < Uniswap v1/v2
此处做了两个重要假设:
池子里只有两个币对(A, B)
A和B的初始数量为1:1
结论
同样成交量下,Curve滑点比uniswap v1/v2更低,但是在同样价格变化下,Curve无常损失更大。随着A值增大,Curve滑点越来越低,无常损失也越来越大(图5)。
为达到和uniswap一样的价格,Curve池需要更多的成交量。假设P0=1
A = 1时,一次性交易池内99%的一个币,价格变化99.3%
A = 100时,一次性交易池内99%的一个币,价格变化84.8%
A = 1000时,一次性交易池内99%的一个币,价格变化38%
==> 因为需要更多的成交量,Curve 很难出现和Uniswap同样的价格。但是假设没有无风险套利机会,Curve 和Uniswap V1/v2 上 是同样的价格,Curve 无常损失更大。
同样成交量下,Uniswap v3滑点比uniswap v1/v2更低,但是同样价格变化下,Uniswap v3无常损失更大。随着价格区间变小,Uniswap v3滑点越来越低,无常损失也越来越大(图6)。
同样是加了杠杆的Uniswap v1/v2仓位, Uniswap v3和Curve 有什么区别呢?
固定Uniswap v3价格区间为[0.8, 1.25], 我们变化 Curve 的A值,我们可以看到,Uniswap v3 的无常损失曲线是在Curve[A =10] 和Curve[A =100] 之间的。也就是说,通过变化A值,Uniswap v3 和 Curve 的无常损失可以达到类似效果。(图7)
Uniswap v3: [0.9986, 1.0014]; Curve A = 5000【现在市场情况】。就现在市场而言,同样价格变化,Curve 和 Uniswap v3 的无常损失基本一致。(图8)
详细python实现见此:python
详细excel实现见此:excel
以下是公式推导
x * y = k = L^2
其中x,y分别代表代币x和y的数量。因为k>0,可以把它定义为L^2
y = L^2 / x ==> dy = - L^2 / x^2 dx ==>
P = - dy / dx = - (- L^2 / x^2 dx) / dx = L^2 / x^2 = y / x
x = L / sqrt(P)
y = L * sqrt(P)
假设流动池里的币对从(x1,y1) 变化到(x2,y2),而价格从p1变化到p2
w10: wealth at time t1 if participate as UNISWAP LP at time t0
w11: wealth at time t1 if hold half asset x and half asset y at time t0
p(t1): price for x at time t1
p(t0): price for x at time t0
Assume r = p(t1) / p(t0)
!!! all the wealth are denominated in y.
w10 = p(t1) * x1 + y1
= p(t1) * L / sqrt(p(t1)) + y1
= L * sqrt(p(t1)) + y1
= 2 * L * sqrt(p(t1))
w11 = p(t1) * x0 + y0 【the quantities remain the same】
= p(t1) * L / sqrt(p(t0)) + y0
= r * P(t0) * L / sqrt(p(t0)) + y0
= r * sqrt(p(t0)) * L + sqrt(p(t0)) * L
= (1 + r) * sqrt(p(t0)) * L
IL = w10 / w11 - 1
= 2 * L * sqrt(p(t1)) / ((1 + r) * sqrt(p(t0)) * L) - 1
= 2 * sqrt(p(t1)) / ((1 + r) * sqrt(p(t0))) - 1
= 2 * sqrt(r) / (1 + r) - 1
what's new:
Pa: low range for x
Pb: up range for x
Pc: current price for x
Pa < Pc < Pb
x_v: virtual reserve for x
y_v: virtual reserve for y
L: virtual liquidity
(x + L / sqrt(Pb)) * (y + L * sqrt(Pa)) = L^2
x_v * y_v = L^2
x_v = x + L / sqrt(Pb)
y_v = y + L * sqrt(Pa)
Pc = - dy / dx = y_v / x_v
x_v = L / sqrt(Pc)
y_v = L * sqrt(Pc)
x = x_v - L / sqrt(Pb)
= L / sqrt(Pc) - L / sqrt(Pb)
y = y_v - L * sqrt(Pa)
= L * sqrt(Pc) - L * sqrt(Pa)
w10: wealth at time t1 if participate as UNISWAP LP at time t0
w11: wealth at time t1 if hold half asset x and half asset y at time t0
Assume r = p(x1) / p(x0)
假设V3只有一个流动区间
V2滑点 = 资本效率乘数 * V3滑点
区间越小, V3滑点越小
实际上,Uniswap v3 是无数个流动性区间累加起来的。每个tick之间对应其单独的流动性,只有这个tick对应的流动性被耗尽,才会进入下一个区间继续寻找流动性。
Curve 是 恒定乘积做市 和 恒定和做市的结合。当 A 取值接近于0时,Curve 曲线 = Uniswap v1/v2 曲线;当 A 取值接近于无穷时,Curve 曲线 = 恒定和做市曲线。A 越大,Curve 曲线越向恒定和做市曲线倾斜。
A ==> 扩增参数(amplification parameter)
D ==> 不变量参数 (StableSwap invariant)
其中,Ann = An^n
假设我们手上有 xi,想去池子换成 xj (=y)。
通过上图的变化,再加上一些简化,我们就可以得到
这个问题就变为,在满足f(y)=0的情况下,求解y。这是一元二次方程,可以直接用求根公式,但Curve.fi 用的牛顿迭代法(可能是Solidity没有根号?)。
由于f’(y) = 2y + (b-D),我们就可以得出下图的迭代公式了
和计算置换量类似的方法,我们假设x,y不变,对做市曲线求解D。
这里的S = sum(xi)。
其中 Dp 如下图
同样用牛顿迭代法,求解D「注:当n=2,此方程有闭式解;当n>2,使用牛顿迭代法」
现在假设n=2(池子里只有两个币对),x和y
已知x,y求D,这是一个三元方程, 可以通过卡尔达诺公式(Cardano Formula)求解
其中
值得注意的是,假设不添加或删除流动性,D是恒定的。x的变化只会带来y的变化。
已知n=2,n^n =4, 带入之前的置换公式,可以得到
同理,对于y来说,这是一个一元二次方程,可以用求根公式求解。
其中a, b, c 分别为:
我们知道
对等式两边求导得到
即可得到y’的公式
我们知道价格等于边际变化量之比,即p_x = -y’ = -dy / dx。通过上述公式,我们就可以得到置换后价格。
已知 p_x = - y’ = g(x,y),对任意(x,y),我们都可以求到其对应的价格。也可以求到平均价格。再利用滑点定义【(成交平均价格-初始价格)/ 初始价格】,即可以求出滑点。
已知做市曲线f(x,y) = 0 和 p_x = - y’ = g(x,y),两个方程求解两个未知数(x,y),我们就可以求到 x,y 分别关于 D和 p_x 的函数。然后再通过无常损失定义【(w10 - w11) / w11】,即可以求出无常损失。
首先找到 y = f(p,x),如下图。
然后我们还知道 y = f(x),所以通过y = f(x) = f(p,x),我们就可以求解 x = f(p) 。这是一个一元四次方程,不太容易解出来,就没继续了。
**此处考虑另外一种方法画出无常损失曲线。**首先我们假设池子里的初始币对(x,y)数量为1:1,那么对于每个给定的y的数量变化,我都可以得到对应x的数量变化,从而计算得到变化后的价格。已知了初始价格,初始数量,新价格和新数量,我们就可以通过无常损失定义,计算出其无常损失了。为了画出,我们就需要一个y的数量变化的列表【dy= [-99, -98, -97, ……, 99]】,然后计算出当前价格,再计算出无常损失。我们就可以得到一个当前价格和无常损失的一一对应关系列表。即可以画出价格对应的无常损失的曲线。
详细python实现见此:python
详细excel实现见此:excel
!!!在推导Uniswap无常损失时,我们是没有限制初始币对数量的。它的机制,在任何时刻,两个币对的价值都是1:1。所以不管当前池子里数量是什么,我们都可以通过公式直接得出无常损失。而在推导Curve无常损失时,我们假设了初始币对数量为1:1。我们通过初始币对数量求到D=x+y=2x=2y(如果不添加或删除流动性,D不变),再通过成交量就可以求到无常损失。 如果初始币对数量不是1:1,那么同样的价格变化(与1:1的初始状态相比),对应的无常损失会不一样。
Uniswap v1 example: https://hackmd.io/@HaydenAdams/HJ9jLsfTz?type=view#🦄-Uniswap-Whitepaper
Uniswap V2 白皮书:https://uniswap.org/whitepaper.pdf
Uniswap V3 白皮书:https://uniswap.org/whitepaper-v3.pdf
Curve v1 白皮书:https://curve.fi/files/stableswap-paper.pdf
Curve v1 详解:https://alvarofeito.com/articles/curve/