AMM 數學公式完整指南:從基礎常數乘積到進階穩定幣模型

深入剖析各類自動做市商(AMM)的數學基礎,從 Uniswap 的常數乘積模型到 Curve 的 StableSwap 演算法,提供完整的公式推導與實務應用指南,包含無常損失計算、Gas 優化與 LP 收益策略。

AMM 數學公式完整指南:從基礎常數乘積到進階穩定幣模型

概述

自動做市商(Automated Market Maker,AMM)是去中心化金融(DeFi)的核心基礎設施。不同於傳統交易所的訂單簿模型,AMM 採用數學公式來決定交易價格,其定價機制的優劣直接影響流動性效率、交易滑點與資金利用率。本文深入剖析各類 AMM 的數學基礎,從最基礎的常數乘積公式到最新的穩定幣 DEX 演算法,提供完整的推到過程與實務應用指南。

理解這些數學模型對於流動性提供者(LP)優化收益、交易者降低滑點、以及協議設計者構建高效市場至關重要。我們將使用詳細的數學推導與實際數值範例,幫助讀者建立直觀的理解。

一、常數乘積模型(Constant Product Model)

1.1 基礎公式推導

常數乘積模型是 Uniswap V2 採用的核心機制,其名稱來源於以下恒等式:

x × y = k

其中:

這個公式的直覺理解是:交易不改變兩個資產儲備量的乘積。當投資者向池子添加流動性時,k 值會相應增加;而當交易發生時,k 值保持不變。

為什麼選擇乘積而非其他函數?

從數學角度而言,乘積函數具有以下特性:

1.2 交易價格計算

根據微分幾何,價格可以定義為邊際變化率。對於常數乘積模型,邊際價格(Marginal Price)為:

dy/dx = y/x

這意味著購買一單位 X 所需的 Y 數量,等於當前 Y 儲備量除以 X 儲備量。

實際交易計算

假設:

根據恒等式:

(x₀) × (y₀) = (x₀ + dx') × (y₀ - dy)

其中 dx' 為輸入的 USDC 數量,dy 為輸出的 ETH 數量。

求解 dy:

y₀ - dy = k / (x₀ + dx')
dy = y₀ - k / (x₀ + dx')

代入 k = x₀ × y₀ = 10000:

dy = 10 - 10000 / (1000 + dx')

若使用常規滑點計算,假設輸入 dx' = 100 USDC:

dy = 10 - 10000 / 1100 = 10 - 9.09 = 0.91 ETH

實際匯率:100 USDC / 0.91 ETH = 110 ETH/USDC(優於報價)

這解釋了為何大額交易會造成嚴重滑點——隨著交易進行,儲備比例偏離初始狀態,價格顯著變動。

1.3 滑點與價格影響分析

滑點(Slippage)是交易實際成交價格與預期價格的偏差,其根本原因是 AMM 的邊際定價機制。

滑點公式推導

對於常數乘積模型,滑點可以精確計算:

實際價格 / 初始價格 = (y₀ / (y₀ - dy)) × (1 - dy/y₀)

簡化後得到滑點率:

滑點率 ≈ dy / y₀ + (dy / y₀)² + ...

當 dy/y₀ << 1 時,一次近似為:

滑點率 ≈ dy / y₀

數值範例

假設池子配置為 50/50(價值相等),則每種資產佔總價值的 50%。若進行一筆佔總流動性 1% 的交易:

這解釋了為何 LP 傾向於提供足夠的流動性——流動性越高,相同交易規模產生的滑點越低。

1.4 流動性深度與價格曲線

常數乘積模型的價格曲線呈現雙曲線特性,其斜率隨價格變動:

斜率 = dy/dx = y/x = 1/價格

這種設計的優點是價格永遠不會達到無窮大(流動性不會完全耗盡),但缺點是在極端價格區間,流動性極度匱乏。

實際影響

交易規模(佔池子比例)預估滑點
0.1%~0.1%
1%~1%
10%~11%
25%~33%
50%~100%

從數據可見,大額交易在常數乘積模型中極不經濟,這催生了後續的集中流動性模型。

二、集中流動性模型(Concentrated Liquidity)

2.1 Uniswap V3 的創新

Uniswap V3 引入的集中流動性機制允許 LP 將資金集中在特定價格區間,而非均勻分佈在整個 0 到 ∞ 的範圍內。這一創新來自於一個簡單的觀察:大多數交易發生在特定價格區間。

核心公式

在區間 [Pₐ, Pᵦ] 內提供流動性時,等效的常數乘積為:

k = (√Pᵦ - √P) × (√P - √Pₐ) / (√Pᵦ - √Pₐ) × L²

其中 L 為流動性數量(Virtual Liquidity),定義為:

L = √(x × y)

2.2 虛擬儲備與流動性計算

虛擬儲備概念

在集中流動性模型中,即使某個區間內的實際儲備為零,系統仍會根據數學公式計算「虛擬儲備」。這允許交易在區間內進行,即使物理上的代幣已經耗盡。

流動性數量(L)計算

對於位於 [Pₐ, Pᵦ] 的頭寸,流動性 L 的計算方式為:

L = Δx × √Pᵦ / (√Pᵦ - √Pₐ) = Δy / (√Pᵦ - √Pₐ)

其中 Δx, Δy 為實際存入的代幣數量。

實際範例

假設 LP 欲在 ETH/USDC 價格區間 1500-2500 USDC 內提供流動性:

計算 L:

L = 1 × 50 / (50 - 38.73) = 50 / 11.27 ≈ 4.44

2.3 區間頭寸的價格變動風險

集中流動性雖然提高了資本效率,但也帶來了「範圍內」(in-range)和「範圍外」(out-of-range)的風險。

當價格離開區間時

當交易價格突破 Pₐ 或 Pᵦ 時,LP 的頭寸將完全由單一資產構成:

無常損失(Impermanent Loss)計算

假設初始價格為 P₀,終止價格為 P₁,在區間 [Pₐ, Pᵦ] 內的無常損失為:

IL = 2 × √(P₁/P₀) - P₁/P₀ - 1  (當 P₀, P₁ 都在區間內)

數值範例

假設:

IL = 2 × √(2500/2000) - 2500/2000 - 1
   = 2 × √1.25 - 1.25 - 1
   = 2 × 1.118 - 2.25
   = 2.236 - 2.25
   = -0.014 = -1.4%

在這種情況下,LP 仍能獲得部分收益,因為價格上漲帶來了資本利得。

三、穩定幣 AMM 與 StableSwap

3.1 常數和模型的問題

對於穩定幣交易對(如 USDC/USDT),傳統常數乘積模型存在嚴重缺陷:

數據說明

假設池子為 1,000,000 USDC + 1,000,000 USDT:

3.2 Curve 的 StableSwap 公式

Curve Finance 引入的 StableSwap 機制結合了常數乘積與常數和模型的優點:

D = A × nⁿ × Σuᵢ + Σ(uᵢⁿ⁺ⁿ)

簡化版本(針對雙代幣池):

D = A × x × y × (x² + y²) + x² × y²

其中:

3.3 放大係數(A)的作用

放大係數 A 是 StableSwap 模型中最關鍵的參數,它決定了曲線在何處開始偏離常數和模型。

A 與曲線形狀

實務選擇

資產類型建議 A 值說明
穩定幣 1:1 掛鉤100-500高 A 值使曲線更接近直線
類似資產(如stETH/ETH)10-50中等 A 值平衡效率與穩定性
波動性資產1-5低 A 值類似傳統 AMM

3.4 交易計算實務

輸入輸出計算

在 StableSwap 中,給定輸入 dx,輸出 dy 的精確計算需要求解二次方程:

Ax² + Bx + C = 0

其中係數根據當前狀態動態計算。實際實現中,通常使用、牛頓法或二分搜尋進行數值求解。

簡化近似公式

當交易量相對於池子很小時,可以使用以下近似:

dy ≈ dx × (1 - (x + dx) / (y - dy)) / (1 + A × (x + y) / D²)

實際範例

假設:

使用近似公式計算:

dy ≈ 100,000 × (1 - 5100000/4900000) / (1 + 100 × 10000000/25000000000)
   ≈ 100,000 × (-0.04) / (1 + 0.04)
   ≈ 100,000 × (-0.0385)
   ≈ 38,500 / 1.04
   ≈ 37,019 USDT

實際滑點:~0.98%(遠優於常數乘積的 ~2%)

3.5 流動性頭寸計算

LP 份額計算

LP 在 StableSwap 中存入資產後,獲得的份額(tokens)計算為:

shares = D × (1 - (vD/D₀)ⁿ)

其中 vD 為提取的價值(扣除費用後)。

收益來源

StableSwap LP 的收益來自三個部分:

  1. 交易手續費(通常 0.04-0.1%)
  2. CRV 激勵代幣(額外收益)
  3. 套利收益(維持價格穩定)

四、動態 AMM 與自適應曲線

4.1 為何需要動態曲線

傳統 AMM 的曲線是靜態的,無法適應市場條件變化。在以下場景中,靜態曲線表現不佳:

4.2 KyberDMM 的動態乘積

Kyber Network 的動態AMM(DMM)引入時間加權的流動性概念:

k(t) = k₀ × f(t)

其中 f(t) 根據以下因素動態調整:

4.3 Saddle Finance 的調整公式

Saddle Finance 針對比特幣錨定資產(如 renBTC/WBTC/sBTC)採用可調參數的 StableSwap:

修正系數 = 1 + β × |p - 1|

其中 β 為敏感性參數,p 為偏離錨定價格的比率。

4.4 實作考量

動態參數的挑戰

最佳實踐

五、費用模型與 LP 收益優化

5.1 交易費用結構

固定費用模型

Uniswap V2 採用 0.3% 的固定費用,這筆費用歸 LP 所有:

收入 = 0.3% × 交易額

動態費用模型

部分協議根據波動率或池子利用率調整費用:

費用率 = 基礎費率 × 波動率因子 × 利用率因子

5.2 LP 收益率計算

年化收益率(APY)公式

APY = (年度交易收入) / (鎖定流動性價值) × 100%

實際計算

假設:

日收入 = 200,000 × 0.3% = 600 USDC
年收入的 = 600 × 365 = 219,000 USDC
APY = 219,000 / 1,000,000 = 21.9%

現實中,交易量會波動,APY 也隨之變化。

5.3 無常損失量化

完整 IL 公式

對於常數乘積池,無常損失為:

IL = 2 × √(P₁/P₀) / (1 + P₁/P₀) - 1

表格查詢

價格變動無常損失
±25%-1.0%
±50%-5.7%
±75%-13.4%
±100%-25.5%
+200%-43.4%
-50%-25.5%

5.4 收益優化策略

1. 集中流動性優化

選擇交易密集的價格區間:

// 選擇區間的簡易邏輯
function calculateOptimalRange(
    uint256 currentPrice,
    uint256 historicalVolatility
) internal pure returns (uint256, uint256) {
    uint256 width = historicalVolatility * currentPrice / 100;
    uint256 lower = currentPrice - width;
    uint256 upper = currentPrice + width;
    return (lower, upper);
}

2. 多元化分散

將流動性分配到多個池子:

3. 收益聚合

使用 Yearn 等收益優化器自動再投資:

// 收益聚合邏輯
function harvest() external {
    // 收集交易費用
    uint256 fees = pendingFees();

    // 自動複投
    if (fees > threshold) {
        addLiquidity(fees);
    }
}

六、進階數學:路徑依賴與滑點優化

6.1 多跳交易的路徑依賴

當交易透過多個池子進行時,最終輸出取決於所選擇的路徑。這就是所謂的「路徑依賴」問題。

範例:USDC → ETH → DAI

路徑 1:USDC → ETH → DAI

路徑 2:USDC → DAI(直接)

顯然,直接路徑效率更高。這催生了 1inch、Paraswap 等聚合器的需求。

6.2 最優路徑算法

貪心算法的局限性

簡單的貪心算法(在每一步選擇最優輸出)可能陷入局部最優:

貪心選擇:A→B→C 可能優於 A→C

動態規劃解法

定義狀態:

dp[i][j] = 從代幣 i 交換到代幣 j 的最大輸出

轉移方程:

dp[i][j] = max(dp[i][k] × dp[k][j])  for all k

複雜度:O(n³),其中 n 為代幣數量。

6.3 滑點預測模型

機器學習輔助

傳統公式無法預測套利行為帶來的價格變動。進階系統使用:

# 滑點預測特徵
features = [
    'trade_size_ratio',      # 交易規模/流動性
    'volatility_24h',        # 24小時波動率
    'utilization_change',     # 利用率變化
    'recent_trade_count'     # 近期交易次數
]

# 滑點預測模型
predicted_slippage = model.predict(features)

安全邊際建議

基於預測結果,建議設置的安全邊際:

預測滑點建議安全邊際
<0.5%+20%
0.5-2%+50%
>2%+100% 或分批交易

七、協議設計的數學考量

7.1 初始流動性設定

新 AMM 池的初始流動性設定至關重要。考慮以下數學問題:

目標:初始價格合理性

初始價格 = 初始代幣A數量 / 初始代幣B數量

應根據外部市場價格設定,避免套利空間過大。

流動性深度規劃

根據預期交易量,所需流動性:

L = 預期日交易量 × (1 / 目標滑點)²

範例:目標日交易量 1,000,000 USDC,目標滑點 0.5%

L = 1,000,000 × (1/0.005)² = 1,000,000 × 40,000 = 40,000,000

7.2 激勵代幣分配數學

費用補貼公式

協議通常使用代幣激勵吸引流動性。分配公式:

補貼率 = 目標APY - 費用收入APY
年度代幣支出 = 鎖定價值 × 補貼率

線性釋放 vs 遞減

遞減模式更有利於長期穩定性,但需要更精細的經濟模型設計。

7.3 脆弱性分析

價格操縱防範

AMM 的定價機制使其容易受到價格操縱攻擊。關鍵指標:

操縱成本 ≈ 流動性 × 期望價格偏移

閃電貸攻擊向量

攻擊流程:

  1. 透過閃電貸大量借貸
  2. 在 AMM 中大額交易操縱價格
  3. 在其他市場套利
  4. 償還閃電貸

防範措施:

八、實務工具與代碼範例

8.1 價格計算合約

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract AMMPricing {
    // 獲取輸出數量(常數乘積)
    function getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut,
        uint256 fee
    ) public pure returns (uint256) {
        require(amountIn > 0, "Invalid input amount");
        require(reserveIn > 0 && reserveOut > 0, "Insufficient liquidity");

        uint256 amountInWithFee = amountIn * (10000 - fee) / 10000;
        uint256 numerator = amountInWithFee * reserveOut;
        uint256 denominator = reserveIn + amountInWithFee;

        return numerator / denominator;
    }

    // 獲取輸入數量(常數乘積)
    function getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut,
        uint256 fee
    ) public pure returns (uint256) {
        require(amountOut > 0, "Invalid output amount");
        require(reserveIn > 0 && reserveOut > 0, "Insufficient liquidity");

        uint256 numerator = reserveIn * amountOut * 10000;
        uint256 denominator = (reserveOut - amountOut) * (10000 - fee);

        return numerator / denominator + 1;
    }

    // 批量獲取多跳路徑輸出
    function getAmountsOut(
        uint256 amountIn,
        address[] memory path,
        mapping(address => (uint256, uint256)) memory reserves,
        uint256 fee
    ) public pure returns (uint256[] memory amounts) {
        require(path.length >= 2, "Invalid path");

        amounts = new uint256[](path.length);
        amounts[0] = amountIn;

        for (uint256 i = 0; i < path.length - 1; i++) {
            (uint256 reserveIn, uint256 reserveOut) = reserves[path[i]];
            amounts[i + 1] = getAmountOut(
                amounts[i],
                reserveIn,
                reserveOut,
                fee
            );
        }
    }
}

8.2 流動性頭寸計算

// 計算集中流動性的價值變化
contract LiquidityPosition {
    struct Position {
        uint256 liquidity;
        uint256 lowerTick;
        uint256 upperTick;
        uint256 lastTimestamp;
    }

    // 計算頭寸價值
    function positionValue(
        Position memory pos,
        uint256 currentPrice,
        uint256 token0Reserve,
        uint256 token1Reserve
    ) public pure returns (uint256 value0, uint256 value1) {
        if (currentPrice <= pos.lowerTick) {
            // 價格低於區間,全部為 token1
            uint256 amount1 = pos.liquidity * (sqrt(pos.upperTick) - sqrt(pos.lowerTick));
            return (0, amount1);
        } else if (currentPrice >= pos.upperTick) {
            // 價格高於區間,全部為 token0
            uint256 amount0 = pos.liquidity * (sqrt(pos.upperTick) - sqrt(pos.lowerTick));
            return (amount0, 0);
        } else {
            // 價格在區間內
            uint256 amount0 = pos.liquidity * (sqrt(currentPrice) - sqrt(pos.lowerTick));
            uint256 amount1 = pos.liquidity * (sqrt(pos.upperTick) - sqrt(currentPrice));
            return (amount0, amount1);
        }
    }

    // 簡化版 sqrt 函數
    function sqrt(uint256 x) public pure returns (uint256 y) {
        uint256 z = (x + 1) / 2;
        y = x;
        while (z < y) {
            y = z;
            z = (x / z + z) / 2;
        }
    }
}

8.3 StableSwap 計算

// Simplified StableSwap D calculation
function calculateD(
    uint256[] memory balances,
    uint256 A
) public pure returns (uint256 D) {
    uint256 n = balances.length;
    uint256 sum = 0;
    uint256 i;

    for (i = 0; i < n; i++) {
        sum += balances[i];
    }

    if (sum == 0) return 0;

    uint256 Dprev = 0;
    D = sum;

    // Newton-Raphson iteration
    for (uint256 i = 0; i < 255; i++) {
        uint256 D_P = D;

        for (uint256 j = 0; j < n; j++) {
            D_P = D_P * D / balances[j];
        }

        uint256 Dnext = (D * (n - 1) + D_P / (A * n ** n)) * sum / ((n + 1) * D_P / (n * n) + D);

        if (Dnext > D) {
            Dnext -= (Dnext - D) / 2;
        } else {
            D += (D - Dnext) / 2;
        }

        if (Dprev == D) break;
        Dprev = D;
    }
}

九、未來發展方向

9.1 v4 與 Hooks 架構

Uniswap V4 引入的 Hooks 機制允許開發者自定義 AMM 曲線:

9.2 整合zk-Rollup

將 AMM 與 zk-Rollup 結合可以:

9.3 機構級流動性

傳統金融機構的進入將推動:

結論

AMM 的數學原理是 DeFi 生態的基石。從常數乘積到 StableSwap,每種模型都代表了在效率、穩定性與安全性之間的不同權衡。理解這些數學公式不僅有助於 LP 優化收益,更能幫助開發者設計更健壯的金融協議。

隨著技術演進,我們將看到更多創新的 AMM 形態出現,但核心的流動性提供與價格發現機制將持續演進。建議讀者實際動手計算、部署測試合約,以深化對這些數學模型的理解。

延伸閱讀

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。

目前尚無評論,成為第一個發表評論的人吧!