> ## Documentation Index
> Fetch the complete documentation index at: https://docs.raydium.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 集約型流動性の数学

> sqrt価格表現、流動性から金額への公式、シングルティック・マルチティックスワップステップ、フィー成長の会計処理 — Raydium CLMMの背後にある数学。

<Info>
  **このページは AI による自動翻訳です。すべての内容は英語版を正とします。**

  [英語版を表示 →](/algorithms/clmm-math)
</Info>

## sqrtを使う理由

Uniswap-v3ファミリーのCLMMは価格をその平方根として表現し、固定小数点の`Q64.64`に格納します：

```
sqrt_price_x64 = floor(sqrt(price) · 2^64)
```

3つの理由があります：

1. **線形流動性の数学。** 価格範囲内のトークン0またはトークン1の量は、`price`の関数ではなく`sqrt_price`の線形関数であることがわかります。`sqrt_price`を格納すると、スワップステップは平方根を計算することなく、これらの線形公式を評価できます。
2. **オーバーフロー制御。** `sqrt_price · L`は合理的なパラメータすべてで`u256`に収まります。`price · L`ははるかに早くオーバーフローする可能性があります。
3. **ティック数学は均一です。** ティックは`1.0001^i`として定義されているため、`sqrt(price) = 1.00005^i`もまた1.00005の正確なべき乗ラダーです。各ティック交差は`sqrt_price_x64`空間の小さな乗算に変わります。

価格とsqrt価格は一対一です。変換は`price = (sqrt_price_x64 / 2^64)^2`です。

## ティックラティス

価格はグリッド上に離散化されます：

```
price(tick_i) = 1.0001^i
```

`tick_i`は`i32`です。アクティブな範囲は`[MIN_TICK, MAX_TICK] = [−443636, 443636]`であり、おおよそ`[2^−128, 2^128]`の価格範囲を与えます。各プールの`tick_spacing`はそのフィーティアによって設定されます：狭いペア（例：ステーブルコイン0.01%ティアはスペーシング1を使用）の場合はより小さいスペーシング、不安定なペア（0.25%ティアは60、1%ティアは120）の場合はより大きいスペーシング。

ポジションは`tick_lower`と`tick_upper`を`tick_spacing`に揃える必要があります。プールのアクティブなティック（流動性がそこで開始または終了するティック）は、スワップステップが気にする唯一のティックです。

## 流動性から金額へ

流動性`L`と価格範囲`[sqrt_lo, sqrt_hi]`（すべての`sqrt_price`値）を持つポジションの場合：

| プール状態                         | トークン0の金額                                        | トークン1の金額                  |
| ----------------------------- | ----------------------------------------------- | ------------------------- |
| 範囲より上の価格 (`sqrt_p ≥ sqrt_hi`) | 0                                               | `L · (sqrt_hi − sqrt_lo)` |
| 範囲内の価格                        | `L · (sqrt_hi − sqrt_p) / (sqrt_p · sqrt_hi)`   | `L · (sqrt_p − sqrt_lo)`  |
| 範囲より下の価格 (`sqrt_p ≤ sqrt_lo`) | `L · (sqrt_hi − sqrt_lo) / (sqrt_lo · sqrt_hi)` | 0                         |

導出：CPMM不変量をローカルに微分します。単一のティック範囲内では、ポジションは仮想準備金`(x_v, y_v)`を持つCPMMとして動作し、プールの現在の`(sqrt_p, L)`が`L = sqrt(x_v · y_v)`と一致するように選択されます。`sqrt_p`から範囲境界まで統合すると、上記の金額が得られます。

**逆公式**（与えられた`amount0`または`amount1`でポジションをミントする場合に使用）：

```
L_from_amount0(amount0, sqrt_lo, sqrt_hi, sqrt_p) =
    amount0 · sqrt_p · sqrt_hi / (sqrt_hi − sqrt_p)

L_from_amount1(amount1, sqrt_lo, sqrt_hi, sqrt_p) =
    amount1 / (sqrt_p − sqrt_lo)

// インレンジポジションへの対称的なデポジットの場合、最小値を使用します。
L = min(L_from_amount0, L_from_amount1)
```

## シングルティックスワップステップ

単一のティック範囲内で、プールはCPMMのように動作します。現在の`sqrt_p`とターゲット`sqrt_target`が与えられた場合：

```
Δamount0_step = L · (sqrt_target − sqrt_p) / (sqrt_p · sqrt_target)     // トークン0にスワップする場合
Δamount1_step = L · (sqrt_target − sqrt_p)                              // トークン1にスワップする場合
```

### 正確な入力ステップ

`Δin_remaining`が与えられた場合：

```
// ティック境界に満たした場合の候補の新しいsqrt_p：
sqrt_after_full = sqrt_target
amount_to_full  = Δamount_in_to_reach(sqrt_p → sqrt_target)

if Δin_remaining ≥ amount_to_full:
    // バケットの残りを消費
    sqrt_p'         = sqrt_target
    Δin_consumed    = amount_to_full
    Δout            = amount_out_at_boundary
else:
    // 越えません；終端sqrt_pについて解く
    sqrt_p'         = L · sqrt_p / (L + Δin_remaining · sqrt_p)      // 0→1スワップの場合
    Δin_consumed    = Δin_remaining
    Δout            = L · (sqrt_p − sqrt_p')                          // Δsqrtに比例
```

`0→1`スワップは`sqrt_p`を低下させます（トークン0を売ると価格は下がります）。`1→0`スワップはそれを上げます。公式は`sqrt_p`と`sqrt_target`を入れ替えると対称です。

### 正確な出力ステップ

同じ構造ですが、`Δin`について解きます。

## マルチティックスワップループ

スワップは入力が枯渇するか価格制限に達するまでティックを反復処理します：

```
while Δin_remaining > 0 and sqrt_p != sqrt_price_limit:
    next_tick = find_next_initialized_tick(pool.tick_current, direction)
    sqrt_target = min(next_tick.sqrt_price, sqrt_price_limit)       // 方向的に

    (Δin, Δout, sqrt_p') = single_step(sqrt_p, sqrt_target, L, Δin_remaining)

    Δin_remaining -= Δin
    accumulated_out += Δout

    if sqrt_p' == next_tick.sqrt_price:
        // ティック交差
        L += next_tick.liquidity_net * direction_sign
        flip_fee_growth_outside(next_tick)
        match_limit_orders_at_tick(next_tick, ...)        // products/clmm/mathを参照
        pool.tick_current = next_tick.tick_index
    sqrt_p = sqrt_p'
```

各`single_step`はプールの現在の`L`を使用します。`L`は初期化されたティックを越えるときに**のみ**変更されます。ティック間の流動性は定数であり、これがステップの数学を閉形式にする理由です。

ティックの`liquidity_net`は、そのティックで開始するポジション流動性の符号付き合計からそこで終了するものを引いたものです。上向きに越えると`liquidity_net`を追加します；下向きに越えるとそれを減算します。

プールが保留中注文をティックで開いている場合、ティック交差ステップは、これらの注文の一部を埋めるためにスワップ入力の一部を機会的に消費します（コホート全体でFIFO）。マッチングアルゴリズムと、上記の基本ステップの公式に適用される可能性のある動的フィーサーチャージは[`products/clmm/math`](/ja/products/clmm/math)に記載されています。これらは閉形式のシングルステップ公式を変更しません。

## フィー成長アキュムレータ

CLMMは単位アクティブ流動性あたりのフィーを、サイドごと、グローバルおよびティックごとに追跡します：

```
fee_growth_global_0_x64     // Q64.64、単調増加
fee_growth_global_1_x64
tick.fee_growth_outside_0_x64   // 「このティックがアクティブ範囲外にあった間に発生したフィー」
tick.fee_growth_outside_1_x64
```

各`single_step`で：

```
step_lp_fee = (Δin · fee_rate) · (1 − protocol_fraction − fund_fraction)
fee_growth_global += step_lp_fee · 2^64 / L     // 入力側のみ
```

（もう一方のサイドの`fee_growth_global`は、そのサイドのトークンがステップで入力として支払われないため、このステップで移動しません。）

ティックを越えるときに、プログラムは`fee_growth_outside`を**反転**させます：

```
tick.fee_growth_outside_0_x64 = fee_growth_global_0_x64 − tick.fee_growth_outside_0_x64
tick.fee_growth_outside_1_x64 = fee_growth_global_1_x64 − tick.fee_growth_outside_1_x64
```

「外部」は`tick_current`に相対的です。`tick_current`がティックより上の場合、外部は「以下」を意味します。`tick_current`が以下の場合、外部は「上」を意味します。反転は解釈を入れ替えます。

### ポジションの`fee_growth_inside`

ポジション`[tick_lower, tick_upper]`と現在の`tick_current`が与えられた場合：

```
if tick_current >= tick_upper:
    inside = tick_lower.fee_growth_outside − tick_upper.fee_growth_outside
else if tick_current < tick_lower:
    inside = tick_upper.fee_growth_outside − tick_lower.fee_growth_outside
else:     // ポジションはインレンジ
    inside = fee_growth_global
           − tick_lower.fee_growth_outside
           − tick_upper.fee_growth_outside
```

ポジションの未回収フィー（トークンサイド`s`）は：

```
tokens_owed_s += L · (fee_growth_inside_s − fee_growth_inside_last_s) / 2^64
fee_growth_inside_last_s = fee_growth_inside_s
```

この更新は、ポジション（`IncreaseLiquidity`、`DecreaseLiquidity`、`CollectFees`）との各インタラクション時に実行されます。

## 作例 — 1つのティックを越える

プール（簡略化）：

* `sqrt_p_x64 = 2^64 · 1.0 = 2^64`（価格 = 1.0）
* `L = 1_000_000`
* `tick_current = 0`
* 下の次の初期化ティック：`tick = −60`、`sqrt_price = 1.0001^(−30) ≈ 0.99700`、`liquidity_net = −400_000`（このティックはポジションを終了するため、下向き交差は400kを削除）
* フィーレート：0.25%

スワップ：`Δin = 10_000` トークン0、方向 = 0→1。

**ステップ1 — `sqrt_target = 0.99700 · 2^64`まで**：

```
amount_in_to_target = L · (1/sqrt_target − 1/sqrt_p)
                    = 1_000_000 · (1/0.99700 − 1/1.0)
                    ≈ 1_000_000 · 0.003009
                    ≈ 3_009
```

3,009 \< 10,000なので、このステップを完全に埋めます：

```
Δin_step  = 3_009 / (1 − 0.0025)  = 3_017    // フィー総額
Δout_step = L · (sqrt_p − sqrt_target) ≈ 1_000_000 · 0.00299 ≈ 2_990
sqrt_p    = 0.99700 · 2^64
tick_current = −60
L         = 1_000_000 + (−400_000)  = 600_000         // ティックを越える
ティック−60のfee_growth_outsideは反転
Δin_remaining = 10_000 − 3_017 = 6_983
```

**ステップ2 — 新しい`L = 600_000`を使用**：

次の初期化ティック（`tick = −120`と言う）は`sqrt = 0.99402`にあります。`amount_in_to_target`を再計算します：

```
amount_in_to_target = 600_000 · (1/0.99402 − 1/0.99700)
                    ≈ 600_000 · 0.003010
                    ≈ 1_806
```

まだ`Δin_remaining`未満です。再度越えます。`Δin_remaining`がゼロに達するまで続けます。

`Δout`の完全なシーケンスは、最終的なスワップ出力に累積されます。

## 初期化とオーバーフロー保護

* `MIN_SQRT_PRICE_X64`と`MAX_SQRT_PRICE_X64`は`tick = ±443636`に対応します。`sqrt_p`をこの範囲外に押し出すスワップは元に戻ります。
* ユーザーの`sqrt_price_limit`パラメータは同じ間隔内にある必要があります。プログラムはチェックします。
* `L · Δsqrt`の積は`u256`で計算され、オーバーフローを避けるために`u128`にシフト バックされます。

## Uniswap v3との違い

* **オラクル。** Raydium の`ObservationState`は`(block_timestamp, tick_cumulative, seconds_per_liquidity_cumulative)`リングバッファを格納します。Uniswapのものとはワイヤ形式が少し異なりますが、TWAP数学は同じです。
* **Token-2022。** Raydium CLMMはToken-2022ミントをサポートしています。トランスファーフィーバリアントでは、追加の事前/事後スワップ金額の調整が必要です。[`algorithms/token-2022-transfer-fees`](/ja/algorithms/token-2022-transfer-fees)を参照してください。
* **ティックビットマップ。** Raydiumは初期化ティックビットマップを`[u64; 16]`にプールごとパックして、高速な`find_next_initialized_tick`を実現します。Uniswapはワードごとのオンチェーンマッピングを使用しています。トレードオフはレント対検索コストです。
* **リワードスロット。** Raydiumは3つのプールごとのリワードストリームをサポートしており、別々の`reward_growth_global_x64`カウンターがあります。構造はフィー成長アキュムレータと同じです。

## ポインタ

* [`products/clmm/math`](/ja/products/clmm/math) — オンチェーン実装と実際のCLMM構造体フィールドを使用した作例。
* [`products/clmm/ticks-and-positions`](/ja/products/clmm/ticks-and-positions) — ティックラティス、`liquidity_net`/`gross`、アクティブ範囲のセマンティクス。
* [`products/clmm/fees`](/ja/products/clmm/fees) — フィー成長アキュムレータの実際の動作。

出典：

* Uniswap v3ホワイトペーパー（sqrt価格数学の正規導出）。
* Raydium CLMMプログラムソース。
