> ## 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.

# AMM v4 數學

> 常數乘積不變量與 AMM v4 的費用慣例、儲備金到訂單簿價格轉換、目標訂單網格構建，以及 PnL 結算步驟。

<Info>
  **本頁內容由 AI 自動翻譯，所有內容以英文版本為準。**

  [查看英文版 →](/products/amm-v4/math)
</Info>

## 不變量

池維持 `coin_reserve × pc_reserve = k`，其中（在 2026-07 OpenBook 移除後）：

```
coin_reserve = coin_vault_balance - accrued_pnl_coin
pc_reserve   = pc_vault_balance   - accrued_pnl_pc
```

有兩點需要注意：

1. 儲備金現在**僅限於金庫**。歷史上的開放訂單項（池作為 OpenBook 限價訂單託管的代幣）已被移除 — 在移除前很久就實際上為零。你可以直接從鏈上金庫餘額計算 `k`。
2. PnL 應計（`need_take_pnl_*`）被減去，以便在管理員掃除費用時保持曲線。這與 CPMM 的 `protocol_fees_*` 排除原則相同。

程式透過 `calc_total_without_take_pnl_no_orderbook` 計算此值（舊的訂單簿感知變體已消失）。

每個 `Swap*` 操作在將 LP 的費用份額加回儲備金後都強制執行 `k' ≥ k`。

## 費用慣例

AMM v4 使用**比率費用**（分子/分母對），而不是 CPMM / CLMM 的 `1/1_000_000` 慣例。鏈上 `Fees` 結構（見程式源碼中的 [`Fees::initialize`](https://github.com/raydium-io/raydium-amm/blob/master/program/src/state.rs)）預設為：

```
Fees {
  min_separate_numerator:    5,
  min_separate_denominator:  10_000,   //  5/10_000 = 0.05%

  trade_fee_numerator:      25,
  trade_fee_denominator:    10_000,    // 25/10_000 = 0.25% — 用於 OpenBook 限價訂單定價

  pnl_numerator:            12,
  pnl_denominator:          100,       // 12/100   = 12%   — 協議在交換費用中的份額

  swap_fee_numerator:       25,
  swap_fee_denominator:     10_000,    // 25/10_000 = 0.25% — AMM 路徑交換的總費用
}
```

解釋（已發佈的主網預設值）：

* **總交換費用：** `swap_fee = amount_in × 25 / 10_000 = 0.25%` 的總輸入。
* **協議份額：** `pnl_numerator / pnl_denominator = 12 / 100 = 12%` **的交換費用**，相當於 `0.25% × 12% = 0.03%` 的交易量。此份額應計到 PnL 計數器中，由 `WithdrawPnl` 掃除。
* **LP 份額：** 交換費用的剩餘 `88%`，相當於 `0.25% × 88% = 0.22%` 的交易量。保留在池中並增加 `k`。
* **無基金份額。** AMM v4 沒有 CPMM/CLMM 的基金費用分割。

注意 `pnl_numerator / pnl_denominator` 是費用的分數**而非**交易量 — 這是對這些欄位名稱的常見誤讀。

`trade_fee_numerator / trade_fee_denominator`（也是 `25 / 10_000`）歷史上由 OpenBook 整合在計算 AMM 限價訂單網格的費用包含價格時使用。隨著 OpenBook 代碼的移除，此欄位已成為遺留物；活躍的交換費用是 `swap_fee_*`。

偏離這些預設值很少見，但在少數舊池上確實存在；在報價前始終從 `AmmInfo.fees` 讀取費用。

## 直接交換數學（AMM 路徑）

最簡單的情況：使用者針對池的金庫進行交換，不與 OpenBook 互動。池的內部儲備金（包括帳上配置）是分母。

**SwapBaseIn（精確輸入）：**

```
amount_after_fee = amount_in − ceil(amount_in × swap_fee_numerator / swap_fee_denominator)
amount_out = amount_after_fee × out_reserve
           / (in_reserve + amount_after_fee)
require(amount_out >= minimum_amount_out)
```

此處使用的儲備金是金庫餘額（減去應計 PnL）。歷史上公式還添加了 AMM 鎖定在 OpenBook 訂單中的代幣；**該項已被移除** — 有效儲備金現在等於原始金庫餘額減去待處理 PnL。曾經用於刷新 OpenBook 端的 `MonitorStep` / 隱式結算路徑已被移除。

**SwapBaseOut（精確輸出）：**

```
amount_in_after_fee = ceil(in_reserve × amount_out / (out_reserve − amount_out))
amount_in_gross     = ceil(amount_in_after_fee × swap_fee_denominator
                            / (swap_fee_denominator − swap_fee_numerator))
require(amount_in_gross <= maximum_amount_in)
```

## 訂單簿互動（歷史）

<Note>
  **已移除。** 本節描述的網格構建反映了 AMM v4 **最初**如何將曲線鏡像到 OpenBook 市場。OpenBook 整合 — 包括 `MonitorStep` 曲柄和 `build_orders` 網格邏輯 — 已從程式中**移除**（2026-07 升級）。下面的數學純粹作為歷史背景保留，說明鏈上 `target_orders` / `amm_open_orders` 帳戶曾經的大小。
</Note>

除了使用者交換外，AMM v4 歷史上在 OpenBook 市場上放置了一個**網格**的限價訂單。網格是從 `AmmInfo` 參數計算的：

* **`depth`** — 每側的價格水準數。
* **`amount_wave`** — 每個水準的基本大小單位。
* **`min_size`**、**`coin_lot_size`**、**`pc_lot_size`** — OpenBook 市場約束。
* **`state_data.swap_acc_coin_fee`**、**`swap_acc_pc_fee`** — 自上次 `TakePnl` 以來的累積費用計數器。

程式透過以恆定比率步驟從當前曲線價格走出來推導每個水準的價格：

```
price_level(k) = curve_price × (1.0001 ^ k)       # 概念上
size_level(k)  = amount_wave × f(depth, k)        # 按深度逐漸減小
```

確切的價格和大小由 `build_orders` 中計算的 `target_orders` 決定，並在每個 `MonitorStep` 與 `amm_open_orders` 進行比較。任何偏差都會導致取消 + 新發佈。OpenBook 上新填充的訂單在下一個刷新 OpenBook 端的操作時結算到池金庫中。

整合者很少需要計算網格 — Raydium 守護者維護它 — 但知道以下內容很有用：

* 具有大量**帳上**流動性的池將該流動性貢獻給 `k`，而不是閒置。
* 陳舊的 OpenBook 市場（事件隊列滿、曲柄被阻止）阻止網格更新；AMM 隨後可以報價與可見訂單簿不同的價格，直到下一次曲柄。

## 結算步驟（PnL）

0.03% 協議份額應計到 `state_data.need_take_pnl_coin` 和 `state_data.need_take_pnl_pc`。`TakePnl` 將這些金額移出金庫到管理員指定的目的地，然後將計數器歸零。

關鍵性質：不變量中的儲備金始終計算**減去**應計 PnL，所以 `TakePnl` 不會移動曲線。這與 CPMM 慣例相符。

## 實際例子

池狀態：

* `coin_reserve = 1_000_000_000_000`（1,000,000 幣側；6 位小數）
* `pc_reserve   = 2_000_000_000_000`（2,000,000 pc 側；6 位小數）
* 費用：預設 `swap = 25/10_000`、`pnl = 3/10_000`。

使用者：`SwapBaseIn` 精確輸入 `1_000_000_000` 幣（1,000 幣）。

```
swap_fee        = ceil(1_000_000_000 * 25 / 10_000)    = 2_500_000
amount_after_fee =                                      997_500_000

amount_out = amount_after_fee * pc_reserve
           / (coin_reserve + amount_after_fee)
           = 997_500_000 * 2_000_000_000_000
           / (1_000_000_000_000 + 997_500_000)
           ≈ 1_995_015_009  (1,995.015 pc)

// 在 2_500_000 交換費用中：
pnl_share = 2_500_000 * 3 / 25  = 300_000    (透過 need_take_pnl_coin 進入協議)
lp_share  = 2_500_000 * 22 / 25 = 2_200_000  (保留在 coin_reserve 中)

new coin_reserve = 1_000_000_000_000 + 1_000_000_000                 = 1_001_000_000_000
                   (其中 300_000 是應計 PnL)
  curve coin_reserve = 1_001_000_000_000 − 300_000 = 1_000_999_700_000
new pc_reserve   = 2_000_000_000_000 − 1_995_015_009                 ≈ 1_998_004_984_991

k' = curve_coin_reserve * new_pc_reserve
   ≈ 2.000_002_701E24
k  = 1_000_000_000_000 * 2_000_000_000_000
   = 2.0E24
k' > k   ✓
```

LP 份額（`2_200_000`）沒有單獨列出 — 它只是提高 `k'` 的剩餘部分。

## 精度規則

* 儲備金乘法使用 `u128`；最終除法向零舍入。
* `swap_fee` 向上舍入（以便池不會低收費）。
* `SwapBaseOut` 的 `amount_in` 向上舍入（以便使用者不會少付）。
* 具有極端儲備金比率的池在非常小的輸入上可能會遇到 `ZeroTradingTokens`；與 CPMM 相同的慣例。

## 與 CPMM 的限制

* AMM v4 的儲備金現在僅限於金庫，所以你**可以**直接從金庫餘額報價（減去 `need_take_pnl_*`） — 之前添加 `open_orders.free` / `open_orders.locked` 金額的要求不再適用。SDK / API 報價仍然是最簡單的選項。
* AMM v4 不公開結構化的鏈上 TWAP。想要 AMM v4 支持的價格的外部消費者必須自己從交易日誌計算。
* 不支援 Token-2022。

## 後續步驟

* [`products/amm-v4/instructions`](/zh-Hant/products/amm-v4/instructions) — `SwapBaseIn`、`Deposit` 等的位置。
* [`products/amm-v4/fees`](/zh-Hant/products/amm-v4/fees) — 完整費用機制、`TakePnl` 詳情。
* [`algorithms/constant-product`](/zh-Hant/algorithms/constant-product) — 共享推導。

來源：

* [Raydium AMM 程式源碼 — `raydium-io/raydium-amm`](https://github.com/raydium-io/raydium-amm)
* Raydium SDK v2 `Liquidity` 模組
