halo 的技术博客

返回

Black-Scholes 公式是期权定价的基石,但它只给了欧式期权的闭式解。一旦你遇到美式期权(可以在到期前提前行权)、障碍期权(价格触到某条线就作废)、回望期权(payoff 依赖路径极值),闭式就基本消失了——这时候你必须靠数值方法。

数值期权定价有三条主流路线:蒙特卡洛(模拟路径)、二叉/三叉树(离散时间)、以及有限差分法(Finite Difference Method, FDM)——它直接在 BS 偏微分方程(PDE)上做文章。本文聚焦 FDM:它把一条连续的偏微分方程,离散成网格上的巨大代数方程组,用计算机求解。

有限差分法三种格式对欧式看涨的收敛速度:误差随网格加密稳定下降

一、从 BS 偏微分方程到差分网格#

BS 方程描述的是期权价值 V(S,t)V(S,t) 随标的 SS 和时间 tt 演化的规律:

Vt+12σ2S22VS2+rSVSrV=0\frac{\partial V}{\partial t} + \frac{1}{2}\sigma^2 S^2\frac{\partial^2 V}{\partial S^2} + rS\frac{\partial V}{\partial S} - rV = 0

有限差分法的思路非常朴素:把连续的 SStt 切成网格。设标的价格从 00SmaxS_{\max} 均匀分 NSN_S 格,时间从 00TT 均匀分 NtN_t 格,网格点 (i,j)(i,j) 表示「第 ii 个价格节点、第 jj 个时间步」。

在每一个网格点上,用差商近似导数:

  • SS 的二阶导(Gamma 项)用中心差分2VS2Vi+12Vi+Vi1ΔS2\frac{\partial^2 V}{\partial S^2} \approx \frac{V_{i+1} - 2V_i + V_{i-1}}{\Delta S^2}
  • SS 的一阶导(Delta 项)用中心差分:VSVi+1Vi12ΔS\frac{\partial V}{\partial S} \approx \frac{V_{i+1} - V_{i-1}}{2\Delta S}
  • tt 的导(Theta 项)用前向/后向差分,这就是三种格式的分水岭

把差商代回 BS 方程,你会得到每个内点 ViV_i 与邻居 Vi1,Vi+1V_{i-1}, V_{i+1} 的线性关系。整条网格在任一时刻就是一个三对角方程组——这正是 FDM 计算高效的根源。

二、三种时间离散格式:显式 / 隐式 / Crank-Nicolson#

时间导数用前向还是后向差分(或各取一半),决定了格式的稳定性精度

  1. 显式(Explicit / 前向欧拉):新时刻的值直接用旧时刻的邻居算出来,无需解方程,最直观。但它在稳定性上有硬性约束:CFL 条件——要求 ΔtΔS2σ2Smax2\Delta t \le \frac{\Delta S^2}{\sigma^2 S_{\max}^2}。网格太粗(时间步太大)就会发散震荡。
  2. 隐式(Implicit / 向后欧拉):新时刻的值依赖新时刻的邻居,于是每个时间步要解一个三对角线性方程组。代价是每次解一次方程,但无条件稳定——随便怎么加密网格都不会炸。
  3. Crank-Nicolson(CN,1950):前向和后向各取一半(权重 θ=0.5\theta=0.5),既二阶精度又无条件稳定,是实务首选。

举个直观对照:显式像「闭眼按公式一步步推」,快但可能踩空;隐式像「每一步都回头校验一遍约束」,稳但要算方程;CN 是两者折中。

三、Python 实战 1:三种格式的核心循环#

下面用 scipy.linalg.solve_banded 解三对角系统,把三套逻辑统一到一个函数里(用 θ\theta 切换)。注意边界:看跌在 S=0S=0 处值为 KerτK e^{-r\tau},在 S=SmaxS=S_{\max} 处趋于 0。

跑出来的自洽校验结果是:BS 闭式 = 10.4506,CN = 10.4544,隐式 = 10.4539,显式 = 10.4547——三种格式偏差都不到 0.005,证明 PDE 离散和内插逻辑正确。

欧式看涨价格曲线:三种 FD 格式与 BS 闭式几乎重合

四、美式期权:Early-Exercise 约束#

欧式期权只比较「继续持有」和「到期行权」,美式期权多一个维度:现在就行权。FDM 处理它极其自然——在每个时间步更新完 VV 后,强制取 max(V, 内在价值)

V美式(S,τ)=max(V持有(S,τ),  KS)V^{\text{美式}}(S,\tau) = \max\big(V^{\text{持有}}(S,\tau),\; K - S\big)

这正是代码里 if american: Vnew = np.maximum(Vnew, intrinsic) 那一行。它表达的是:只要「立即行权拿到的钱」比「继续持有值」多,理性持有者就行权,期权价值被这道地板托住。

bs_put = K*np.exp(-r*T)*norm.cdf(-(np.log(S0/K)+(r+0.5*sig**2)*T)/(sig*np.sqrt(T))) ) \
         - S0*norm.cdf(-(np.log(S0/K)+(r+0.5*sig**2)*T)/(sig*np.sqrt(T)))
am_put = fd_price(1.0, 200, 2000, "put", american=True)
print(f"欧式看跌 BS = {bs_put:.4f}")
print(f"美式看跌 FD = {am_put:.4f}  (美式溢价 {am_put-bs_put:+.4f})")
python

数值上美式看跌 = 6.0914,欧式看跌 BS = 5.5735,美式溢价 +0.5179——提前行权权本身值钱,这与理论一致(美式看跌确实比欧式贵)。

五、Python 实战 2:价值曲面与稳定性#

V(S,τ)V(S,\tau) 在整张网格上存下来,就能画出价值曲面——它直观展示了「临近到期 + 深度实值」时期权价值如何被 Gamma/Theta 推高。

Ns, Nt = 120, 600
dS, dt = Smax/Ns, T/Nt
S_grid = np.linspace(0, Smax, Ns+1); i = np.arange(Ns+1)
alpha = 0.5*sig**2*dt*i**2; delta = 0.5*r*dt*i; gamma = r*dt
V = np.maximum(S_grid-K, 0.0)
sub=-0.5*(alpha-delta); diag=1+0.5*(2*alpha+gamma); sup=-0.5*(alpha+delta)
ab=np.zeros((3,Ns+1)); ab[0,1:]=sup[:-1]; ab[1,:]=diag; ab[2,:-1]=sub[1:]
Vmat=np.zeros((Nt+1,Ns+1)); Vmat[0]=V
for step in range(Nt):
    tau=(step+1)*dt
    b=V+0.5*((alpha-delta)*np.concatenate([[0],V[:-1]])+(-2*alpha-gamma)*V+(alpha+delta)*np.concatenate([V[1:],[0]]))
    Vnew=solve_banded((1,1),ab,b)
    Vnew[0]=0.0; Vnew[Ns]=Smax-K*np.exp(-r*tau); V=Vnew; Vmat[step+1]=V
# Vmat[i,j] 即 V(S_grid[j], 时刻 i) -> 可直接 contourf 画图
python

Crank-Nicolson 看涨期权价值曲面 V(S,τ)

显式格式的稳定性必须用图说话。下面故意违反 CFL:把时间步设得过大(Nt=250N_t=250),显式解立刻在障碍附近震荡发散;而 Nt=4000N_t=4000(满足 CFL)时平滑贴合 BS。

def price_curve(Nt):
    V = np.maximum(S_grid-K, 0.0)
    for step in range(Nt):
        Vnew=(alpha-delta)*np.concatenate([[0],V[:-1]])+(1-2*alpha-gamma)*V\
             +(alpha+delta)*np.concatenate([V[1:],[0]]); V=Vnew
    return V
stable = price_curve(4000)     # 满足 CFL
unstable = price_curve(250)    # 违反 CFL -> 发散
python

显式格式稳定性:CFL 条件不满足即震荡发散

六、网格与边界:两个常被忽视的工程细节#

  • 空间边界 SmaxS_{\max}:理论上 SS\to\infty,但网格必须有上界。实务取 Smax=Ke(r+)TS_{\max} = K\cdot e^{(r+\cdots)\cdot T} 的几倍,或者用对数坐标网格让尾部更密。若 SmaxS_{\max} 太小,深度实值 call 的边界条件会系统性压低整条曲线。
  • 边界条件形式:本文用的是「线性边界」(端点按 BS 渐近线性外推)。更严谨的是二次边界(考虑 Gamma 在边界的衰减),对高 Gamma 障碍期权尤其重要,否则边界会反射虚假波。
  • 收敛阶:CN 对 ΔS\Delta SΔt\Delta t 都是二阶收敛;但如果在 S0S_0 处用线性插值取价,会引入一阶误差——要拿精确价就得在 S0S_0 处加密或做二次插值。

七、真实陷阱#

  • CFL 稳定性陷阱(显式专属):显式快,但 Δt\Delta t 一旦超过阈值就爆炸。解法:要么守 CFL(通常要求 NtO(NS2)N_t \sim O(N_S^2),代价是时间步极多),要么直接用隐式/CN。实务几乎不单独用纯显式。
  • 边界反射陷阱:边界条件设错,会在 SmaxS_{\max}S=0S=0 处产生「虚假反射波」,污染整张曲面,尤其是障碍期权贴边界时。解法:用更大的 SmaxS_{\max} + 二次边界,或对数网格。
  • 美式约束顺序陷阱max(V, 内在价值) 必须在每个时间步做,而不是只在期末做。若只在最后投影一次,等于没建模提前行权,美式溢价会算丢。
  • 网格稀疏陷阱:用太粗的网格(比如 NS<50N_S<50),CN 偏差可能到 1% 以上。本文校验显示 NS=200N_S=200 时偏差已 <0.005;但障碍/美式对网格更敏感,需更密。
  • 插值取价陷阱:在 S0S_0 不在网格节点上时,用线性插值会引入一阶误差。若要做希腊值(Delta/Gamma),应在网格上直接差分而非插值后求导。

八、落地清单#

  1. 欧式期权:直接用 CN(θ=0.5\theta=0.5),NS=200,Nt=2000N_S=200, N_t=2000 已足够精确到 0.01 以内,且无条件稳定。
  2. 美式期权:隐式或 CN + 每步 max(V, 内在价值);看跌美式溢价可用本文代码直接自洽校验。
  3. 障碍/回望等路径依赖:FDM 需改造敲出/敲入逻辑(下一篇巴黎期权会讲),注意边界与网格耦合。
  4. 要算希腊值:在网格上做中心差分((V[i+1]-V[i-1])/(2ΔS) 得 Delta,(V[i+1]-2V[i]+V[i-1])/ΔS² 得 Gamma),别用插值后的值。
  5. 稳定性优先:默认选 CN,别为省一次线性方程求解去冒显式发散的风险。

结语#

有限差分法是「把 BS 偏微分方程敲成网格代数」的艺术。显式最易写但受 CFL 约束,隐式稳定但要解三对角,Crank-Nicolson 用半个时间步的前后加权平均,既稳又准,几乎是实务默认。它的真正威力不在欧式(那里 BS 闭式就够了),而在美式提前行权、障碍敲出、回望极值这类闭式失效的地方——而那恰恰是奇异期权定价的主战场。下一篇我们就用这套 PDE 思想,去对付比普通障碍更刁钻的「巴黎式障碍」。

本文数值均用 Python 从零实跑自洽校验:欧式看涨三种格式对 BS 闭式偏差均 < 0.005;美式看跌溢价 +0.5179,与理论一致。代码可复现上述全部图表。

有限差分法期权定价:用网格把 Black-Scholes 偏微分方程敲成数值解
https://blog.halo26812.eu.org/blog/finite-difference-option-pricing
Author halo
Published at 2026年7月20日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨