返回 Expert 笔记
Expert Day 68

美式期权 — 二叉树、有限差分与最优行权

CRR 二叉树定价、有限差分(FD)、自由边界问题、最优行权

2026-07-08
Phase 2 - 量化数学与衍生品定价 (Day 61-74)
量化美式期权CRR二叉树有限差分

日期: 2026-07-08 方向: 量化 / 衍生品定价 阶段: Phase 2 - 量化数学与衍生品定价 (Day 61-74) 标签: #量化 #美式期权 #CRR #二叉树 #有限差分


今日目标

类型内容
学习CRR 二叉树定价、有限差分(FD)、自由边界问题、最优行权
实操Python 实现 CRR 二叉树(向量化),美式 Put 与早行权边界
产出binomial.py — 美式期权定价 + 早行权分析

一、数学/理论基础

1.1 美式 vs 欧式期权

特性欧式美式
行权时间仅到期日任意时刻直到到期
定价BS 封闭解数值方法
早行权N/A满足条件时最优

关键定理:无股息时,美式 Call 早行权从不最优(提前行权会损失时间价值),美式 Call = 欧式 Call。但美式 Put 早行权可能最优。加密市场 BTC(无 yield)期权:Call 等同欧式,Put 才需特殊处理

1.2 Cox-Ross-Rubinstein (CRR) 二叉树

思想:把 $[0, T]$ 离散为 $N$ 步,每步 $\Delta t = T/N$。每步价格:

  • 上涨因子 $u = e^{\sigma\sqrt{\Delta t}}$
  • 下跌因子 $d = 1/u = e^{-\sigma\sqrt{\Delta t}}$
  • 风险中性概率 $p = (e^{(r-q)\Delta t} - d)/(u - d)$

为什么这样选?匹配 GBM 的一阶矩与二阶矩:

  • $\mathbb{E}[\Delta \ln S] = (r-q-\sigma^2/2)\Delta t$
  • $\text{Var}(\Delta \ln S) = \sigma^2 \Delta t$

CRR 选 $u = e^{\sigma\sqrt{\Delta t}}, d = 1/u$ 让树"重组" (recombining),节点数 $O(N^2)$ 而非 $2^N$。

1.3 二叉树倒推(欧式)

终端节点 $S_T^j = S_0 u^j d^{N-j}$,payoff $V_T^j = \max(S_T^j - K, 0)$(Call)。

倒推:

$$ V_t^j = e^{-r\Delta t}\left[ p , V_{t+\Delta t}^{j+1} + (1-p) V_{t+\Delta t}^j \right] $$

最终 $V_0$ 即期权价。

1.4 美式期权倒推(加早行权检查)

每步取 max(continuation value, exercise value):

$$ V_t^j = \max\left( e^{-r\Delta t}[p V_{t+\Delta t}^{j+1} + (1-p)V_{t+\Delta t}^j], , \text{payoff}(S_t^j) \right) $$

payoff 对 Call 是 $\max(S-K, 0)$,对 Put 是 $\max(K-S, 0)$。

1.5 收敛性

CRR 二叉树以 $O(1/N)$ 速度收敛到 BS。$N=500$ 通常误差 < 0.1%。奇数 vs 偶数 N:偶数 N 的奇偶振荡问题,可用 Richardson 外推 $V = (V_N + V_{N+1})/2$ 改善。

1.6 早行权边界 (Optimal Exercise Boundary)

对美式 Put:存在临界价格 $S^*(t)$,使得:

  • $S < S^*(t)$:早行权最优
  • $S > S^*(t)$:持有最优

随 $t \to T$,$S^*(t) \to K$(边界条件)。

实务:每个时间步,找最大的 $j$ 使得 $\text{exercise}_j > \text{continuation}_j$,对应 $S^*(t)$。

1.7 有限差分 (FD) — 解 BS PDE

直接数值求解 BS PDE:

$$ \partial_t V + \frac{1}{2}\sigma^2 S^2 \partial_{SS} V + (r-q)S \partial_S V - rV = 0 $$

变量替换 $x = \ln S$ 让 PDE 系数变常数:

$$ \partial_t V + \frac{1}{2}\sigma^2 \partial_{xx} V + (r - q - \sigma^2/2) \partial_x V - rV = 0 $$

Crank-Nicolson 方法(隐式 + 中心差分):

$$ \frac{V_i^{n+1} - V_i^n}{\Delta t} + \frac{1}{2}(\mathcal{L} V^{n+1} + \mathcal{L} V^n) = 0 $$

精度 $O(\Delta t^2 + \Delta x^2)$,无条件稳定。

美式扩展:每步加 LCP (Linear Complementarity Problem) 投影,或简单用 PSOR (Projected SOR) 迭代。

1.8 LSM (Longstaff-Schwartz) — 美式 MC

当维度高时(多资产美式期权),二叉树和 FD 失效。Longstaff-Schwartz (2001):MC 模拟路径,每步用回归估计 continuation value,与 exercise value 比较。


二、直觉解释

Q: 为什么无股息美式 Call 不需要早行权?

考虑 deep ITM Call:早行权得 $S - K$;不行权得"call option",价值 $C \ge \max(S - K e^{-rT}, 0) > S - K$(因为 $K e^{-rT} < K$)。所以持有更值钱。这个论证依赖 $r > 0$ 与 $q = 0$。有股息时不成立。

Q: 为什么美式 Put 早行权可能最优?

Put payoff 是 $K - S$,"K"是固定的。早行权立即获得 $K$,可以再投资得利息。如果继续持有 Put,$K$ 还要等到 $T$ 才能拿到(折现损失 $K(1 - e^{-r(T-t)})$)。当 $S$ 很低时,"利息收益" > "时间价值",早行权值得。

Q: CRR vs Jarrow-Rudd 等其他离散树?

CRR 让树重组($ud = 1$),最常用。Jarrow-Rudd 用 $u = e^{(r-\sigma^2/2)\Delta t + \sigma\sqrt{\Delta t}}$,$p = 0.5$ 简化概率,但 $u, d$ 在不同节点不同。生产用 CRR 最普遍

Q: 加密市场美式期权多吗?

Deribit 的 BTC/ETH vanilla 期权全是欧式!只有 OKX 的部分股票期权是美式。但 DeFi 协议(Lyra V2)一些产品有 American 特征,且 perpetual 期权某种意义上是"无限到期的美式"。所以美式定价在 DeFi exotic 中仍重要。


三、代码实现

"""
binomial.py - CRR 二叉树定价 (欧式 + 美式)
依赖: numpy, scipy
"""

import numpy as np
from scipy.stats import norm


def crr_european(S, K, r, sigma, T, N=500, q=0.0, kind="call"):
    """CRR 二叉树定价欧式期权 (向量化)"""
    dt = T / N
    u = np.exp(sigma * np.sqrt(dt))
    d = 1.0 / u
    p = (np.exp((r - q) * dt) - d) / (u - d)
    disc = np.exp(-r * dt)

    # 终端价格 (S_0 * u^j * d^(N-j))
    j = np.arange(N + 1)
    S_T = S * (u ** j) * (d ** (N - j))

    # 终端 payoff
    if kind == "call":
        V = np.maximum(S_T - K, 0)
    else:
        V = np.maximum(K - S_T, 0)

    # 倒推 (向量化)
    for n in range(N - 1, -1, -1):
        V = disc * (p * V[1:n+2] + (1 - p) * V[0:n+1])

    return V[0]


def crr_american(S, K, r, sigma, T, N=500, q=0.0, kind="put"):
    """CRR 二叉树定价美式期权"""
    dt = T / N
    u = np.exp(sigma * np.sqrt(dt))
    d = 1.0 / u
    p = (np.exp((r - q) * dt) - d) / (u - d)
    disc = np.exp(-r * dt)

    j = np.arange(N + 1)
    S_T = S * (u ** j) * (d ** (N - j))
    V = np.maximum(K - S_T, 0) if kind == "put" else np.maximum(S_T - K, 0)

    # 倒推 + 早行权检查
    for n in range(N - 1, -1, -1):
        S_n = S * (u ** np.arange(n + 1)) * (d ** (n - np.arange(n + 1)))
        cont = disc * (p * V[1:n+2] + (1 - p) * V[0:n+1])
        if kind == "put":
            payoff = np.maximum(K - S_n, 0)
        else:
            payoff = np.maximum(S_n - K, 0)
        V = np.maximum(cont, payoff)

    return V[0]


def crr_american_with_boundary(S, K, r, sigma, T, N=500, q=0.0, kind="put"):
    """同上, 但额外返回每步早行权边界 S*(t)"""
    dt = T / N
    u = np.exp(sigma * np.sqrt(dt))
    d = 1.0 / u
    p = (np.exp((r - q) * dt) - d) / (u - d)
    disc = np.exp(-r * dt)

    j = np.arange(N + 1)
    S_T = S * (u ** j) * (d ** (N - j))
    V = np.maximum(K - S_T, 0) if kind == "put" else np.maximum(S_T - K, 0)

    boundary = []
    for n in range(N - 1, -1, -1):
        S_n = S * (u ** np.arange(n + 1)) * (d ** (n - np.arange(n + 1)))
        cont = disc * (p * V[1:n+2] + (1 - p) * V[0:n+1])
        payoff = np.maximum(K - S_n, 0) if kind == "put" else np.maximum(S_n - K, 0)
        # 找到早行权边界
        exercise_optimal = payoff > cont
        if kind == "put":
            # Put: 边界是最大的 S 使得 exercise 最优
            indices = np.where(exercise_optimal)[0]
            S_star = S_n[indices.max()] if len(indices) > 0 else 0
        else:
            indices = np.where(exercise_optimal)[0]
            S_star = S_n[indices.min()] if len(indices) > 0 else np.inf
        boundary.append((n * dt, S_star))
        V = np.maximum(cont, payoff)

    return V[0], boundary


# ====== Crank-Nicolson FD (欧式 Call) ======

def cn_european_call(S0, K, r, sigma, T, q=0.0, M=200, N=500):
    """
    Crank-Nicolson FD 解 BS PDE (变量替换 x=ln(S))
    M: 时间步数, N: 价格网格
    """
    x = np.log(S0)
    x_min = x - 5 * sigma * np.sqrt(T)
    x_max = x + 5 * sigma * np.sqrt(T)
    dx = (x_max - x_min) / N
    dt = T / M

    grid = np.linspace(x_min, x_max, N + 1)
    S_grid = np.exp(grid)
    V = np.maximum(S_grid - K, 0)  # Terminal payoff

    # PDE coefficients
    sigma2 = sigma**2
    a = 0.5 * sigma2 / dx**2
    b = (r - q - 0.5*sigma2) / (2*dx)

    # Tridiagonal: alpha V_{i-1} + beta V_i + gamma V_{i+1}
    alpha = a - b
    beta = -2*a - r
    gamma = a + b

    # Build tridiagonal matrix
    main_diag = (1 - dt/2 * beta) * np.ones(N - 1)
    sub_diag  = (-dt/2 * alpha) * np.ones(N - 2)
    super_diag = (-dt/2 * gamma) * np.ones(N - 2)

    main_diag_R = (1 + dt/2 * beta) * np.ones(N - 1)
    sub_diag_R  = (dt/2 * alpha) * np.ones(N - 2)
    super_diag_R = (dt/2 * gamma) * np.ones(N - 2)

    from scipy.linalg import solve_banded

    for n in range(M, 0, -1):
        rhs = main_diag_R * V[1:N]
        rhs[1:] += sub_diag_R * V[1:N-1]
        rhs[:-1] += super_diag_R * V[2:N]
        # boundary contribution
        rhs[0] += (dt/2 * alpha) * V[0]
        rhs[-1] += (dt/2 * gamma) * V[N]

        # Solve banded
        ab = np.zeros((3, N - 1))
        ab[0, 1:] = super_diag
        ab[1, :] = main_diag
        ab[2, :-1] = sub_diag
        V_new = solve_banded((1, 1), ab, rhs)
        V[1:N] = V_new

        # Boundary update (Dirichlet)
        V[0] = 0
        V[N] = S_grid[N] - K * np.exp(-r * (T - (n-1)*dt))

    # Interpolate at S0
    return np.interp(np.log(S0), grid, V)


# ====== 验证 + 主流程 ======

def bs_call(S, K, r, sigma, T, q=0.0):
    d1 = (np.log(S/K) + (r-q+0.5*sigma**2)*T) / (sigma*np.sqrt(T))
    d2 = d1 - sigma*np.sqrt(T)
    return S*np.exp(-q*T)*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)


def bs_put(S, K, r, sigma, T, q=0.0):
    d1 = (np.log(S/K) + (r-q+0.5*sigma**2)*T) / (sigma*np.sqrt(T))
    d2 = d1 - sigma*np.sqrt(T)
    return K*np.exp(-r*T)*norm.cdf(-d2) - S*np.exp(-q*T)*norm.cdf(-d1)


def main():
    # 参数
    S, K, r, sigma, T, q = 100.0, 100.0, 0.05, 0.30, 1.0, 0.0

    print("=" * 60)
    print(f"美式 vs 欧式期权定价 (S={S}, K={K}, r={r}, σ={sigma}, T={T})")
    print("=" * 60)

    # CRR 收敛性
    print("\n  欧式 Call CRR 收敛 (vs BS):")
    bs_c = bs_call(S, K, r, sigma, T, q)
    print(f"  BS Call      = {bs_c:.6f}")
    for N in [50, 100, 500, 2000]:
        crr = crr_european(S, K, r, sigma, T, N=N, q=q, kind="call")
        print(f"  CRR (N={N:>5}) = {crr:.6f}, error = {abs(crr-bs_c):.4e}")

    # 美式 Put vs 欧式 Put
    print("\n  美式 vs 欧式 Put:")
    eu_p = bs_put(S, K, r, sigma, T, q)
    am_p = crr_american(S, K, r, sigma, T, N=2000, q=q, kind="put")
    print(f"  欧式 Put       = {eu_p:.4f}")
    print(f"  美式 Put       = {am_p:.4f}")
    print(f"  Early-exercise premium = {am_p - eu_p:.4f}  ({(am_p/eu_p - 1)*100:.2f}%)")

    # 早行权边界
    print("\n  美式 Put 早行权边界 S*(t):")
    _, boundary = crr_american_with_boundary(S, K, r, sigma, T, N=200, q=q, kind="put")
    boundary = sorted(boundary)
    for t, S_star in boundary[::20]:
        print(f"    t={t:.3f}, S*(t)={S_star:.2f}")

    # 美式 Call (无股息)
    print("\n  美式 Call (无股息) 应等于欧式 Call:")
    bs_c = bs_call(S, K, r, sigma, T, q=0)
    am_c = crr_american(S, K, r, sigma, T, N=2000, q=0, kind="call")
    print(f"  欧式 Call    = {bs_c:.4f}")
    print(f"  美式 Call    = {am_c:.4f}")
    print(f"  Difference   = {abs(am_c - bs_c):.6e}")

    # 有股息时美式 Call > 欧式 Call
    q2 = 0.05
    print(f"\n  美式 Call (q={q2}) 应高于欧式:")
    bs_c2 = bs_call(S, K, r, sigma, T, q=q2)
    am_c2 = crr_american(S, K, r, sigma, T, N=2000, q=q2, kind="call")
    print(f"  欧式 Call    = {bs_c2:.4f}")
    print(f"  美式 Call    = {am_c2:.4f}")

    # CN FD 验证
    cn = cn_european_call(S, K, r, sigma, T, q=q, M=500, N=400)
    print(f"\n  CN FD Call  = {cn:.4f}, BS Call = {bs_c:.4f}")


if __name__ == "__main__":
    main()

预期输出

欧式 Call CRR 收敛 (vs BS):
  BS Call      = 14.231254
  CRR (N=   50) = 14.286234, error = 5.50e-02
  CRR (N=  100) = 14.262145, error = 3.09e-02
  CRR (N=  500) = 14.236425, error = 5.17e-03
  CRR (N= 2000) = 14.232568, error = 1.31e-03

美式 vs 欧式 Put:
  欧式 Put       = 9.3540
  美式 Put       = 9.7234
  Early-exercise premium = 0.3694  (3.95%)

美式 Call (无股息) 应等于欧式 Call:
  欧式 Call    = 14.2313
  美式 Call    = 14.2326
  Difference   = 1.31e-03

四、真实数据/案例

CRR 收敛性

经验:$N=500$ 误差通常 < 0.5%;$N=2000$ < 0.1%。生产环境用 $N=1000$ + Richardson 外推平衡精度与速度。

美式 Put 早行权 premium 实例

某 ITM Put:S=80, K=100, r=5%, σ=30%, T=1Y

  • 欧式 Put = $20.40
  • 美式 Put = $21.85
  • Early premium = 7%

加密 BTC 永续合约的"清算"机制有点像 forced 美式行权——下穿清算价就强制平仓,付清算费。这是隐含的早行权 option。

Deribit 期权全是欧式 — 但 Lyra V2 引入"American-like"

Lyra V2 (Optimism L2) 期权可以"任意时刻 cash-settle",需要早行权框架。具体定价仍以欧式 BS 为基础 + 早行权 adjustment。


五、加密市场特化

5.1 永续合约 = 无限期美式期权?

永续合约可视为"持有人随时可平仓换 cash"。但因为 funding 机制,价格被锚定到现货,没有真正的"option premium"。所以永续不是期权,但持仓决策类似美式行权。

5.2 DeFi 期权协议中的"行权"

协议行权方式
Lyra V1欧式,到期 cash-settle
Premia V3美式(任意时点行权)
Dopex欧式 + 自动 settle
Aevo欧式(Deribit-like)

Premia 是 DeFi 中少见支持美式的,需要 on-chain 二叉树或 LSM——燃料费极高,所以采用 off-chain price 与 oracle 结合的混合方案。

5.3 流动性挖矿与早行权

某些激励代币(如 Ribbon vault rebase)含 early withdrawal penalty——本质上是惩罚"早行权"的负 option premium。理解美式 option 思维有助于设计这类机制。


六、常见陷阱

  1. CRR p 公式用错:用 $r$ 而非 $r-q$;正确是 $p = (e^{(r-q)\Delta t} - d)/(u-d)$。

  2. 奇偶振荡:偶数 N 收敛慢于奇数 N。用 Richardson $V \approx (V_N + V_{N+1})/2$。

  3. 美式 Call 错用早行权检查:无股息时不需要,浪费 50% 时间;有股息(如 ETH staking)才需要。

  4. 早行权边界精度低:用 N=200 的边界很粗,需 N>1000。

  5. FD 边界条件错:欧式 Call 在 $S \to \infty$ 边界是 $S - K e^{-rT}$,不是 $S$。

  6. 美式 Put 用 BS 公式:永远低估价格,套利风险。


七、关键速查

公式表达式
CRR u/d$u = e^{\sigma\sqrt{\Delta t}}, d = 1/u$
CRR p$p = (e^{(r-q)\Delta t} - d)/(u - d)$
倒推欧式$V_t = e^{-r\Delta t}[p V_t^{up} + (1-p) V_t^{down}]$
倒推美式$V_t = \max(\text{cont}, \text{payoff})$
美式 Call 不行权条件$q = 0, r > 0$

八、面试题

Q1: 为什么无股息美式 Call 不需要早行权?

早行权得 $S - K$;持有得 $C \ge S - Ke^{-rT}$(来自 lower bound)。$S - Ke^{-rT} > S - K$(因为 $r > 0$),所以持有更值钱。论证依赖 $q = 0$;ETH 有 staking yield 时美式 Call 可能早行权。

Q2: CRR 二叉树为什么选 $u = e^{\sigma\sqrt{\Delta t}}$?

这样设计让树"重组"(节点可重合),内存从 $2^N$ 降到 $O(N^2)$,且匹配 GBM 的方差。

Q3: 美式期权用蒙特卡洛能定价吗?

标准 MC 不能(forward simulation 无法决定早行权)。Longstaff-Schwartz (LSM) 通过回归估计 continuation value 解决。高维(多资产)美式期权必用 LSM。

Q4: 在 DeFi 上做美式期权有什么挑战?

(1) 链上计算二叉树/LSM 太贵;(2) 需要 oracle 提供实时价;(3) 早行权 trigger 是公开博弈(MEV 风险)。Premia V3 用 off-chain calculation + on-chain settle 折中。

Q5: 早行权边界 $S^*(t)$ 在到期前 $t \to T$ 时趋于什么值?

美式 Put: $S^*(T^-) \to K$(边界条件)。直观:临到期 $S < K$ 立即行权获 $K - S$;持有期权则 payoff 也是 $K - S$(如果 ITM),但贴现 + 失去更多上行机会。


九、明日预告

Day 69: 异类期权 — 障碍期权(Barrier)、亚式期权(Asian)、Lookback 期权,以及蒙特卡洛定价方法。明天我们处理 path-dependent 期权——这些在 DeFi structured products 中越来越常见(如 Ribbon、Theta Vaults)。