第 2 章:二叉树和三叉树期权定价

本章从 CRR 二叉树出发,介绍欧式和美式期权的回溯定价及 Delta、Gamma 估计,随后讨论柔性二叉树、Richardson 外推、二叉 Black–Scholes 树和 Boyle 三叉树。通过价格误差和收敛曲线,比较不同树方法的精度与计算量。

本章通用代码:导入包与示例参数

下面导入计算和绘图所需的包,设置显示格式及示例参数。

# 本章通用代码:导入计算和绘图所需的包
import sys
from dataclasses import replace
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

project_root = Path.cwd()
while not (project_root / "src").exists() and project_root != project_root.parent:
    project_root = project_root.parent
sys.path.insert(0, str(project_root / "src"))

from quant_option_pricing import (
    AmericanOption,
    BlackScholesModel,
    EuropeanOption,
    TreeSettings,
)
from quant_option_pricing.black_scholes import (
    black_scholes_greeks,
    black_scholes_formula,
)
plt.style.use("seaborn-v0_8-whitegrid")
plt.rcParams["font.family"] = "Microsoft YaHei"
plt.rcParams["axes.unicode_minus"] = False
plt.rcParams["figure.dpi"] = 160
plt.rcParams["savefig.dpi"] = 200
np.set_printoptions(precision=6, suppress=True)
pd.set_option("display.precision", 6)

# 本章默认示例使用的模型、期权和树设置
model = BlackScholesModel(rate=0.06, volatility=0.20)
option = EuropeanOption.put(spot=40.0, strike=45.0, maturity=0.5)
settings = TreeSettings(n_steps=100)

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

在 BSM 模型中,股票价格 \(S_t\) 在风险中性世界中服从几何布朗运动

\[ S_t=S_0\exp\left[\left(r-\frac{\sigma^2}{2}\right)t+\sigma W_t\right] \tag{2.1.1} \]

其中 \(S_0\) 表示股票现值,\(r\) 代表无风险利率,\(\sigma\) 表示股票波动率,\(W_t\) 代表布朗运动。

Cox–Ross–Rubinstein(1979)提出,在 BSM 模型中期权定价可以使用二叉树来近似。将期权到期日 \(T\) 等分为 \(n\) 份,时间点为 \(0,h,2h,\ldots,nh\),其中 \(h=T/n\)。在二叉树上,若标的资产在时间 \(kh\) 的价格为 \(S_k\),在时间 \((k+1)h\) 的股票价格仅有两种可能:或者以概率 \(p\) 上涨至 \(uS_k\),或者以概率 \(1-p\) 下跌到 \(dS_k\),其中 \(u>e^{rh}>d>0\)。由此生成的二叉树如图 2.1 所示。

这种二叉树被称为重新连接树(recombining tree),其优点是节点增长相对缓慢:向上移动之后再向下移动,会到达与向下移动之后再向上移动相同的节点,因此 \(n\) 期二叉树在时间 \(nh\) 的节点仅为 \(n+1\) 个。

n 期二叉树上的标的资产价格。

图 2.1 \(n\)-期二叉树上的标的资产价格。

各层节点按股价从低到高编号为 \(i=1,\ldots,k+1\);根节点记为 \(S_0\),在回溯公式中采用 \(S_{0,1}=S_0\)、\(V_{0,1}=V_0\)。若向上的分叉表示股价下降,则

\[ S_{k,i}=S_{k-1,i}d,\quad S_{k,i+1}=S_{k-1,i}u \tag{2.1.2} \]

因此

\[ S_{k,i}=S_0d^{k+1-i}u^{i-1},\quad 0\leq k\leq n,\quad 1\leq i\leq k+1. \tag{2.1.3} \]

CRR 二叉树先选择每一步的上涨和下跌因子,使对数股价的两种变动幅度相同:

\[ u=e^{\sigma\sqrt{h}} \tag{2.1.4} \]

\[ d=e^{-\sigma\sqrt{h}} \tag{2.1.5} \]

因此 \(ud=1\),每一步的对数股价变动分别为 \(\sigma\sqrt{h}\) 和 \(-\sigma\sqrt{h}\)。风险中性估值要求树上下一期股价的条件均值等于无风险增长后的股价,因此

\[ p(uS_k)+(1-p)dS_k=S_ke^{rh}. \]

整理后得到风险中性上涨概率

\[ p=\frac{e^{rh}-d}{u-d} \tag{2.1.6} \]

下面先比较树上和几何布朗运动的一步条件均值,再比较条件方差。

树上下一期股价的条件均值由两个可能取值按概率加权得到:

\[ \begin{aligned} \mathbb{E}_{\mathrm{CRR}}[S_{k+1}\mid S_k]&=p(uS_k)+(1-p)(dS_k)\\ &=S_k[pu+(1-p)d]\\ &=S_ke^{rh}. \end{aligned} \]

最后一个等号来自等式 (2.1.6) 的风险中性概率选择。风险中性几何布朗运动的条件均值也等于 \(S_ke^{rh}\)。给定时间 \(kh\) 的股价 \(S_k\),下一期股价的对数服从

\[ \ln S_{k+1}\mid S_k\sim N\left(\ln S_k+\left(r-\frac{\sigma^2}{2}\right)h,\sigma^2h\right). \]

利用标准正态随机变量 \(Z\sim N(0,1)\) 的矩母函数 \(\mathbb{E}[e^{aZ}]=e^{a^2/2}\),得到

\[ \mathbb{E}[S_{k+1}\mid S_k]=\exp\left\{\ln S_k+\left(r-\frac{\sigma^2}{2}\right)h+\frac{\sigma^2h}{2}\right\}=S_ke^{rh} \tag{2.1.7} \]

因此,风险中性概率下树上条件均值与几何布朗运动条件均值相等。

树上下一期股价的条件二阶矩和条件方差分别为

\[ \begin{aligned} \mathbb{E}_{\mathrm{CRR}}[S_{k+1}^2\mid S_k]&=S_k^2[pu^2+(1-p)d^2],\\ \operatorname{Var}_{\mathrm{CRR}}(S_{k+1}\mid S_k)&=\mathbb{E}_{\mathrm{CRR}}[S_{k+1}^2\mid S_k]-\mathbb{E}_{\mathrm{CRR}}[S_{k+1}\mid S_k]^2\\ &=S_k^2p(1-p)(u-d)^2. \end{aligned} \]

而几何布朗运动的下一期条件二阶矩和条件方差分别为

\[ \mathbb{E}[S_{k+1}^2\mid S_k]=\exp\left\{2\ln S_k+2\left(r-\frac{\sigma^2}{2}\right)h+\frac{4\sigma^2h}{2}\right\}=S_k^2e^{(2r+\sigma^2)h} \tag{2.1.8} \]

\[ \begin{aligned} \operatorname{Var}_{\mathrm{GBM}}(S_{k+1}\mid S_k)&=\mathbb{E}[S_{k+1}^2\mid S_k]-\mathbb{E}[S_{k+1}\mid S_k]^2\\ &=S_k^2e^{2rh}(e^{\sigma^2h}-1). \end{aligned} \tag{2.1.9} \]

两个条件方差并不完全相等,但可以验证当 \(h\to0\) 时在 \(h\) 的一阶项上相等。

我们先看二叉树条件方差。由等式 (2.1.4) 和等式 (2.1.5),通过一阶泰勒展开可以得到

\[ u-d=e^{\sigma\sqrt h}-e^{-\sigma\sqrt h}=2\sigma\sqrt h+O(h^{3/2}). \]

从而 \[ \lim_{h\to0}p=\frac12, \qquad \lim_{h\to0}\frac{u-d}{\sqrt h}=2\sigma. \] 因此树上条件方差除以 \(h\) 后的极限为: \[ \lim_{h\to0}\frac{\operatorname{Var}_{\mathrm{CRR}}(S_{k+1}\mid S_k)}{h} =S_k^2\lim_{h\to0}p(1-p)\left(\frac{u-d}{\sqrt h}\right)^2 =S_k^2\sigma^2. \tag{2.1.10} \]

而对于几何布朗运动的条件方差,当 \(h\to0\) 时,\(e^{2rh}\to1\),而 \((e^{\sigma^2h}-1)/h\to\sigma^2\),所以 \[ \lim_{h\to0}\frac{\operatorname{Var}_{\mathrm{GBM}}(S_{k+1}\mid S_k)}{h} =S_k^2\sigma^2. \tag{2.1.11} \]

可见CRR 树上的条件方差与几何布朗运动的条件方差在 \(h\) 的一阶项上相等。

程序 2.1根据标的资产波动率 \(\sigma\),无风险利率\(r\) ,期权到期日 \(T\) 和二叉树步数 \(n\) 计算 CRR 二叉树上标的资产上涨的概率 \(p\),以及用于计算标的资产在时间 \(0, h, 2h, . . . , nh\) 的价格(见等式 2.1.3)所需的 \(u^i, d^i, i = 0, 1, . . . , n\)。

公式与代码对应

time_step 对应 \(h=T/n\);up、down 和 up_probability 分别对应等式 (2.1.4)–(2.1.6) 中的 \(u\)、\(d\) 和 \(p\)。

down_values 按顺序保存 \(d^n,d^{n-1},\ldots,1\),up_values 保存 \(1,u,\ldots,u^n\)。两个数组逐项相乘,再乘以 \(S_0\),就得到从低到高排列的终端股价 \(S_0d^{n-j}u^j\),其中 \(j=0,\ldots,n\)。

Python程序 2.1:CRR二叉树参数生成函数

def crr_tree_parameters(model, maturity, n_steps):
    """生成 CRR 二叉树的下行因子、上行因子、风险中性概率和时间步长。"""
    time_step = maturity / n_steps
    up = np.exp(model.volatility * np.sqrt(time_step))
    down = 1.0 / up
    up_probability = (np.exp(model.rate * time_step) - down) / (up - down)
    down_values = down ** np.arange(n_steps, -1, -1)
    up_values = up ** np.arange(n_steps + 1)
    return down_values, up_values, up_probability, time_step

2.1.1 欧式期权

对于欧式期权,通过程序2.1 生成二叉树后,可以从期权到期日 \(T\) 一步步往回倒推出在时间 \((n-1)h,\ldots,h,0\) 的期权价格。记 \(g(S_T)\) 为期权到期收益,则

\[ V_{n,i}=g(S_{n,i}) \tag{2.1.12} \]

从到期日开始向后回溯,得到

\[ V_{k,i}=e^{-rh}\left((1-p)V_{k+1,i}+pV_{k+1,i+1}\right),\quad 0\leq k\leq n-1,\quad 1\leq i\leq k+1. \tag{2.1.13} \]

等式 (2.1.13) 把一个节点的定价分为两步:先将两个后继节点的期权价值按风险中性概率加权,得到下一期价值的条件期望;再乘以 \(e^{-rh}\),把它折现到当前时刻。回溯从到期日开始,是因为这时每个节点的价值可以直接由行权收益确定。算出一层的价值后,就可以把它们作为已知量,继续计算上一层,直到得到时间 0 的期权价格。

图 2.2 展示了一个简单的 2 期 CRR 二叉树定价欧式看跌期权的例子。

  1. 生成图 2.2 左图的二叉树上的标的资产价格。

  2. 将期权到期日 \(T\) 时二叉树上的资产价格 \(S_0d^2,S_0,S_0u^2\) 代入欧式看跌期权的行权收益 \(V=g(S_T)=(K-S_T)^+\)(图 2.2 右图)。

  3. 计算在时间 \(T/2\) 时的期权价格。

  4. 计算在时间 \(0\) 时的期权价格。

2 期 CRR 二叉树。左图为二叉树上的标的资产价格,右图为二叉树上的期权价格。

图 2.2 2-期 CRR 二叉树。左图为二叉树上的标的资产价格,右图为二叉树上的期权价格。

对这个 2 期例子,先把到期日的资产价格 \(S_0d^2,S_0,S_0u^2\) 代入欧式看跌期权的行权收益 \((K-S_T)^+\),再计算

\[ V_d=e^{-rT/2}\left[pV_{ud}+(1-p)V_{dd}\right] \tag{2.1.14} \]

\[ V_u=e^{-rT/2}\left[pV_{uu}+(1-p)V_{ud}\right] \tag{2.1.15} \]

最后得到

\[ V_0=e^{-rT/2}\left[pV_u+(1-p)V_d\right]. \tag{2.1.16} \]

CRR二叉树定价欧式期权可由 程序 2.2 实现。如有兴趣了解更多二叉树的实现可以参看 Higham(2002)。

公式与代码对应

discount_factor 对应一步贴现因子 \(e^{-rh}\);values 对应等式 (2.1.12)–(2.1.13) 中同一层的期权价值 \(V_{k,i}\)。

数组 values 按股价从低到高保存同一层的期权价值。每次回溯时,values[:i] 和 values[1:i+1] 分别提供上一层各节点的下行、上行后继价值。相邻两个值合成为一个当前价值,数组长度因此从 \(i+1\) 减为 \(i\);回溯到时间 0 时,数组中只剩下初始期权价格。

Python程序 2.2:欧式 CRR 二叉树定价函数

def european_crr_price(model, option, settings):
    """按欧式 CRR 二叉树程序生成到期收益并逐层贴现回溯。"""
    n_steps = settings.n_steps
    down_values, up_values, up_probability, time_step = crr_tree_parameters(
        model, option.maturity, n_steps
    )
    values = np.maximum(
        option.cp * (option.spot * down_values * up_values - option.strike),
        0.0,
    )
    discount_factor = np.exp(-model.rate * time_step)
    for i in range(n_steps, 0, -1):
        values = discount_factor * (
            up_probability * values[1 : i + 1]
            + (1.0 - up_probability) * values[:i]
        )
    return float(values[0])

表 2.1 显示当 CRR 二叉树在步数 \(n=50\) 时,得到的期权价格就已经相当准确:当标的资产价格为 \(S_0=45\),波动率为 \(\sigma=0.2\),利率为 \(r=6\%\),期权行权价 \(K=40,45,50\) 和到期日 \(T=0.5,2\),相对误差仅 1% 左右或者更低。

# 表 2.1:步数为 $n=50$ 的 CRR 二叉树定价欧式看跌期权结果。参数为 $S_0=45,\sigma=0.2,r=6\%$
reference_steps = 50
reference_strikes = (40.0, 45.0, 50.0)
reference_maturities = (0.5, 2.0)

crr_reference_rows = []
for maturity in reference_maturities:
    for strike in reference_strikes:
        reference_option = EuropeanOption.put(
            spot=45.0, strike=strike, maturity=maturity
        )
        black_scholes_value = black_scholes_formula(
            model.volatility,
            reference_option.spot,
            reference_option.strike,
            reference_option.maturity,
            model.rate,
            reference_option.cp,
        )
        crr_value = european_crr_price(
            model,
            reference_option,
            replace(settings, n_steps=reference_steps),
        )
        crr_reference_rows.append(
            {
                "K": strike,
                "T": maturity,
                "V_BS": round(black_scholes_value, 4),
                "V_CRR": round(crr_value, 4),
                "相对误差(%)": round(
                    100
                    * abs(crr_value - black_scholes_value)
                    / black_scholes_value,
                    2,
                ),
            }
        )
pd.DataFrame(crr_reference_rows)
K T V_BS V_CRR 相对误差(%)
0 40.0 0.5 0.4510 0.4462 1.06
1 45.0 0.5 1.8902 1.8775 0.67
2 50.0 0.5 4.7620 4.7682 0.13
3 40.0 2.0 1.2562 1.2696 1.07
4 45.0 2.0 2.6503 2.6247 0.97
5 50.0 2.0 4.7038 4.7137 0.21

表 2.1 步数为 \(n=50\) 的 CRR 二叉树定价欧式看跌期权结果,相对误差以百分比表示。期权其他参数为 \(S_0=45,\sigma=0.2,r=6\%\)。

2.1.2 \(\Delta\) 和 \(\Gamma\) 估计

使用二叉树估计敏感性参数最简单的方法是有限差分法:将某个市场风险因子(如股票价格、波动率)人为地改变一个很小的幅度(比如上调 1% 或 1 个基点)再重新估值。但对于 \(\Delta\) 和 \(\Gamma\),还有其他更简便的方法。

2.1.2.1 Hull 方法

Hull(2014)指出,\(\Delta\) 和 \(\Gamma\) 可以在用于定价而生成的二叉树上直接估计。其中,利用时间 \(h\) 的两个节点估计当前时刻的 \(\Delta\),利用时间 \(2h\) 的三个节点估计当前时刻的 \(\Gamma\)。若二叉树在时间 \(0,h,2h\) 的节点如图 2.3 所示,则 \(\Delta\) 和 \(\Gamma\) 的估计分别由等式 (2.1.17) 和等式 (2.1.18) 给出。

\[ \Delta=\frac{V_{1,2}-V_{1,1}}{S_{1,2}-S_{1,1}} \tag{2.1.17} \]

\[ \Gamma=\frac{\dfrac{V_{2,3}-V_{2,2}}{S_{2,3}-S_{2,2}}-\dfrac{V_{2,2}-V_{2,1}}{S_{2,2}-S_{2,1}}}{\dfrac12(S_{2,3}-S_{2,1})}. \tag{2.1.18} \]

等式 (2.1.17) 用两个节点之间的期权价值变化量除以股价变化量,得到价格曲线的局部斜率,即 Delta。计算 Gamma 时,先在时间 \(2h\) 的三个节点之间分别求出左、右两段的斜率,再比较这两个斜率随股价的变化。两个斜率分别对应各自区间的中点,这两个中点的距离为 \(\tfrac12(S_{2,3}-S_{2,1})\),因此等式 (2.1.18) 用这一距离作分母。

二叉树在时间 0、h、2h 的节点。

图 2.3 二叉树在时间 \(0,h,2h\) 的节点。图中的 \(S_{0,0}\)、\(V_{0,0}\) 表示根节点,与正文的 \(S_0\)、\(V_0\) 相同。

程序 2.3 给出了使用 Hull 方法计算 Black–Scholes 模型下欧式期权的 \(\Delta\) 和 \(\Gamma\) 的算法。

公式与代码对应

p、q 和 h 分别对应上涨概率 \(p\)、下跌概率 \(1-p\) 和时间步长 \(h\)。

第一次循环结束后,values 保存时间 \(2h\) 的三个期权价值,spots 保存对应的股价 \(S_0d^2,S_0,S_0u^2\)。left_delta 和 right_delta 对应等式 (2.1.18) 分子中的左、右两段斜率。再回溯一层后,values 的两个值用于等式 (2.1.17) 的 Delta 估计。

Python程序 2.3:Hull 方法的 Delta 和 Gamma 估计函数

def crr_delta_gamma(model, option, settings):
    """按 Hull 方法返回欧式期权价格、Delta 和 Gamma。"""
    n_steps = settings.n_steps
    down_values, up_values, p, h = crr_tree_parameters(
        model, option.maturity, n_steps
    )
    up, down = up_values[1], down_values[-2]
    q = 1.0 - p
    discount = np.exp(-model.rate * h)
    stock_prices = option.spot * down_values * up_values
    values = np.maximum(option.cp * (stock_prices - option.strike), 0.0)

    for _ in range(n_steps - 2):
        values = discount * (p * values[1:] + q * values[:-1])

    spots = option.spot * np.array([down**2, 1.0, up**2])
    left_delta = (values[1] - values[0]) / (spots[1] - spots[0])
    right_delta = (values[2] - values[1]) / (spots[2] - spots[1])
    gamma = (right_delta - left_delta) / ((spots[2] - spots[0]) / 2.0)

    values = discount * (p * values[1:] + q * values[:-1])
    delta = (values[1] - values[0]) / (option.spot * (up - down))
    value = discount * (p * values[1] + q * values[0])
    return float(value), float(delta), float(gamma)

固定现价 \(S_0=40\)、到期时间 \(T=0.5\)、波动率 \(\sigma=0.2\)、利率 \(r=6\%\) 和树步数 \(n=100\)。表2.2 显示:对于不同欧式看跌期权的执行价,Hull 方法都可以得到比较精确的 \(\Delta\) 和 \(\Gamma\) 估计。

# 结果输出:不同执行价下Hull 方法与 Black–Scholes 解析值的比较
greek_strikes = (35.0, 40.0, 45.0, 50.0, 55.0)
hull_greek_rows = []
for strike in greek_strikes:
    strike_option = EuropeanOption.put(
        spot=option.spot, strike=strike, maturity=option.maturity
    )
    _, tree_delta, tree_gamma = crr_delta_gamma(model, strike_option, settings)
    exact_greeks = black_scholes_greeks(
        model.volatility,
        strike_option.spot,
        strike_option.strike,
        strike_option.maturity,
        model.rate,
        strike_option.cp,
    )
    hull_greek_rows.append(
        {
            "执行价": strike,
            "树上 Delta": round(tree_delta, 4),
            "Black–Scholes Delta": round(exact_greeks["delta"], 4),
            "树上 Gamma": round(tree_gamma, 4),
            "Black–Scholes Gamma": round(exact_greeks["gamma"], 4),
        }
    )
pd.DataFrame(hull_greek_rows)
执行价 树上 Delta Black–Scholes Delta 树上 Gamma Black–Scholes Gamma
0 35.0 -0.1100 -0.1099 0.0334 0.0332
1 40.0 -0.3889 -0.3886 0.0683 0.0678
2 45.0 -0.7098 -0.7088 0.0608 0.0606
3 50.0 -0.9038 -0.9023 0.0302 0.0305
4 55.0 -0.9763 -0.9755 0.0099 0.0102

表 2.2 不同执行价下Hull 方法与 Black–Scholes 解析值的比较。

2.1.2.2 扩展二叉树

Pelsser 和 Vorst(1994)提出扩展二叉树方法,利用当前时刻邻近节点的期权价值估计 \(\Delta\) 和 \(\Gamma\)。如图 2.4 所示,扩展二叉树的起始节点不是现在,而是两期之前(\(-2h\))。其中 \(S_{-1,1}=S_0d,S_{-1,2}=S_0u,S_{-2}=S_0\)。

扩展二叉树在时间 −2h、−h、0、h 的节点。

图 2.4 扩展二叉树在时间 \(-2h,-h,0,h\) 的节点。

在扩展二叉树上,\(\Delta\) 和 \(\Gamma\) 的估计如下。

\[ \Delta=\frac{V_{0,3}-V_{0,1}}{S_{0,3}-S_{0,1}} \tag{2.1.19} \]

\[ \Gamma=\frac{\dfrac{V_{0,3}-V_0}{S_{0,3}-S_0}-\dfrac{V_0-V_{0,1}}{S_0-S_{0,1}}}{\dfrac12(S_{0,3}-S_{0,1})}. \tag{2.1.20} \]

向前扩展两期后,时间 0 这一层具有 \(S_0d^2\)、\(S_0\) 和 \(S_0u^2\) 三个股价节点。三个节点上的期权都具有相同的剩余期限 \(T\),因此可以在当前时刻比较价格随股价的变化,估计 Delta 和 Gamma。中间节点给出所求期权的价格,两侧节点提供计算斜率和曲率所需的邻近值。

程序 2.4 可用于使用 CRR 二叉树计算 Black–Scholes 模型下欧式期权的 \(\Delta\) 和 \(\Gamma\)。

公式与代码对应

total_steps=n_steps+2 对应从 \(-2h\) 到 \(T\) 的总步数;以 \(h=T/n\) 为步长,从终端层回溯 n_steps 次后,保留的是时间 0 的三个节点价值。

value_down、value 和 value_up 分别对应等式 (2.1.19)–(2.1.20) 中的 \(V_{0,1}\)、\(V_0\) 和 \(V_{0,3}\),对应股价为 \(S_0d^2,S_0,S_0u^2\)。

Python程序 2.4:扩展二叉树的 Delta 和 Gamma 估计函数

def crr_extended_delta_gamma(model, option, settings):
    """按扩展 CRR 二叉树返回欧式期权价格、Delta 和 Gamma。"""
    n_steps = settings.n_steps
    down_values, up_values, p, h = crr_tree_parameters(
        model, option.maturity, n_steps
    )
    up, down = up_values[1], down_values[-2]
    q = 1.0 - p
    discount = np.exp(-model.rate * h)

    total_steps = n_steps + 2
    up_moves = np.arange(total_steps + 1)
    stock_prices = option.spot * down ** (total_steps - up_moves) * up**up_moves
    values = np.maximum(option.cp * (stock_prices - option.strike), 0.0)
    for _ in range(n_steps):
        values = discount * (p * values[1:] + q * values[:-1])

    value_down, value, value_up = values
    delta = (value_up - value_down) / (option.spot * (up**2 - down**2))
    gamma = 2.0 * (
        (value_up - value) / (up**2 - 1.0)
        - (value - value_down) / (1.0 - down**2)
    ) / (option.spot**2 * (up**2 - down**2))
    return float(value), float(delta), float(gamma)

固定现价 \(S_0=40\)、到期时间 \(T=0.5\)、波动率 \(\sigma=0.2\)、利率 \(r=6\%\) 和树步数 \(n=100\)。表2.3 显示:对于不同欧式看跌期权的执行价,扩展二叉树也能得到比较精确的 \(\Delta\) 和 \(\Gamma\) 估计。

# 结果输出:不同执行价下扩展二叉树与 Black–Scholes 解析值的比较
greek_strikes = (35.0, 40.0, 45.0, 50.0, 55.0)
extended_greek_rows = []
for strike in greek_strikes:
    strike_option = EuropeanOption.put(
        spot=option.spot, strike=strike, maturity=option.maturity
    )
    _, tree_delta, tree_gamma = crr_extended_delta_gamma(model, strike_option, settings)
    exact_greeks = black_scholes_greeks(
        model.volatility,
        strike_option.spot,
        strike_option.strike,
        strike_option.maturity,
        model.rate,
        strike_option.cp,
    )
    extended_greek_rows.append(
        {
            "执行价": strike,
            "树上 Delta": round(tree_delta, 4),
            "Black–Scholes Delta": round(exact_greeks["delta"], 4),
            "树上 Gamma": round(tree_gamma, 4),
            "Black–Scholes Gamma": round(exact_greeks["gamma"], 4),
        }
    )
pd.DataFrame(extended_greek_rows)
执行价 树上 Delta Black–Scholes Delta 树上 Gamma Black–Scholes Gamma
0 35.0 -0.1115 -0.1099 0.0333 0.0332
1 40.0 -0.3884 -0.3886 0.0676 0.0678
2 45.0 -0.7065 -0.7088 0.0606 0.0606
3 50.0 -0.9008 -0.9023 0.0307 0.0305
4 55.0 -0.9749 -0.9755 0.0103 0.0102

表 2.3 不同执行价下扩展二叉树与 Black–Scholes 解析值的比较。

接下来针对不同二叉树步数,计算两种 Greeks 计算方法与 Black–Scholes 解析值之间的误差。步数取 \(20,40,\ldots,10240\),这样可以直接观察误差随步数变化的趋势。

# 中间量计算:按照前面的参数和公式整理数值结果
greek_option = option

greek_steps = np.array(
    [20, 40, 80, 160, 320, 640, 1280, 2560, 5120, 10240]
)
bs_greeks = black_scholes_greeks(
    model.volatility,
    greek_option.spot,
    greek_option.strike,
    greek_option.maturity,
    model.rate,
    greek_option.cp,
)
hull_results = np.array(
    [
        crr_delta_gamma(
            model,
            greek_option,
            replace(settings, n_steps=int(steps)),
        )[1:]
        for steps in greek_steps
    ]
)
extended_results = np.array(
    [
        crr_extended_delta_gamma(
            model,
            greek_option,
            replace(settings, n_steps=int(steps)),
        )[1:]
        for steps in greek_steps
    ]
)
delta_errors = {
    "Hull 方法": hull_results[:, 0] - bs_greeks["delta"],
    "扩展二叉树": extended_results[:, 0] - bs_greeks["delta"],
}
gamma_errors = {
    "Hull 方法": hull_results[:, 1] - bs_greeks["gamma"],
    "扩展二叉树": extended_results[:, 1] - bs_greeks["gamma"],
}

图 2.5 比较相同参数下两种方法的 Delta 估计误差。曲线展示的是带符号的误差,因此应按曲线到零线的距离判断精度。横轴使用对数刻度,便于同时观察小步数和大步数区域。

# 图 2.5:使用 Hull 方法和扩展二叉树估计欧式看跌期权 Delta 的误差
fig, ax = plt.subplots(figsize=(7.5, 4.2))
delta_styles = {
    "Hull 方法": {"color": "tab:blue", "marker": "D"},
    "扩展二叉树": {"color": "tab:orange", "marker": "o"},
}
for label, errors in delta_errors.items():
    ax.semilogx(
        greek_steps,
        errors,
        linestyle="-",
        linewidth=1.1,
        markersize=4.5,
        label=label,
        **delta_styles[label],
    )
ax.axhline(0.0, color="black", linewidth=0.8, alpha=0.6)
ax.set_xlim(10, 10240)
ax.set_ylim(-0.006, 0.012)
ax.set_xlabel("二叉树步数 $n$")
ax.set_ylabel("Delta 误差")
ax.set_title("二叉树 Delta 误差")
ax.legend(frameon=False)
ax.grid(True, which="both", alpha=0.25)
fig.tight_layout()
plt.show()

图 2.5 使用 Hull 方法和扩展二叉树 估计欧式看跌期权 Delta 的误差。

图 2.5 使用 Hull 方法和扩展二叉树 估计欧式看跌期权 Delta 的误差。

在全部十个绘制的步数上,Hull 方法的 Delta 绝对误差都更小。

Hull 方法使用时间 \(h\) 的两个节点 \(S_0d\) 和 \(S_0u\) 估计 Delta,而扩展二叉树使用时间 0 的两个节点 \(S_0d^2\) 和 \(S_0u^2\)。两种方法的股价节点间距分别为

\[ \begin{aligned} w_H &= S_0(u-d),\\ w_E &= S_0(u^2-d^2),\\ \frac{w_E}{w_H} &= u+d=e^{\sigma\sqrt{h}}+e^{-\sigma\sqrt{h}}\approx 2. \end{aligned} \]

当 \(h\) 较小时,扩展二叉树用于估计 Delta 的股价节点间距约为 Hull 方法的两倍。扩展二叉树的邻近节点具有相同的剩余期限 \(T\),而 Hull 方法的节点具有剩余期限 \(T-h\)。扩展二叉树消除了这一时间偏移,但较宽的股价区间使估计量反映更大范围内的平均斜率,从而改变了空间有限差分的近似偏差。

在本例中,Hull 方法的时间与节点间距近似偏差和 CRR 节点价值误差部分抵消,而扩展二叉树的空间近似偏差与节点价值误差相互叠加。

图 2.6 使用相同的期权参数和步数比较 Gamma 估计误差。

# 图 2.6:使用 Hull 方法和扩展二叉树估计欧式看跌期权 Gamma 的误差
fig, ax = plt.subplots(figsize=(7.5, 4.2))
gamma_styles = {
    "Hull 方法": {"color": "tab:blue", "marker": "D"},
    "扩展二叉树": {"color": "tab:orange", "marker": "o"},
}
for label, errors in gamma_errors.items():
    ax.semilogx(
        greek_steps,
        errors,
        linestyle="-",
        markersize=4.5,
        label=label,
        **gamma_styles[label],
    )
ax.axhline(0.0, color="black", linewidth=0.8, alpha=0.6)
ax.set_xlim(10, 20000)
ax.set_ylim(-0.0006, 0.0008)
ax.set_xlabel("二叉树步数 $n$")
ax.set_ylabel("Gamma 误差")
ax.set_title("二叉树 Gamma 误差")
ax.legend(frameon=False)
ax.grid(True, which="both", alpha=0.25)
fig.tight_layout()
plt.show()

图 2.6 使用 Hull 方法和扩展二叉树 估计欧式看跌期权 Gamma 的误差。

图 2.6 使用 Hull 方法和扩展二叉树 估计欧式看跌期权 Gamma 的误差。

在 \(n=40,80,320,640\) 时,Hull 方法的绝对误差更小;在其余六个绘制的步数上,扩展二叉树的绝对误差更小。随着二叉树细化,两种方法都趋近于解析 Gamma,但两者的精度排序随步数变化。

2.1.3 美式期权

美式期权允许持有人在到期日 \(T\) 之前的任意时刻行权,因此定价时需要确定何时行权、何时继续持有。即使在 BSM 模型下,美式期权通常也没有解析表达式,需要使用数值方法近似。

将到期时间 \(T\) 等分为 \(n\) 份,并假设期权只允许在时间 \(0,h,2h,\ldots,nh\) 行权时,得到的是百慕大期权。它介于只能在到期日行权的欧式期权和可以连续行权的美式期权之间;当 \(n\) 增大时,百慕大期权的价格可以用来逼近美式期权的价格。下面统一把这些允许提前行权的合约称为美式期权。

记期权的行权收益为 \(g(S)\)。令 \(\mathcal T_n\) 为取值于 \(\{0,h,2h,\ldots,nh\}\) 的停时集合:每个停时代表一种根据当时已知市场信息作出的行权规则。例如,当股价首次进入行权区域时执行期权。离散行权网格上的期权初始价值可以写为

\[ \begin{align*} V(0,S) = \sup_{\tau\in\mathcal T_n}\mathbb{E}^Q\left[e^{-r\tau}g(S_\tau)\mid S_0=S\right]. \tag{2.1.21} \end{align*} \]

由于美式期权可以在任何允许的时刻行权,其价值必然不小于行权收益。因此在每个允许行权的时刻 \(t\),

\[ V(t,S)\geq g(S). \tag{2.1.22} \]

没有分红的美式看涨期权

以下假设标的资产不支付股息,且无风险利率满足 \(r\geq0\)。

首先,由于美式期权可以提前行权,所以其价值必然不小于相应的欧式期权价值,可记为

\[ \begin{align*} C_A(S_t,T-t,K) \geq C_E(S_t,T-t,K). \tag{2.1.23} \end{align*} \]

其中 \(S_t\) 为标的资产在时间 \(t\) 的价格,\(K\) 为欧式和美式期权的行权价,\(T\) 为到期日。

第二,在没有分红的情况下,欧式期权的价格下限为

\[ \begin{align*} C_E(S_t,T-t,K) \geq \left(S_t-Ke^{-r(T-t)}\right)^+. \tag{2.1.24} \end{align*} \]

推导公式 (2.1.24) 可以考虑两个投资组合在 \(t\) 时分别为:

  • 组合 1:一份欧式看涨期权 \(C_E(S,T-t,K)\) 和现金 \(Ke^{-r(T-t)}\);

  • 组合 2:一份股票 \(S\)。

这两个投资组合在期权到期日 \(T\) 的价值见下表。

\(S_T<K\) \(S_T\geq K\)
组合 1 \(K\) \((S_T-K)+K=S_T\)
组合 2 \(S_T\) \(S_T\)

表 2.4 无分红看涨期权下界证明中两个投资组合在到期日的价值比较。

到期时,组合 1 的价值在 \(S_T<K\) 时高于组合 2,在 \(S_T\geq K\) 时与组合 2 相等。因此,在时间 \(t\) 组合 1 的价值也不小于组合 2,即

\[ \begin{align*} C_E(S_t,T-t,K)+Ke^{-r(T-t)}\geq S_t. \tag{2.1.25} \end{align*} \]

将 \(Ke^{-r(T-t)}\) 移到不等式右侧,再加上期权价格总是非负,就可以得到不等式 (2.1.24)。结合不等式 (2.1.23),我们可以得到

\[ \begin{align*} C_A(S_t,T-t,K)\geq\left(S_t-Ke^{-r(T-t)}\right)^+. \tag{2.1.26} \end{align*} \]

最后,在任意允许行权的时刻 \(\tau\leq T\),立即行权收益为 \((S_\tau-K)^+\)。选择继续持有至到期,其价值为对应的欧式看涨期权价格。由 \(r\geq0\) 和式(2.1.24),

\[ \begin{align*} \underbrace{(S_\tau-K)^+}_{\text{停止(立即行权)价值}}\leq\left(S_\tau-Ke^{-r(T-\tau)}\right)^+\leq\underbrace{C_E(S_\tau,T-\tau,K)}_{\text{持有至到期的价值}}, \tag{2.1.27} \end{align*} \]

因此,继续持有至到期的价值至少等于立即行权收益。在每个允许行权的时刻都可以选择继续持有,最优行权规则可取 \(\tau=T\),所以无分红且 \(r\geq0\) 时,美式看涨期权与对应的欧式看涨期权同价。

使用动态规划定价美式期权

上述不提前行权的论证不能直接用于标的资产支付分红的美式看涨期权或美式看跌期权。看涨期权持有人行权后可以持有股票并获得此后的分红;看跌期权持有人行权后可以提前收到行权价对应的现金,并用这笔现金赚取利息。这些收益可能使提前行权成为最优选择,因此不能简单地用对应的欧式期权价格来定价。在 BSM 模型下,这些美式期权的价格通常没有闭式表达式,因此我们使用动态规划进行数值计算。

公式 (2.1.21) 表示的美式期权价格可以用动态规划从期权到期日 \(t=nh\) 一步步倒推到 \(t=0\)。记 \(V_i(x)=V(ih,x)\) 为当 \(S_{ih}=x\),且期权在 \(t=ih\) 时还未被执行时的价值,则

\[ \begin{align*} V_n(x) ={}& g_n(x), \tag{2.1.28}\\ V_{i-1}(x) ={}& \max\left\{g_{i-1}(x),e^{-rh}\mathbb{E}^Q\left[V_i(S_{ih})\mid S_{(i-1)h}=x\right]\right\}, \tag{2.1.29}\\ & i=1,2,\ldots,n. \tag{2.1.30} \end{align*} \]

其中 \(g_{i-1}(x)\) 表示期权在时间 \((i-1)h\) 的行权价值,而 \(e^{-rh}\mathbb{E}^Q[V_i(S_{ih})\mid S_{(i-1)h}=x]\) 表示期权在时间 \((i-1)h\) 的持有价值。计算美式期权价值时需要在每一步都选择二者的最大值。当行权价值大于持有价值时,就选择行权,否则就选择持有期权。

例如,一份美式看跌期权的行权价为 40,某个节点的股价为 30,立即行权可以获得 10。若在该节点算出的继续持有价值为 9.6,则选择行权,节点价值为 10;若继续持有价值为 10.4,则选择继续持有,节点价值为 10.4。继续持有价值由下一期的期权价值计算,而下一期的价值已经包含此后各节点的最优行权选择。逐层回溯就把未来的行权决策纳入了当前价格。

在 CRR 二叉树上实现动态规划

实现式 (2.1.28)–(2.1.30) 中的动态规划递推,需要在每一步计算条件期望。在 CRR 二叉树上,每个节点在下一期只有上涨和下跌两种可能状态,因此条件期望就是两个后继节点的期权价值按风险中性概率 \(p\) 和 \(1-p\) 加权的平均值。从到期收益出发,逐层向前回溯,将这一加权平均值贴现即可得到继续持有价值,再在每个节点将其与立即行权价值进行比较。

记美式看跌期权的立即行权收益为 \((K-S)^+\)。在二叉树上,每个允许行权的节点都要比较立即行权价值和继续持有价值,并取二者的最大值。因此,美式看跌期权价格为

\[ V_{k,i}=\max\left((K-S_{k,i})^+,e^{-rh}\left((1-p)V_{k+1,i}+pV_{k+1,i+1}\right)\right), \quad 0\leq k\leq n-1,\quad 1\leq i\leq k+1. \tag{2.1.31} \]

比如,在图 2.2 给出的 2 期例子中,

\[ V_d=\max\left((K-S_0d)^+,e^{-rT/2}\left[pV_{ud}+(1-p)V_{dd}\right]\right) \tag{2.1.32} \]

\[ V_u=\max\left((K-S_0u)^+,e^{-rT/2}\left[pV_{uu}+(1-p)V_{ud}\right]\right) \tag{2.1.33} \]

\[ V_0=\max\left((K-S_0)^+,e^{-rT/2}\left[pV_u+(1-p)V_d\right]\right). \tag{2.1.34} \]

这可由美式期权的 CRR 二叉树定价程序实现。

公式与代码对应

在每次回溯中,stock_prices 保存当前要计算的上一层股价;exercise 对应这些节点的立即行权收益 \(g(S)\),continuation 对应下一期价值的贴现条件期望。values = np.maximum(exercise, continuation) 实现等式 (2.1.31) 中逐节点取最大值的操作。

Python程序 2.5:美式 CRR 二叉树定价函数

def american_crr_price(model, option, settings):
    """按美式 CRR 二叉树程序逐层比较行权价值和贴现后的持有价值。"""
    n_steps = settings.n_steps
    down_values, up_values, up_probability, time_step = crr_tree_parameters(
        model, option.maturity, n_steps
    )
    values = np.maximum(
        option.cp * (option.spot * down_values * up_values - option.strike),
        0.0,
    )
    discount_factor = np.exp(-model.rate * time_step)
    for i in range(n_steps, 0, -1):
        continuation = discount_factor * (
            up_probability * values[1 : i + 1]
            + (1.0 - up_probability) * values[:i]
        )
        stock_prices = (
            option.spot * down_values[n_steps - i + 1 :] * up_values[:i]
        )
        exercise = np.maximum(
            option.cp * (stock_prices - option.strike), 0.0
        )
        values = np.maximum(exercise, continuation)
    return float(values[0])

下面调用美式 CRR 定价函数,并与相同参数的欧式看跌期权价格比较。

# 参数定义:比较同一看跌期权的欧式价格和美式价格
european_put = european_crr_price(model, option, settings)
american_option = AmericanOption.put(
    spot=option.spot,
    strike=option.strike,
    maturity=option.maturity,
)
american_put = american_crr_price(model, american_option, settings)
early_exercise_premium = american_put - european_put
pd.Series(
    {
        "欧式看跌期权": european_put,
        "美式看跌期权": american_put,
        "提前行权溢价": early_exercise_premium,
    }
)
欧式看跌期权    4.630949
美式看跌期权    5.143206
提前行权溢价    0.512256
dtype: float64

2.1.4 CRR 二叉树的收敛性质

Cox–Ross–Rubinstein(1979)指出,当 CRR 二叉树的步数 \(n\) 逐渐增加时,二叉树得到的欧式期权价格估计会收敛至 Black–Scholes 公式。F. Diener 和 M. Diener(2004)研究了 CRR 树的价格震荡,给出通常二叉树模型的定价误差为 \(O(1/n)\)。这表示误差的渐近量级与步数成反比。也就是说,当 \(n\) 加 倍时,CRR 二叉树的定价误差大致减半。

我们首先考虑平值期权,并选取参数 \(S_0=K=10,T=1,\sigma=0.3,r=6\%\)。

绘图辅助函数:CRR价格收敛图

def plot_crr_price_convergence(steps, prices, reference_price):
    """绘制CRR价格、Black–Scholes基准及奇偶步数分开的收敛图。"""
    odd_mask = steps % 2 == 1
    even_mask = ~odd_mask
    fig, plot_axes = plt.subplots(2, 1, figsize=(8.5, 7.0), sharex=True)
    plot_axes[0].plot(steps, prices, color="tab:blue", linewidth=1.0, label="CRR 价格")
    plot_axes[0].axhline(
        reference_price, color="tab:red", linewidth=1.2,
        label="Black–Scholes 价格",
    )
    plot_axes[0].set_ylabel("期权价格")
    plot_axes[0].set_title("所有步数")
    plot_axes[0].legend(frameon=False)
    plot_axes[0].grid(True, alpha=0.25)

    plot_axes[1].plot(
        steps[odd_mask], prices[odd_mask], color="tab:green", linewidth=1.2,
        label="CRR 价格:奇数 n",
    )
    plot_axes[1].plot(
        steps[even_mask], prices[even_mask], color="tab:blue", linewidth=1.2,
        label="CRR 价格:偶数 n",
    )
    plot_axes[1].axhline(
        reference_price, color="tab:red", linewidth=1.2,
        label="Black–Scholes 价格",
    )
    plot_axes[1].set_xlabel("二叉树步数 $n$")
    plot_axes[1].set_ylabel("期权价格")
    plot_axes[1].set_title("分别显示奇数和偶数步数")
    plot_axes[1].legend(frameon=False)
    plot_axes[1].grid(True, alpha=0.25)
    fig.tight_layout()
    plt.show()
# 参数定义:本节图表使用 $\sigma=0.3$,默认模型保留给前面的示例
convergence_model = replace(model, volatility=0.30)
# 中间量计算:按照前面的参数和公式整理数值结果
atm_option = EuropeanOption.put(spot=10.0, strike=10.0, maturity=1.0)
convergence_steps = np.arange(50, 501)
bs_atm = black_scholes_formula(
    convergence_model.volatility,
    atm_option.spot,
    atm_option.strike,
    atm_option.maturity,
    convergence_model.rate,
    atm_option.cp,
)
crr_atm_prices = np.array(
    [
        european_crr_price(
            convergence_model,
            atm_option,
            replace(settings, n_steps=int(steps)),
        )
        for steps in convergence_steps
    ]
)
crr_atm_errors = np.abs(crr_atm_prices - bs_atm)
odd_mask = convergence_steps % 2 == 1
even_mask = convergence_steps % 2 == 0

在本例参数和 \(n=50,51,\ldots,500\) 的步数范围内,图 2.7 显示:

  1. 当把 CRR 二叉树步数从 50 增加到 500 时,得到的期权价格在Black-Scholes 价格上下震荡。
  2. 幸运的是,如果我们只取偶数步数,那么 CRR 二叉树总是低估期权价格,从而给出了期权价格的下界。
  3. 而如果只取奇数步数,则 CRR 二叉树总是高估期权价格,从而给出了期权价格的上界。
# 图 2.7:CRR 平值欧式看跌期权价格的奇偶步收敛
plot_crr_price_convergence(convergence_steps, crr_atm_prices, bs_atm)

图 2.7 对应不同步数的 CRR 二叉树得到的平值欧式看跌期权价格。期权参数为 $S_0=K=10,T=1,\sigma=0.3,r=6\%$。

图 2.7 对应不同步数的 CRR 二叉树得到的平值欧式看跌期权价格。期权参数为 \(S_0=K=10,T=1,\sigma=0.3,r=6\%\)。

图 2.8 显示,仅考虑偶数步数时,CRR 二叉树定价误差以 1/n 的速度单调向 0 收敛。如果仅选取奇数步数,也能得到类似的结果。

# 图 2.8:CRR 二叉树平值欧式看跌期权误差向 0 的收敛,同时显示奇数和偶数步数的结果
fig, ax = plt.subplots(figsize=(8.0, 5.2))
ax.loglog(
    convergence_steps[odd_mask],
    crr_atm_errors[odd_mask],
    "o",
    markersize=3.0,
    label="CRR 误差:奇数 n",
)
ax.loglog(
    convergence_steps[even_mask],
    crr_atm_errors[even_mask],
    "o",
    markersize=3.0,
    label="CRR 误差:偶数 n",
)
ax.loglog(
    convergence_steps,
    crr_atm_errors[0] * (convergence_steps[0] / convergence_steps),
    "r-",
    linewidth=1.2,
    label="$1/n$",
)
ax.set_xlabel("二叉树步数 $n$")
ax.set_ylabel("价格绝对误差")
ax.set_title("CRR 二叉树平值期权误差")
ax.legend(frameon=False)
ax.grid(True, which="both", alpha=0.25)
fig.tight_layout()
plt.show()

图 2.8 蓝色圆点和橙色圆点分别表示奇数和偶数步数下的平值欧式看跌期权绝对误差。红色实线向 0 的收敛速度为 $1/n$。期权参数为 $S_0=K=10,T=1,\sigma=0.3,r=6\%$。

图 2.8 蓝色圆点和橙色圆点分别表示奇数和偶数步数下的平值欧式看跌期权绝对误差。红色实线向 0 的收敛速度为 \(1/n\)。期权参数为 \(S_0=K=10,T=1,\sigma=0.3,r=6\%\)。

然而,对于非平值期权,仅选取奇数或者偶数步数并不能使得 CRR 二叉树单调收敛。令当前股价为 \(S_0=8\),并取 \(K=10,T=1,\sigma=0.3,r=6\%\) 计算实值期权的价格,并继续保留奇数与偶数步数的分组。

# 中间量计算:按照前面的参数和公式整理数值结果
itm_option = EuropeanOption.put(spot=8.0, strike=10.0, maturity=1.0)
bs_itm = black_scholes_formula(
    convergence_model.volatility,
    itm_option.spot,
    itm_option.strike,
    itm_option.maturity,
    convergence_model.rate,
    itm_option.cp,
)
crr_itm_prices = np.array(
    [
        european_crr_price(
            convergence_model,
            itm_option,
            replace(settings, n_steps=int(steps)),
        )
        for steps in convergence_steps
    ]
)
crr_itm_errors = np.abs(crr_itm_prices - bs_itm)

图 2.9 显示,即使仅选取 \(n\) 为奇数还是偶数,CRR 二叉树的期权价格估计还是会随着 n 的增加在 Black-Scholes价格上下震荡。。

# 图 2.9:CRR 实值欧式看跌期权价格的奇偶步收敛
plot_crr_price_convergence(convergence_steps, crr_itm_prices, bs_itm)

图 2.9 对应不同步数的 CRR 二叉树得到的实值欧式看跌期权价格。期权参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.9 对应不同步数的 CRR 二叉树得到的实值欧式看跌期权价格。期权参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

图 2.10 显示 CRR 二叉树收敛速度确实仍为 \(1/n\),但误差的收敛非常不稳定。

# 图 2.10:CRR 二叉树实值欧式看跌期权误差的收敛,同时显示奇数和偶数步数的结果
fig, ax = plt.subplots(figsize=(8.0, 5.2))
ax.loglog(
    convergence_steps[odd_mask],
    crr_itm_errors[odd_mask],
    ":",
    linewidth=1.2,
    color="black",
    label="CRR 误差:奇数 n",
)
ax.loglog(
    convergence_steps[even_mask],
    crr_itm_errors[even_mask],
    "-",
    linewidth=1.2,
    color="tab:red",
    label="CRR 误差:偶数 n",
)
ax.loglog(
    convergence_steps,
    crr_itm_errors[0] * (convergence_steps[0] / convergence_steps),
    "--",
    color="tab:blue",
    linewidth=1.2,
    label="$1/n$",
)
ax.set_xlabel("二叉树步数 $n$")
ax.set_ylabel("价格绝对误差")
ax.set_title("CRR 二叉树实值期权误差")
ax.legend(frameon=False)
ax.grid(True, which="both", alpha=0.25)
fig.tight_layout()
plt.show()

图 2.10 黑色点线和红色实线分别表示奇数和偶数步数下的实值欧式看跌期权绝对误差。蓝色虚线向 0 的收敛速度为 $1/n$。期权参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.10 黑色点线和红色实线分别表示奇数和偶数步数下的实值欧式看跌期权绝对误差。蓝色虚线向 0 的收敛速度为 \(1/n\)。期权参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

CRR 二叉树定价的误差来自两个方面:

  1. BSM 模型假设资产的对数收益服从正态分布,CRR 二叉树用离散的二项分布来近似正态分布。
  2. 二叉树在期权到期日的节点 \(S_{n,i},i=1,\ldots,n+1\) 和期权行权价 \(K\) 的相互影响。

第一种误差可以通过增加二叉树步数 \(n\) 来降低;根据中心极限定理,当 \(n\rightarrow\infty\) 时,树上的对数收益分布收敛于相应的正态分布。而图 2.7 和图 2.9 显示,平值期权的第二种误差更小。

图 2.11 给出了一个简单的例子。在欧式看跌期权 \(S_0=8,T=1,\sigma=0.3,r=6\%\) 的 2 期和 4 期二叉树中,对于平值期权,当 \(n\) 为偶数(2 和 4)时,\(K=S_0=8\) 总是落在二叉树上。然而对于实值期权 \(K=10\),当 \(n=2\) 时,\(K\) 落在两个节点 8 和 12.23 中央,而当 \(n=4\) 时,\(K\) 离节点 10.80 的距离约为 0.80,小于到节点 8 的距离 2。也就是说,对于非平值期权,\(n\) 的变化会影响 \(K\) 在二叉树节点间的相对位置,这产生了二叉树价格误差的震荡。

行权价之所以对误差有明显影响,是因为看跌期权的到期收益 \((K-S)^+\) 在 \(S=K\) 处有一个折点:左侧斜率为 \(-1\),右侧斜率为 0。树用离散节点上的收益及其概率权重计算期望。步数改变时,折点附近有哪些节点、这些节点分布在折点的哪一侧都会变化,因而可能使误差上下波动。

2 期和 4 期 CRR 二叉树。

图 2.11 2 期和 4 期 CRR 二叉树。期权参数为 \(S_0=8,T=1,\sigma=0.3,r=6\%\)。

在 Cox–Ross–Rubinstein(1979)提出二叉树法定价期权后,有很多研究人员提出了对二叉树的改进,比如 Broadie 和 Detemple(1996)、Leisen 和 Reimer(1996)、Tian(1993,1999)、Chung 和 Shih(2007)、Boyle(1986)以及 Kamrad 和 Ritchken(1991)。此外,Joshi(2009)比较了各种二叉树定价美式期权的表现,而 Chan 等(2009)比较了各种三叉树。在下面的章节中我们着重介绍其中三种改进:Tian(1999)提出的柔性二叉树,Broadie 和 Detemple(1996)提出的二叉 Black–Scholes 树,以及 Boyle(1986)提出的三叉树。

2.2 柔性二叉树

为改善 CRR 二叉树收敛中的震荡,Tian(1999)提出构建柔性二叉树(flexible binomial tree),使得在期权到期日 \(T\) 时行权价 \(K\) 总是落在二叉树上。由于 CRR 二叉树的条件 \(ud = 1\) 并非必要条件,所以 Tian(1999) 提出舍弃这一条件,而是引入倾斜参数(tilt parameter)\(\lambda\),将 CRR 树的上涨和下跌因子同时乘以 \(e^{\lambda\sigma^2h}\),从而平移终端节点,使一个节点落在行权价 \(K\) 上。调整后的上涨、下跌因子及风险中性概率为

\[ u=e^{\sigma\sqrt h+\lambda\sigma^2h},\qquad d=e^{-\sigma\sqrt h+\lambda\sigma^2h},\qquad p=\frac{e^{rh}-d}{u-d}. \tag{2.2.1} \]

当 \(\lambda=0\) 时,柔性二叉树简化为 CRR 二叉树。而当 \(\lambda>0\) 时,二叉树上的资产价格会比 CRR 二叉树上的价格更高;相反,当 \(\lambda<0\) 时,二叉树上的资产价格会比 CRR 二叉树上的价格更低(比如图 2.11 和图 2.12 分别展示了 \(\lambda=0\) 和 \(\lambda<0\) 的 4 期二叉树)。

从对数股价看,倾斜参数使上涨和下跌的对数因子同时增加 \(\lambda\sigma^2h\),两者之间的距离仍为 \(\log u-\log d=2\sigma\sqrt h\)。经过 \(k\) 步后,该层节点相对于 CRR 网格整体平移了 \(k\lambda\sigma^2h\)。上涨概率随后按等式 (2.2.1) 重新计算,使调整后的节点仍满足条件均值 \(E[S_{k+1}\mid S_k]=S_ke^{rh}\)。

2.2.1 欧式期权

定价欧式期权时,需要选取合适的 \(\lambda\) 使得在期权到期日,行权价正好落在二叉树上。为了找到合适的 \(\lambda\),首先考虑对应 \(\lambda=0\) 的 CRR 二叉树。记 \(u_0\) 和 \(d_0\) 为 CRR 二叉树向上和向下跳跃的大小(见等式 (2.1.4) 和等式 (2.1.5))。记 \(j\) 为向上移动的次数,对应第 \(j+1\) 个节点。在期权到期日 \(T\),标的资产价格为

\[ S_{n,j+1}=S_0u_0^jd_0^{n-j},\quad 0\leq j\leq n. \tag{2.2.2} \]

对于行权价为 \(K\) 的期权,先找到在 \(T\) 时对数股价最接近 \(\log K\) 的节点 \(j(K)\),满足

\[ j(K)=\arg\min_\eta\left|\log(S_0u_0^\eta d_0^{n-\eta})-\log K\right|. \tag{2.2.3} \]

因为 \(\log S_{n,j+1}\) 是 \(j\) 的线性函数,所以不难得到 \(j(K)\) 是离

\[ \frac{\log(K/S_0)-n\log(d_0)}{\log(u_0/d_0)} \tag{2.2.4} \]

最近的整数。然后选择 \(\lambda\) 代入等式 (2.2.1),使得

\[ S_0u^{j(K)}d^{n-j(K)}=K, \tag{2.2.5} \]

从而得到

\[ \lambda=\frac{\log(K/S_0)-(2j(K)-n)\sigma\sqrt h}{n\sigma^2h}. \tag{2.2.6} \]

等式 (2.2.3)–(2.2.6) 可以理解为两个连续步骤:先在原来的 CRR 终端网格上,找到对数股价最接近 \(\log K\) 的节点;再计算把这个节点移动到 \(K\) 所需的倾斜量。这样,到期收益的折点就对应一个明确的终端节点。

程序 2.6 根据标的资产价格 \(S_0\)、波动率 \(\sigma\)、无风险利率 \(r\)、期权到期日 \(T\)、行权价 \(K\) 和二叉树步数 \(n\),计算柔性二叉树上标的资产上涨的概率 \(p\),以及用于计算标的资产在时间 \(0,h,2h,\ldots,nh\) 的价格(见等式 (2.1.3))所需的 \(u^i,d^i\),其中 \(i=0,1,\ldots,n\)。

公式与代码对应

base_up 和 base_down 对应原 CRR 树的 \(u_0\)、\(d_0\);strike_index 对应选中的终端节点编号 \(j(K)\);tilt 对应等式 (2.2.6) 的倾斜参数 \(\lambda\)。

up 和 down 是调整后的 \(u\)、\(d\),up_probability 是重新计算的风险中性概率 \(p\)。返回的两个幂次数组沿用程序 2.1 的排列顺序。

Python程序 2.6:柔性二叉树参数生成函数

继续考虑参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\) 的看跌实值期权和相应的 4 期二叉树。根据等式 (2.2.6) 可以推出 \(j(K)=3,\lambda = -0.8540\)。由此生成的柔性二叉树见图 2.12。与图 2.11 中的 4 期 CRR 二叉树比较,由于 \(\lambda<0\),所以柔性二叉树上的资产价格会比 CRR 二叉树上的价格更低,并且其中的第四个节点正好等于 \(K=10\)。

4 期柔性二叉树。

图 2.12 4 期柔性二叉树。参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

欧式期权的柔性二叉树定价可以由程序 2.7 实现。

Python程序 2.7:欧式柔性二叉树定价函数

柔性二叉树收敛实验使用偶数步数 \(n=50,52,\ldots,500\)。下面计算柔性二叉树和 CRR 二叉树的价格,并同时计算柔性二叉树相对于 Black–Scholes 价格的绝对误差。

# 中间量计算:计算柔性树、CRR树和Black–Scholes基准价格
flexible_steps = np.arange(50, 501, 2)
flexible_prices = np.array([
    european_flexible_binomial_price(convergence_model, itm_option, replace(settings, n_steps=int(steps)))
    for steps in flexible_steps
])
crr_flexible_prices = np.array([
    european_crr_price(convergence_model, itm_option, replace(settings, n_steps=int(steps)))
    for steps in flexible_steps
])
flexible_bs = black_scholes_formula(
    convergence_model.volatility, itm_option.spot, itm_option.strike,
    itm_option.maturity, convergence_model.rate, itm_option.cp,
)
flexible_errors = np.abs(flexible_prices - flexible_bs)

下面另外计算包含奇数步数的柔性树价格,用于绘制误差收敛图;价格图仍使用前一个单元中的偶数步数序列。

# 中间量计算:计算含奇数步数的柔性树误差,用于误差收敛图
flexible_error_steps = np.arange(51, 501)
flexible_error_prices = np.array([
    european_flexible_binomial_price(convergence_model, itm_option, replace(settings, n_steps=int(steps)))
    for steps in flexible_error_steps
])
flexible_error_values = np.abs(flexible_error_prices - flexible_bs)

图 2.13 显示定价实值看跌期权时,虽然柔性二叉树并不能完全做到单调收敛至 Black-Scholes 价 格,但显然比 CRR 二叉树要平滑的多。此外,与 CRR 二叉树得到的价格在 Black-Scholes 价格上下震荡不同,柔性二叉树总是低估期权价格,且误差要大于 CRR 二叉树。

# 图 2.13:对应不同偶数步数的柔性二叉树得到的实值欧式看跌期权价格
fig, ax = plt.subplots(figsize=(8.0, 5.0))
ax.plot(
    flexible_steps,
    crr_flexible_prices,
    color="black",
    linestyle=":",
    label="CRR 价格",
)
ax.plot(
    flexible_steps,
    flexible_prices,
    color="red",
    label="柔性二叉树价格",
)
ax.axhline(
    flexible_bs,
    color="blue",
    linestyle="--",
    label="Black–Scholes 价格",
)
ax.set_xlabel("二叉树步数 $n$")
ax.set_ylabel("欧式看跌期权价格")
ax.set_title("柔性二叉树实值期权价格收敛")
ax.legend(frameon=False)
ax.grid(True, alpha=0.25)
fig.tight_layout()
plt.show()

图 2.13 对应不同步数(仅取偶数)的柔性二叉树得到的实值欧式看跌期权价格。期权参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.13 对应不同步数(仅取偶数)的柔性二叉树得到的实值欧式看跌期权价格。期权参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

图 2.14 显示柔性二叉树的误差按 \(O(1/n)\) 收敛。

# 图 2.14:柔性二叉树实值欧式看跌期权误差的收敛
fig, ax = plt.subplots(figsize=(8.0, 5.0))
ax.loglog(
    flexible_error_steps,
    flexible_error_values,
    color="red",
    linewidth=1.0,
    label="柔性二叉树误差",
)
ax.loglog(
    flexible_error_steps,
    flexible_error_values[0]
    * (flexible_error_steps[0] / flexible_error_steps),
    "--",
    color="blue",
    label="$1/n$",
)
ax.set_xlabel("二叉树步数 $n$")
ax.set_ylabel("价格绝对误差")
ax.set_title("柔性二叉树实值期权误差")
ax.legend(frameon=False)
ax.grid(True, which="both", alpha=0.25)
fig.tight_layout()
plt.show()

图 2.14 红色实线:对应不同步数 $n$ 的柔性二叉树得到的实值欧式看跌期权误差。蓝色虚线向 0 的收敛速度为 $1/n$。期权参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.14 红色实线:对应不同步数 \(n\) 的柔性二叉树得到的实值欧式看跌期权误差。蓝色虚线向 0 的收敛速度为 \(1/n\)。期权参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

2.2.2 Richardson 外推法

图 2.13 中,柔性二叉树的价格曲线较为平滑,这有利于通过外推抵消主导误差。柔性二叉树可以结合 Richardson 外推法(Extrapolation)显著降低期权价格估计的误差(可参看 Chang 等(2007))。记 \(V_n\) 和 \(V_{n/2}\) 分别为基于步数 \(n\)(必须为偶数)和 \(n/2\) 的二叉树期权价格估计,则

\[ V_n^{RE}=2V_n-V_{n/2}. \tag{2.2.7} \]

Richardson 外推利用两种步数下的价格估计抵消主要误差。设真实价格为 \(V\),并假设所比较的两种步数具有相同的主导误差系数 \(a\),则可以写成

$$

\[\begin{aligned} V_n&=V+\frac{a}{n}+O(n^{-2}),\\ V_{n/2}&=V+\frac{2a}{n}+O(n^{-2}),\\ 2V_n-V_{n/2}&=V+O(n^{-2}). \end{aligned}\]

$$

将这两个展开代入等式 (2.2.7),\(a/n\) 项恰好抵消,剩余误差为 \(O(n^{-2})\)。

对于欧式期权,Richardson 外推由 Python 程序 2.8 实现。

公式与代码对应

value_n 和 value_n_over_2 分别对应等式 (2.2.7) 中步数为 \(n\) 和 \(n/2\) 时的价格估计 \(V_n\)、\(V_{n/2}\);返回值对应 \(V_n^{RE}\)。

Python程序 2.8:Richardson外推计算

下面在偶数步数 \(n=50,52,\ldots,500\) 上分别计算柔性二叉树、CRR 二叉树以及各自的 Richardson 外推价格。

# 中间量计算:计算柔性树和CRR树的基础价格
richardson_steps = np.arange(50, 501, 2)
flexible_base_prices = np.array([
    european_flexible_binomial_price(convergence_model, itm_option, replace(settings, n_steps=int(steps)))
    for steps in richardson_steps
])
crr_base_prices = np.array([
    european_crr_price(convergence_model, itm_option, replace(settings, n_steps=int(steps)))
    for steps in richardson_steps
])

基础树价格计算完毕后,对两种二叉树分别应用 Richardson 外推公式。

# 中间量计算:计算柔性树和CRR树的Richardson外推价格
flexible_half_prices = np.array([
    european_flexible_binomial_price(
        convergence_model, itm_option, replace(settings, n_steps=int(steps // 2))
    )
    for steps in richardson_steps
])
crr_half_prices = np.array([
    european_crr_price(
        convergence_model, itm_option, replace(settings, n_steps=int(steps // 2))
    )
    for steps in richardson_steps
])
flexible_re_prices = richardson_extrapolation(
    flexible_base_prices, flexible_half_prices
)
crr_re_prices = richardson_extrapolation(crr_base_prices, crr_half_prices)

图 2.15 比较柔性二叉树价格和 Richardson 外推价格。外推后的价格更接近 Black–Scholes 价格。

# 图 2.15:柔性二叉树加 Richardson 外推法得到的实值欧式看跌期权价格
fig, ax = plt.subplots(figsize=(8.0, 5.0))
ax.plot(
    richardson_steps,
    flexible_base_prices,
    color="black",
    linestyle=":",
    label="柔性二叉树价格",
)
ax.plot(
    richardson_steps,
    flexible_re_prices,
    color="red",
    label="柔性树 + Richardson 外推",
)
ax.axhline(
    flexible_bs,
    color="blue",
    linestyle="--",
    label="Black–Scholes 价格",
)
ax.set_xlabel("二叉树步数 $n$")
ax.set_ylabel("欧式看跌期权价格")
ax.set_title("柔性二叉树 Richardson 外推")
ax.legend(frameon=False)
ax.grid(True, alpha=0.25)
fig.tight_layout()
plt.show()

图 2.15 对应不同步数的柔性二叉树 + Richardson 外推法得到的实值欧式看跌期权价格。期权参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.15 对应不同步数的柔性二叉树 + Richardson 外推法得到的实值欧式看跌期权价格。期权参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

虽然 CRR 二叉树也可以结合 Richardson 外推法,但由于 CRR 二叉树收敛不平滑,所以使用 Richardson 外推法不但不能提高期权价格估计的精确度,反而会引起更多震荡,见图 2.16。

# 图 2.16:CRR 二叉树加 Richardson 外推法得到的实值欧式看跌期权价格。CRR 的误差系数随网格位置变化,外推价格也呈现震荡
fig, ax = plt.subplots(figsize=(8.0, 5.0))
ax.plot(
    richardson_steps,
    crr_base_prices,
    color="black",
    linestyle=":",
    label="CRR 价格",
)
ax.plot(
    richardson_steps,
    crr_re_prices,
    color="red",
    label="CRR + Richardson 外推",
)
ax.axhline(
    flexible_bs,
    color="blue",
    linestyle="--",
    label="Black–Scholes 价格",
)
ax.set_xlabel("二叉树步数 $n$")
ax.set_ylabel("欧式看跌期权价格")
ax.set_title("CRR 二叉树 Richardson 外推")
ax.legend(frameon=False)
ax.grid(True, alpha=0.25)
fig.tight_layout()
plt.show()

图 2.16 对应不同步数的 CRR 二叉树 + Richardson 外推法得到的实值欧式看跌期权价格。期权参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.16 对应不同步数的 CRR 二叉树 + Richardson 外推法得到的实值欧式看跌期权价格。期权参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

2.2.3 美式期权

柔性二叉树同样适用于美式期权,见程序 2.9。

Python程序 2.9:美式柔性二叉树定价函数

下面将前文参数为 \(S_0=8,K=10,T=1\) 的看跌期权改为美式期权。取偶数步数 \(n=50,52,\ldots,500\) 计算柔性二叉树价格和 Richardson 外推价格,并以 \(n=20000\) 的 Boyle 三叉树价格作为数值近似基准。Boyle 三叉树定价方法见第 2.4.2 节。

# 参数定义:与欧式看跌期权相同参数的美式看跌期权
american_put_option = AmericanOption.put(
    spot=itm_option.spot,
    strike=itm_option.strike,
    maturity=itm_option.maturity,
)
# 中间量计算:按照前面的参数和公式整理数值结果
flexible_american_prices = np.array([
    american_flexible_binomial_price(
        convergence_model, american_put_option, replace(settings, n_steps=int(steps))
    )
    for steps in richardson_steps
])
flexible_american_half_prices = np.array([
    american_flexible_binomial_price(
        convergence_model, american_put_option, replace(settings, n_steps=int(steps // 2))
    )
    for steps in richardson_steps
])
flexible_american_re_prices = richardson_extrapolation(
    flexible_american_prices, flexible_american_half_prices
)
from quant_option_pricing.trees import (
    american_boyle_trinomial_price as boyle_reference_price,
)
boyle_american_reference = boyle_reference_price(
    convergence_model,
    american_put_option,
    replace(settings, n_steps=20000),
)

pd.Series({
    "Boyle 基准(20000 步)": boyle_american_reference,
})
Boyle 基准(20000 步)    2.103992
dtype: float64

图 2.17 展示本例美式看跌期权的柔性二叉树价格,以及 Richardson 外推后的价格。外推曲线更接近高步数数值基准,体现了主导误差抵消带来的显著精度改善。

# 图 2.17:柔性二叉树加 Richardson 外推法得到的实值美式看跌期权价格
fig, ax = plt.subplots(figsize=(8.0, 5.0))
ax.plot(
    richardson_steps,
    flexible_american_prices,
    color="magenta",
    linestyle=":",
    label="柔性二叉树价格",
)
ax.plot(
    richardson_steps,
    flexible_american_re_prices,
    color="red",
    label="柔性树 + Richardson 外推",
)
ax.axhline(
    boyle_american_reference,
    color="blue",
    linestyle="--",
    label="数值基准:Boyle 三叉树",
)
ax.set_xlabel("二叉树步数 $n$")
ax.set_ylabel("美式看跌期权价格")
ax.set_title("柔性二叉树 Richardson 外推的美式期权价格")
ax.legend(frameon=False)
ax.grid(True, alpha=0.25)
fig.tight_layout()
plt.show()

图 2.17 对应不同步数的柔性二叉树 + Richardson 外推法得到的实值美式看跌期权价格。期权参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.17 对应不同步数的柔性二叉树 + Richardson 外推法得到的实值美式看跌期权价格。期权参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

2.3 美式期权定价的二叉 Black–Scholes 树

Broadie 和 Detemple(1996)提出在定价美式期权时,在二叉树的倒数第二步时期权的持有价值可以由 Black-Scholes 公式给出,再与立即行权收益比较。这一方法被称为 Binomial Black-Scholes Tree,它的优点在于通过平滑终端收益的折点,减轻第 2.1.4 节中行权价与终端节点相对位置造成的误差,从而使得二叉树在步数增加时得到的期权价格收敛更平滑。

程序 2.10 将二叉 Black-Scholes 树与 CRR 二叉树结合定价美式期权。

公式与代码对应

初始化时,stock_prices 保存时间 \(T-h\) 的 \(n\) 个股价节点;time_step 对应这时的剩余期限 \(h\),作为期限参数传入 black_scholes_formula。

values 先保存这些节点的 Black–Scholes 持有价值,与立即行权收益逐项比较后,成为时间 \(T-h\) 的美式期权价值。随后循环从这一层继续向前回溯。

Python程序 2.10:美式期权的平滑 CRR 二叉树定价

平滑二叉树收敛实验使用偶数步数 \(n=50,52,\ldots,500\)。

# 图 2.18:计算普通和平滑 CRR 二叉树的价格序列
smooth_steps = np.arange(50, 501, 2)
crr_american_prices = np.array([
    american_crr_price(
        convergence_model, american_put_option, replace(settings, n_steps=int(steps))
    )
    for steps in smooth_steps
])
smoothed_crr_american_prices = np.array([
    smoothed_crr_american_price(
        convergence_model, american_put_option, replace(settings, n_steps=int(steps))
    )
    for steps in smooth_steps
])

图 2.18 比较本例实值美式看跌期权的普通 CRR 树和平滑 CRR 树,参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

  1. 基准采用 \(n=20000\) 的 Boyle 三叉树数值近似,方法见第 2.4 节。
  2. 普通 CRR 二叉树得到的价格随着步数 \(n\) 的增加上下震荡,这与其定价欧式期权的表现类似。
  3. 平滑 CRR 二叉树定价误差比普通二叉树明显小得多,特别是当\(n > 200\) 时
# 图 2.18:普通 CRR 二叉树和平滑 CRR 二叉树定价实值美式看跌期权的比较

fig, ax = plt.subplots(figsize=(8.0, 5.0))
ax.plot(
    smooth_steps,
    crr_american_prices,
    color="black",
    linestyle=":",
    label="CRR 价格",
)
ax.plot(
    smooth_steps,
    smoothed_crr_american_prices,
    color="red",
    label="平滑 CRR 价格",
)
ax.axhline(
    boyle_american_reference,
    color="blue",
    linestyle="--",
    label="数值基准:Boyle 三叉树 20000 步",
)
ax.set_xlabel("二叉树步数 $n$")
ax.set_ylabel("美式看跌期权价格")
ax.set_title("普通和平滑 CRR 二叉树")
ax.legend(frameon=False)
ax.grid(True, alpha=0.25)
fig.tight_layout()
plt.show()

图 2.18 对应不同步数(仅取偶数)的平滑CRR二叉树得到的实值美式看跌期权价格。期权参数为$S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.18 对应不同步数(仅取偶数)的平滑CRR二叉树得到的实值美式看跌期权价格。期权参数为\(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

二叉 Black–Scholes 树也可以和柔性二叉树结合,见程序 2.11。

Python程序 2.11:美式期权的平滑柔性二叉树定价

下面沿用上一实验的参数和偶数步数\(n=50,52,\ldots,500\),只把平滑处理应用到柔性二叉树。

# 图 2.19:计算平滑柔性二叉树的价格序列
smoothed_flexible_american_prices = np.array([
    smoothed_flexible_american_price(
        convergence_model, american_put_option, replace(settings, n_steps=int(steps))
    )
    for steps in smooth_steps
])

图 2.19 显示平滑后的柔性二叉树的误差比平滑前更小。与平滑 CRR 二叉树相比,平滑后的柔性二叉树的误差非常接近,但从收敛的平滑程度来说存在多处跳跃。

# 图 2.19:平滑柔性二叉树得到的实值美式看跌期权价格

fig, ax = plt.subplots(figsize=(8.0, 5.0))
ax.plot(
    smooth_steps,
    smoothed_crr_american_prices,
    color="black",
    label="平滑 CRR 价格",
)
ax.plot(
    smooth_steps,
    flexible_american_prices,
    color="magenta",
    linestyle=":",
    label="柔性二叉树价格",
)
ax.plot(
    smooth_steps,
    smoothed_flexible_american_prices,
    color="red",
    marker="o",
    markersize=2.0,
    label="平滑柔性树价格",
)
ax.axhline(
    boyle_american_reference,
    color="blue",
    linestyle="--",
    label="数值基准:Boyle 三叉树 20000 步",
)
ax.set_xlabel("二叉树步数 $n$")
ax.set_ylabel("美式看跌期权价格")
ax.set_title("平滑柔性二叉树")
ax.legend(frameon=False)
ax.grid(True, alpha=0.25)
fig.tight_layout()
plt.show()

图 2.19 对应不同步数(仅取偶数)的平滑柔性二叉树得到的实值美式看跌期权价格。期权参数为$S_0=8,K=10,T=1,\sigma=0.3,r=6\%$

图 2.19 对应不同步数(仅取偶数)的平滑柔性二叉树得到的实值美式看跌期权价格。期权参数为\(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)

平滑 CRR 二叉树与平滑柔性二叉树的曲线几乎重合。在本例中,应用 Black–Scholes 平滑后,将行权价放在到期节点上带来的额外精度提升较小。这两种改进主要针对同一个误差来源:到期看跌期权收益 \(g(S)=(K-S)^+\) 在行权价处的折点。

行权价对齐调整了到期节点对这一折点的取样位置。Black–Scholes 平滑则在倒数第二层,即时间 \(T-h\),使用解析的继续持有价值:

\[ V_{n-1}(S)=\max\left\{(K-S)^+,P_{\mathrm{BS}}(S,K,h)\right\}, \]

其中,\(P_{\mathrm{BS}}(S,K,h)\) 表示剩余期限为 \(h\) 的欧式看跌期权价值。该公式对最后一期的股价分布进行积分,替代了用两个后继节点近似到期收益的计算。因此,行权价对齐所针对的大部分误差已经由平滑处理消除。

2.4 Boyle 三叉树

Boyle(1986)提出三叉树,通过三个分支同时匹配股价的条件均值和条件二阶矩,以改善定价精度。在三叉树上,若在时间 \(kh\) 股票价格为 \(S_k\),则在时间 \((k+1)h\) 的股票价格有三种可能:

  1. 以概率 \(p_u\) 上涨至 \(uS_k\);
  2. 以概率 \(p_d\) 下跌到 \(dS_k\);
  3. 以概率 \(p_m=1-p_u-p_d\) 变化为 \(mS_k\),

其中 \(u>m>d\)。若想生成如图 2.20 所示的重新连接三叉树,则需要满足

\[ ud=m^2. \tag{2.4.1} \]

同样步数 \(n\) 下,二叉树在到期日有 \(n+1\) 个节点,三叉树有 \(2n+1\) 个节点;每个回溯节点分别计算两个和三个后继节点的贴现期望,因此三叉树的计算量较大。

n 期 Boyle 三叉树节点。

图 2.20 \(n\)-期 Boyle 三叉树节点。

如图 2.20 所示的三叉树上,若向上的分叉表示股价下降,则时间 \(kh\) 的节点由表 2.5 给出。

节点 节点取值
\(S_{k,1}\) \(S_0 d^k u^0\)
\(S_{k,2}\) \(S_0 d^{k-1} u^0\)
\(S_{k,3}\) \(S_0 d^{k-1} u^1\)
\(S_{k,4}\) \(S_0 d^{k-2} u^1\)
\(S_{k,5}\) \(S_0 d^{k-2} u^2\)
\(\vdots\) \(\vdots\)
\(S_{k,2k-1}\) \(S_0 d^1 u^{k-1}\)
\(S_{k,2k}\) \(S_0 d^0 u^{k-1}\)
\(S_{k,2k+1}\) \(S_0 d^0 u^k\)

表 2.5 三叉树在时间 \(kh\) 时股价的取值。

下面先根据这些公式计算一步三叉树的参数。

给定时间 \(kh\) 的股价 \(S_k\),下一期股价分别以概率 \(p_u,p_d,p_m\) 取值 \(uS_k,dS_k,mS_k\)。因此,条件均值是这三个可能股价按概率加权的平均;条件二阶矩则先将每个可能股价平方,再按相同概率加权。将这两个条件矩与风险中性几何布朗运动的一步条件矩匹配,Boyle 三叉树的参数 \(u,d,p_u,p_d\) 需满足:

\[ p_uuS_k+p_ddS_k+(1-p_u-p_d)mS_k=S_kM \tag{2.4.2} \]

\[ p_uu^2S_k^2+p_dd^2S_k^2+(1-p_u-p_d)m^2S_k^2=S_k^2M^2\Psi \tag{2.4.3} \]

\[ ud=m^2. \tag{2.4.4} \]

其中

\[ M=e^{rh},\qquad \Psi=e^{\sigma^2h}. \tag{2.4.5} \]

等式 (2.4.2) 左侧是上述条件均值,右侧 \(S_kM\) 与等式 (2.1.7) 给出的风险中性几何布朗运动条件均值相同;等式 (2.4.3) 左侧是上述条件二阶矩,右侧 \(S_k^2M^2\Psi\) 与等式 (2.1.8) 给出的条件二阶矩相同。由于条件方差等于条件二阶矩减去条件均值的平方,下一期股价的条件方差为 \(S_k^2M^2(\Psi-1)\)。

三叉树在给定三个节点位置后,可以通过分配上、中、下三个概率,同时满足概率总和为 1、条件均值匹配和条件二阶矩匹配。令中间因子 \(m=1\),即中间分支保持股价不变,再结合重新连接条件 \(ud=1\)。在这一设置下,求解等式 (2.4.2)–(2.4.4) 得到

\[ m=1, \qquad p_u=\frac{md-M(m+d)+M^2\Psi}{(u-d)(u-m)}, \tag{2.4.6} \]

\[ p_d=\frac{um-M(u+m)+M^2\Psi}{(u-d)(m-d)}, \qquad p_m=1-p_u-p_d. \tag{2.4.7} \]

但满足等式 (2.4.2)–(2.4.4) 的 \(u\) 和 \(d\) 的选择并不唯一。如果使用 CRR 二叉树的选择 \(u=e^{\sigma\sqrt h}\),很多情况下会出现 \(p_m<0\)。为避免这个问题,Boyle 引入额外参数 \(\lambda\) 使得

\[ u=e^{\lambda\sigma\sqrt h},\qquad d=e^{-\lambda\sigma\sqrt h}, \tag{2.4.8} \]

并推荐使用 \(\lambda=1.2\)。

参数 \(\lambda\) 控制上下节点离中间节点的距离:\(\lambda\) 增大时,上下两个可能价格之间的间距增大,三个分支的概率随之重新分配,以保持给定的条件均值和条件方差。选择间距时,还需要使三个概率都落在 \([0,1]\) 内。第 2.2 节同样使用符号 \(\lambda\),其作用是整体倾斜二叉树网格;这里的作用是调整三叉树的分支间距。

程序2.12 根据上述条件生成 Boyle 三叉树,在定价欧式和美式期权时可以调用。

公式与代码对应

growth 对应 \(M=e^{rh}\),variance_growth 对应 \(\Psi=e^{\sigma^2h}\),middle 对应 \(m=1\);spacing 对应等式 (2.4.8) 的间距参数 \(\lambda\)。

p_up 和 p_down 对应 \(p_u\) 和 \(p_d\)。up_exponents、down_exponents 保存表 2.5 中 \(u\) 和 \(d\) 的指数;返回的幂次数组逐项相乘并乘以 \(S_0\),得到从低到高排列的 \(2n+1\) 个终端股价。

Python程序 2.12:Boyle三叉树参数生成函数

取本章默认参数 \(T=0.5,\sigma=0.2,r=6\%,n=100\) 和 \(\lambda=1.2\),调用程序 2.12 计算 Boyle 三叉树的上行和下行概率。

# 中间量计算:调用程序 2.12 获取 Boyle 三叉树的上行和下行概率
_, _, boyle_up_probability, boyle_down_probability, _ = boyle_tree_parameters(
    model, option.maturity, settings.n_steps, settings.trinomial_lambda
)

程序 2.12 返回 \(p_u\) 和 \(p_d\);根据等式 (2.4.7),中间分支的概率为 \(p_m=1-p_u-p_d\)。下面列出三个概率。

# 结果输出:Boyle 三叉树三个分支的风险中性概率
boyle_middle_probability = 1.0 - boyle_up_probability - boyle_down_probability
pd.Series(
    {
        "p_d": boyle_down_probability,
        "p_m": boyle_middle_probability,
        "p_u": boyle_up_probability,
    }
)
p_d    0.341572
p_m    0.305073
p_u    0.353355
dtype: float64

2.4.1 欧式期权

使用 Boyle 三叉树计算欧式期权时,在到期日生成 \(2n+1\) 个收益,然后从后向前计算三个相邻节点的贴现风险中性期望。这可由程序2.13 实现。

公式与代码对应

p_middle 对应 \(p_m=1-p_u-p_d\)。在从第 \(i\) 层回溯到第 \(i-1\) 层时,values[:2*i-1]、values[1:2*i] 和 values[2:2*i+1] 分别提供各节点的下行、中间和上行后继价值。加权贴现后,节点数从 \(2i+1\) 减为 \(2i-1\)。

Python程序 2.13:欧式 Boyle 三叉树定价函数

Boyle 三叉树收敛实验使用平值期权参数 \(S_0=K=10,T=1,\sigma=0.3,r=6\%\),并取偶数步数 \(n=50,52,\ldots,500\)。

下面用同一组平值参数计算价格,并同时保留 CRR 二叉树价格和 Black–Scholes 基准价格。

# 中间量计算:按照前面的参数和公式整理数值结果
trinomial_steps = np.arange(50, 501, 2)
boyle_atm_prices = np.array(
    [
        european_boyle_trinomial_price(
            convergence_model,
            atm_option,
            replace(settings, n_steps=int(steps)),
        )
        for steps in trinomial_steps
    ]
)
crr_atm_trinomial_prices = np.array(
    [
        european_crr_price(
            convergence_model,
            atm_option,
            replace(settings, n_steps=int(steps)),
        )
        for steps in trinomial_steps
    ]
)
boyle_atm_bs = black_scholes_formula(
    convergence_model.volatility,
    atm_option.spot,
    atm_option.strike,
    atm_option.maturity,
    convergence_model.rate,
    atm_option.cp,
)
crr_atm_errors = np.abs(crr_atm_trinomial_prices - boyle_atm_bs)
boyle_atm_errors = np.abs(boyle_atm_prices - boyle_atm_bs)

图 2.21 使用本例平值欧式看跌期权参数 \(S_0=K=10,T=1,\sigma=0.3,r=6\%\),比较偶数步数下的树价格。在这组参数下,Boyle 树的表现相当优秀:当 \(n=50\) 的价格误差小于 CRR 树 \(n=500\) 的误差,并且若仅选取偶数步数 \(n\) 时, Boyle 三叉树也可以做到平滑收敛。

# 图 2.21:Boyle 三叉树平值欧式看跌期权价格。参数为 $S_0=K=10,T=1,\sigma=0.3,r=6\%$
fig, ax = plt.subplots(figsize=(8.0, 5.0))
ax.plot(
    trinomial_steps,
    crr_atm_trinomial_prices,
    color="black",
    linestyle=":",
    label="CRR 价格:偶数 n",
)
ax.plot(
    trinomial_steps,
    boyle_atm_prices,
    color="red",
    label="Boyle 三叉树:偶数 n",
)
ax.axhline(
    boyle_atm_bs,
    color="blue",
    linestyle="--",
    label="Black–Scholes 价格",
)
ax.set_xlabel("三叉树步数 $n$")
ax.set_ylabel("欧式看跌期权价格")
ax.set_title("Boyle 三叉树平值期权价格收敛")
ax.legend(frameon=False)
ax.grid(True, alpha=0.25)
fig.tight_layout()
plt.show()

图 2.21 Boyle 三叉树平值欧式看跌期权价格。参数为 $S_0=K=10,T=1,\sigma=0.3,r=6\%$。

图 2.21 Boyle 三叉树平值欧式看跌期权价格。参数为 \(S_0=K=10,T=1,\sigma=0.3,r=6\%\)。

根据图 3.22,Boyle 三叉树的收敛速度也是 \(1/n\)。

# 图 2.22:Boyle 三叉树平值欧式看跌期权误差。Boyle 三叉树的收敛速度也是 $1/n$
fig, ax = plt.subplots(figsize=(7.5, 4.2))
ax.loglog(
    trinomial_steps,
    crr_atm_errors,
    "k--",
    label="CRR 二叉树误差",
)
ax.loglog(
    trinomial_steps,
    boyle_atm_errors,
    "r-",
    label="Boyle 三叉树误差",
)
ax.loglog(
    trinomial_steps,
    boyle_atm_errors[0] * (trinomial_steps[0] / trinomial_steps),
    "b--",
    label="$1/n$",
)
ax.set_xlabel("三叉树步数 $n$")
ax.set_ylabel("价格绝对误差")
ax.set_title("Boyle 三叉树平值期权误差")
ax.legend(frameon=False)
ax.grid(True, which="both", alpha=0.25)
fig.tight_layout()
plt.show()

图 2.22 红色实线:对应不同步数 $n$ 的 Boyle 三叉树得到的平值欧式看跌期权价格误差。蓝色虚线向 0 的收敛速度为 $1/n$。期权参数为 $S_0=K=10,T=1,\sigma=0.3,r=6\%$。

图 2.22 红色实线:对应不同步数 \(n\) 的 Boyle 三叉树得到的平值欧式看跌期权价格误差。蓝色虚线向 0 的收敛速度为 \(1/n\)。期权参数为 \(S_0=K=10,T=1,\sigma=0.3,r=6\%\)。

接下来考虑实值期权,\(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\),并沿用上面的偶数步数网格。计算 Boyle 三叉树和 CRR 二叉树的价格,并以 Black–Scholes 价格作为基准。

# 中间量计算:按照前面的参数和公式整理数值结果
boyle_itm_prices = np.array(
    [
        european_boyle_trinomial_price(
            convergence_model,
            itm_option,
            replace(settings, n_steps=int(steps)),
        )
        for steps in trinomial_steps
    ]
)
crr_itm_trinomial_prices = np.array(
    [
        european_crr_price(
            convergence_model,
            itm_option,
            replace(settings, n_steps=int(steps)),
        )
        for steps in trinomial_steps
    ]
)
boyle_itm_bs = black_scholes_formula(
    convergence_model.volatility,
    itm_option.spot,
    itm_option.strike,
    itm_option.maturity,
    convergence_model.rate,
    itm_option.cp,
)
boyle_itm_errors = np.abs(boyle_itm_prices - boyle_itm_bs)
american_trinomial_steps = np.arange(50, 501, 2)

图 2.23显示:虽然三叉树估计与 CRR 二叉树一样在 Black–Scholes 价格上下震荡,但明显前者的震荡区间比后者更小,特别是当 \(n\) 较小、CRR 二叉树误差较大的时候。

# 图 2.23:Boyle 三叉树实值欧式看跌期权价格。参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$
fig, ax = plt.subplots(figsize=(8.0, 5.0))
ax.plot(
    trinomial_steps,
    crr_itm_trinomial_prices,
    color="black",
    linestyle=":",
    label="CRR 价格:偶数 n",
)
ax.plot(
    trinomial_steps,
    boyle_itm_prices,
    color="red",
    label="Boyle 三叉树价格:偶数 n",
)
ax.axhline(
    boyle_itm_bs,
    color="blue",
    linestyle="--",
    label="Black–Scholes 价格",
)
ax.set_xlabel("三叉树步数 $n$")
ax.set_ylabel("欧式看跌期权价格")
ax.set_title("Boyle 三叉树实值期权价格收敛")
ax.legend(frameon=False)
ax.grid(True, alpha=0.25)
fig.tight_layout()
plt.show()

图 2.23 Boyle 三叉树实值欧式看跌期权价格。参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.23 Boyle 三叉树实值欧式看跌期权价格。参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

图 2.24 显示 Boyle 三叉树的收敛速度仍为 \(1/n\),并且误差收敛和 CRR 二叉树一样不稳定。

# 图 2.24:Boyle 三叉树实值欧式看跌期权误差。三叉树估计的震荡区间比 CRR 二叉树小,但误差收敛仍可能不稳定
fig, ax = plt.subplots(figsize=(7.5, 4.2))
ax.loglog(
    trinomial_steps,
    boyle_itm_errors,
    "r-",
    marker=".",
    markersize=4,
    label="Boyle 误差",
)
ax.loglog(
    trinomial_steps,
    boyle_itm_errors[0] * (trinomial_steps[0] / trinomial_steps),
    "b--",
    label="$1/n$",
)
ax.set_xlabel("三叉树步数 $n$")
ax.set_ylabel("价格绝对误差")
ax.set_title("Boyle 三叉树实值期权误差")
ax.legend(frameon=False)
ax.grid(True, which="both", alpha=0.25)
fig.tight_layout()
plt.show()

图 2.24 红色实线:对应不同步数 $n$ 的 Boyle 三叉树得到的实值欧式看跌期权价格误差。蓝色虚线向 0 的收敛速度为 $1/n$。期权参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.24 红色实线:对应不同步数 \(n\) 的 Boyle 三叉树得到的实值欧式看跌期权价格误差。蓝色虚线向 0 的收敛速度为 \(1/n\)。期权参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

2.4.2 美式期权

Boyle 三叉树也可用于计算美式期权价格,见程序 2.14。每次回溯时,将三个后继节点的持有价值与当前节点的立即行权收益进行比较。

Python程序 2.14:美式 Boyle 三叉树定价函数

下面使用 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\) 和偶数步数 \(n=50,52,\ldots,500\),计算 Boyle 三叉树的美式看跌期权价格,并用 \(n=20000\) 的同一方法作为数值近似基准。

# 中间量计算:按照前面的参数和公式整理数值结果
boyle_american_prices = np.array([
    american_boyle_trinomial_price(
        convergence_model, american_put_option, replace(settings, n_steps=int(steps))
    )
    for steps in american_trinomial_steps
])
boyle_american_reference = american_boyle_trinomial_price(
    convergence_model,
    american_put_option,
    replace(settings, n_steps=settings.reference_steps),
)
boyle_american_errors = np.abs(
    boyle_american_prices - boyle_american_reference
)

图 2.25 显示Boyle 三叉树误差比 CRR 二叉树更小。

# 图 2.25:Boyle 三叉树定价实值美式看跌期权的价格
fig, ax = plt.subplots(figsize=(8.0, 5.0))
ax.plot(
    american_trinomial_steps,
    crr_american_prices,
    color="black",
    linestyle=":",
    label="CRR 价格",
)
ax.plot(
    american_trinomial_steps,
    boyle_american_prices,
    color="red",
    label="Boyle 三叉树价格",
)
ax.axhline(
    boyle_american_reference,
    color="blue",
    linestyle="--",
    label="数值基准:Boyle 三叉树 20000 步",
)
ax.set_xlabel("三叉树步数 $n$")
ax.set_ylabel("美式看跌期权价格")
ax.set_title("Boyle 三叉树美式期权价格")
ax.legend(frameon=False)
ax.grid(True, alpha=0.25)
fig.tight_layout()
plt.show()

图 2.25 对应不同步数(仅选取偶数 $n$)的 Boyle 三叉树得到的实值美式看跌期权价格。期权参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.25 对应不同步数(仅选取偶数 \(n\))的 Boyle 三叉树得到的实值美式看跌期权价格。期权参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

Boyle三叉树同样可以与Black–Scholes 树法结合定价美式期权,以改善定价收敛的平滑性。在倒数第二层使用 Black–Scholes 连续时间价格平滑 Boyle 三叉树,并在这一层比较立即行权收益,再按美式期权的回溯关系计算此前各层的价值。见程序2.15。

公式与代码对应

初始化时,down_values[2:] 与 up_values[:-2] 配合生成时间 \(T-h\) 的 \(2n-1\) 个股价节点,保存在 stock_prices 中。这些节点的剩余期限均为 time_step,即 \(h\);values 在平滑和行权比较后保存这一层的美式期权价值。

Python程序 2.15:平滑 Boyle 三叉树定价函数

下面沿用上一实验的参数和偶数步数,计算平滑 Boyle 三叉树价格,再与普通 Boyle 三叉树和同一个高步数基准比较。

# 中间量计算:按照前面的参数和公式整理数值结果
smoothed_boyle_american_prices = np.array(
    [
        smoothed_boyle_trinomial_price(
            convergence_model,
            american_put_option,
            replace(settings, n_steps=int(steps)),
        )
        for steps in american_trinomial_steps
    ]
)

根据图 2.26,平滑后的 Boyle 三叉树得到的期权价格收敛更为平滑,且误差更小。

# 图 2.26:Boyle 三叉树定价实值美式看跌期权的价格
fig, ax = plt.subplots(figsize=(8.0, 5.0))
ax.plot(
    american_trinomial_steps,
    boyle_american_prices,
    color="red",
    label="Boyle 三叉树价格",
)
ax.plot(
    american_trinomial_steps,
    smoothed_boyle_american_prices,
    color="black",
    linestyle=":",
    label="平滑 Boyle 三叉树价格",
)
ax.axhline(
    boyle_american_reference,
    color="blue",
    linestyle="--",
    label="数值基准:Boyle 三叉树 20000 步",
)
ax.set_xlabel("三叉树步数 $n$")
ax.set_ylabel("美式看跌期权价格")
ax.set_title("Boyle 三叉树美式期权价格")
ax.legend(frameon=False)
ax.grid(True, alpha=0.25)
fig.tight_layout()
plt.show()

图 2.26 对应不同步数(仅选取偶数 $n$)的平滑 Boyle 三叉树得到的实值美式看跌期权价格。期权参数为 $S_0=8,K=10,T=1,\sigma=0.3,r=6\%$。

图 2.26 对应不同步数(仅选取偶数 \(n\))的平滑 Boyle 三叉树得到的实值美式看跌期权价格。期权参数为 \(S_0=8,K=10,T=1,\sigma=0.3,r=6\%\)。

参考文献

  • Cox, J. C., Ross, S. A., & Rubinstein, M.(1979). “Option Pricing: A Simplified Approach.” Journal of Financial Economics, 7(3), 229–263.
  • Higham, D. J.(2002). “Nine Ways to Implement the Binomial Method for Option Valuation in MATLAB.” SIAM Review, 44(4), 661–677.
  • Hull, J.(2014). Options, Futures, and Other Derivatives(第 9 版). Pearson.
  • Pelsser, A., & Vorst, T. C. F.(1994). “The Binomial Model and the Greeks.” The Journal of Derivatives, 1(3), 45–49.
  • Diener, F., & Diener, M.(2004). “Asymptotics of the Price Oscillations of a European Call Option in a Tree Model.” Mathematical Finance, 14(2), 271–293.
  • Broadie, M., & Detemple, J.(1996). “American Option Valuation: New Bounds, Approximations, and a Comparison of Existing Methods.” The Review of Financial Studies, 9(4), 1211–1250.
  • Leisen, D. P., & Reimer, M.(1996). “Binomial Models for Option Valuation—Examining and Improving Convergence.” Applied Mathematical Finance, 3, 319–346.
  • Tian, Y.(1993). “A Modified Lattice Approach to Option Pricing.” Journal of Futures Markets, 13, 563–577.
  • Tian, Y.(1999). “A Flexible Binomial Option Pricing Model.” The Journal of Futures Markets, 19, 817–843.
  • Chung, S. L., & Shih, P. T.(2007). “Generalized Cox-Ross-Rubinstein Binomial Model.” Management Science, 53, 508–520.
  • Boyle, P.(1986). “Option Valuation Using a Three-Jump Process.” International Options Journal, 3, 7–12.
  • Kamrad, B., & Ritchken, P.(1991). “Multinomial Approximating Models for Options with k State Variables.” Management Science, 37(12), 1640–1652.
  • Joshi, M.(2009). “The Convergence of Binomial Trees for Pricing the American Put.” The Journal of Risk, 11(4), 87–108.
  • Chan, J. H., Joshi, M., Tang, R., & Yang, C.(2009). “Trinomial or Binomial: Accelerating American Put Option Price on Trees.” The Journal of Futures Markets, 29(9), 826–839.
  • Chang, C.-C., Chung, S.-L., & Stapleton, R.(2007). “Richardson Extrapolation Techniques for the Pricing of American-Style Options.” Journal of Futures Markets, 27, 791–817.