美式期权 — 二叉树、有限差分与最优行权
CRR 二叉树定价、有限差分(FD)、自由边界问题、最优行权
日期: 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 思维有助于设计这类机制。
六、常见陷阱
-
CRR p 公式用错:用 $r$ 而非 $r-q$;正确是 $p = (e^{(r-q)\Delta t} - d)/(u-d)$。
-
奇偶振荡:偶数 N 收敛慢于奇数 N。用 Richardson $V \approx (V_N + V_{N+1})/2$。
-
美式 Call 错用早行权检查:无股息时不需要,浪费 50% 时间;有股息(如 ETH staking)才需要。
-
早行权边界精度低:用 N=200 的边界很粗,需 N>1000。
-
FD 边界条件错:欧式 Call 在 $S \to \infty$ 边界是 $S - K e^{-rT}$,不是 $S$。
-
美式 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)。