見出し画像

Whirlpool mathematics

Whirlpool (や Uniswap v3) の価格と $${tick}$$ の変換についてのメモです。

なお、Whirlpool の SDK ではこれらの処理をやってくれるヘルパークラスがあるので、実装の詳細を知らずとも変換は可能です。

tick から価格 P

数学的背景

$$
\begin{array}{}
P &=& 1.0001^{tick} \\
\sqrt{P} &=& \sqrt{1.0001^{tick}} \\
&=& \sqrt{1.0001}^{tick} \\
\end{array}
$$

実装

  • get_sqrt_price_positive_tick

  • get_sqrt_price_negative_tick

実装上のキーポイント

べき乗を分解する。

$${tick = 203}$$ の場合を例にする。
なお、203 は 128+64+8+2+1 なので 2 進数では  11001011 となる。

$$
\begin{array}{rcl}
\sqrt{P} &=& \sqrt{1.0001}^{tick} \\
&=& \sqrt{1.0001}^{203} \\
&=& \sqrt{1.0001}^{128+64+8+2+1} \\
&=& \sqrt{1.0001}^{128} \cdot \sqrt{1.0001}^{64}  \cdot \sqrt{1.0001}^{8}  \cdot \sqrt{1.0001}^{2}  \cdot \sqrt{1.0001}^{1} \\
\end{array}
$$

このように分解すると、事前に $${\sqrt{1.0001}^{2^n}}$$ を計算しておけば、あとは掛け算で実装できる。

Whirlpool における $${tick}$$ の範囲は [-443636, 443636]。
443636 は 19 ビットの 1101100010011110100 であるため、事前に計算しておくのは $${\sqrt{1.0001}^{2^{18}}}$$ までで足りる。

この程度の数なら十分ハードコードできる。

なお、マイナス方向の場合も同様に分解する。
$${tick = -203}$$ の場合を例にする。

$$
\begin{array}{rcl}
\sqrt{P} &=& \sqrt{1.0001}^{tick} \\
&=& \sqrt{1.0001}^{-203} \\
&=& \frac{1}{\sqrt{1.0001}^{203}} \\
&=& \frac{1}{\sqrt{1.0001}^{128+64+8+2+1}} \\
&=& \frac{1}{\sqrt{1.0001}^{128}} \cdot \frac{1}{\sqrt{1.0001}^{64}}  \cdot \frac{1}{\sqrt{1.0001}^{8}}  \cdot \frac{1}{\sqrt{1.0001}^{2}}  \cdot \frac{1}{\sqrt{1.0001}^{1}} \\
\end{array}
$$

同様に、事前に $${\frac{1}{\sqrt{1.0001}^{2^n}}}$$ を計算しておけば、あとは掛け算で実装できる。

価格 P から tick

数学的背景

$$
\begin{array}{rcl}
tick&=&\lfloor\log_{1.0001}{P}\rfloor \\
&=&\lfloor\log_{\sqrt{1.0001}}{\sqrt{P}}\rfloor\\
\end{array}
$$

実装

  • tick_index_from_sqrt_price

実装上のキーポイント

2 を底として計算する

下記のように変換する。

$$
\begin{array}{rcl}
tick &=&\lfloor\log_{\sqrt{1.0001}}{\sqrt{P}}\rfloor\\
&=&\lfloor\log_{\sqrt{1.0001}}2 \cdot \log_{2}\sqrt{P} \rfloor\\
\end{array}
$$

$${\log_{\sqrt{1.0001}}2}$$ は定数になるため、あとは $${\log_{2}\sqrt{P}}$$ を計算すればよい。

2 を底とした対数の計算方法はこちらで説明されている。

整数部と小数部を別々に計算する

$${\log_{2}\sqrt{P}}$$ を計算する上で、整数部と小数部を別々に考える。

例えば、$${\log_{2} \sqrt{169}}$$、つまり $${\log_{2} 13}$$ を解こうとすると、$${2^3 \lt 13 \lt 2^4}$$ は自明であるため、解が $${3 + \alpha  (0 \lt \alpha \lt 1)}$$ になることはわかる。

$$
\begin{array}{rcl}
\log_{2} 13 &=&\log_{2} 2^3 \cdot 2^\alpha \\
&=&3 + \log_{2}2^\alpha \\
\end{array}
$$

整数部が 3 とわかったので、あとは小数部である $${\alpha}$$ を求めればよくなった。

$$
\begin{array}{rcl}
\log_{2} 13  &=&3 + \log_{2}2^\alpha \\
\log_{2} 13 - 3 &=& \log_{2}2^\alpha \\
\log_{2} \frac{13}{2^3} &=& \alpha \\
\\
\alpha &=& \log_{2} \frac{13}{2^3} \\
\end{array}
$$

この $${\alpha}$$ の計算ロジックは Wikipedia にも載っているものだが、$${\alpha}$$ を 2 進数で表して、その小数部の各ビットを 1 つずつ解き明かしていると解釈できる。

次の2つの性質を使いながら、値が判明している真数を操作・観察しながら、対数側である $${\alpha}$$ のビットを決定していく流れを示す。

  • 真数に対する2乗が、対数($${\alpha}$$) を2倍にする

  • 対数から1を引くと、真数が 1/2 になる

この結果から、$${\alpha}$$ の2進数表現は 0.1011・・・ となることがわかり、0.6875 (0.5 + 0.125 + 0.0625) 以上であるとわかる。4 ビットではまだ精度が不足しているが、この処理を進めていけば、十分な精度の結果を得ることができる。

この記事が気に入ったらサポートをしてみませんか?