Finite Difference Methods for Option Pricing › The Crank-Nicolson Scheme

Michael BrenndoerferDecember 4, 20256 min read
Quantitative FinanceAll chapters
Part 6 of 15Numerical Methods for Derivative Pricing
Chapter 36Finite Difference Methods for Option Pricing › The Crank-Nicolson Scheme
Reading section 5 of 14 · The Crank-Nicolson Scheme · 6 minSection 5 of 14 · 6 min

Book contents

Section 5 of 14 · 6 min read

Finite Difference Methods for Option Pricing › The Crank-Nicolson SchemeOne section · Sections in this chapter5 / 14 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

The Crank-Nicolson scheme represents a middle ground between explicit and implicit methods. It averages the spatial derivatives at times tnt_n and tn+1t_{n+1}, achieving second-order accuracy in time while maintaining unconditional stability. This combination of accuracy and stability makes Crank-Nicolson the method of choice for most practical applications.

The Averaging Approach

Instead of evaluating spatial derivatives entirely at tnt_n (implicit) or tn+1t_{n+1} (explicit), Crank-Nicolson uses the average of both evaluations. This averaging can be motivated by the trapezoidal rule for numerical integration: when integrating the time derivative, we approximate the integral of the spatial operator by averaging its values at the beginning and end of the time interval. The scheme uses:

∂2V∂S2≈12[Vj+1n−2Vjn+Vj−1n(ΔS)2+Vj+1n+1−2Vjn+1+Vj−1n+1(ΔS)2]\frac{\partial^2 V}{\partial S^2} \approx \frac{1}{2}\left[\frac{V_{j+1}^n - 2V_j^n + V_{j-1}^n}{(\Delta S)^2} + \frac{V_{j+1}^{n+1} - 2V_j^{n+1} + V_{j-1}^{n+1}}{(\Delta S)^2}\right]

where:

  • V⋅nV_{\cdot}^n: values at current time step
  • V⋅n+1V_{\cdot}^{n+1}: values at next time step
  • ΔS\Delta S: price step size

and similarly for the first derivative. This averaging can be viewed as taking a half-step with the explicit scheme and a half-step with the implicit scheme. The explicit part uses known information from the future time step, while the implicit part ensures stability by coupling values at the current time step.

The Discretized Equation

Substituting the approximations into the Black-Scholes PDE:

Vjn+1−VjnΔt+12(LjVn+LjVn+1)=0\frac{V_j^{n+1} - V_j^n}{\Delta t} + \frac{1}{2}\left(\mathcal{L}_j V^n + \mathcal{L}_j V^{n+1}\right) = 0

where:

  • LjV\mathcal{L}_j V: spatial operator at node jj, equal to 12σ2Sj2∂2V∂S2+rSj∂V∂S−rV\frac{1}{2}\sigma^2 S_j^2 \frac{\partial^2 V}{\partial S^2} + rS_j\frac{\partial V}{\partial S} - rV
  • Vn,Vn+1V^n, V^{n+1}: option values at current and next time steps

The spatial operator Lj\mathcal{L}_j encapsulates all the terms involving spatial derivatives and the discounting term. Applying this operator at both time levels and averaging creates the characteristic Crank-Nicolson structure. Rearranging terms by time step:

−αjVj−1n+(1+βj)Vjn−γjVj+1n=αjVj−1n+1+(1−βj)Vjn+1+γjVj+1n+1-\alpha_j V_{j-1}^n + (1 + \beta_j) V_j^n - \gamma_j V_{j+1}^n = \alpha_j V_{j-1}^{n+1} + (1 - \beta_j) V_j^{n+1} + \gamma_j V_{j+1}^{n+1}

where:

  • LHS: implicit terms at current time tnt_n
  • RHS: explicit terms at next time tn+1t_{n+1}
  • αj,βj,γj\alpha_j, \beta_j, \gamma_j: Crank-Nicolson coefficients

The left side involves unknown values at tnt_n, forming a tridiagonal system just as in the implicit scheme. The right side uses known values at tn+1t_{n+1}, which we can compute explicitly before solving the system. The coefficients are:

αj=Δt4(σ2j2−rj)βj=Δt2(σ2j2+r)γj=Δt4(σ2j2+rj)\begin{aligned} \alpha_j &= \frac{\Delta t}{4}\left(\sigma^2 j^2 - rj\right) \\ \beta_j &= \frac{\Delta t}{2}\left(\sigma^2 j^2 + r\right) \\ \gamma_j &= \frac{\Delta t}{4}\left(\sigma^2 j^2 + rj\right) \end{aligned}

where:

  • Δt\Delta t: time step
  • σ\sigma: volatility
  • rr: risk-free rate
  • jj: spatial index

Notice that these coefficients are exactly half of the corresponding implicit scheme coefficients, which reflects the averaging of the spatial operator between two time levels. The left side involves unknown values at tnt_n, while the right side uses known values at tn+1t_{n+1}. This again leads to a tridiagonal system at each time step.

Implementation

In[16]:
Code
def crank_nicolson_european_call(S_max, K, T, r, sigma, M, N):
    """
    Price a European call option using the Crank-Nicolson finite difference method.
    """
    dS = S_max / M
    dt = T / N

    # Grid of stock prices
    S = np.linspace(0, S_max, M + 1)

    # Initialize option values at expiration
    V = np.maximum(S - K, 0)

    # Precompute coefficients for interior points
    j = np.arange(1, M)
    alpha = 0.25 * dt * (sigma**2 * j**2 - r * j)
    beta = 0.5 * dt * (sigma**2 * j**2 + r)
    gamma = 0.25 * dt * (sigma**2 * j**2 + r * j)

    # Tridiagonal matrix coefficients (left side)
    a_left = -alpha[1:]  # Sub-diagonal
    b_left = 1 + beta  # Main diagonal
    c_left = -gamma[:-1]  # Super-diagonal

    # Time stepping
    for n in range(N - 1, -1, -1):
        # Build right-hand side (explicit part)
        d = np.zeros(M - 1)
        d = alpha * V[0 : M - 1] + (1 - beta) * V[1:M] + gamma * V[2 : M + 1]

        # Boundary condition adjustments
        boundary_0 = 0
        boundary_M = S_max - K * np.exp(-r * (N - n) * dt)

        d[0] += alpha[0] * boundary_0
        d[-1] += gamma[-1] * boundary_M

        # Solve tridiagonal system
        V[1:M] = thomas_algorithm(a_left, b_left, c_left, d)

        # Update boundaries
        V[0] = boundary_0
        V[M] = boundary_M

    return S, V
In[17]:
Code
# Price with Crank-Nicolson method
S_grid, V_cn = crank_nicolson_european_call(S_max, K, T, r, sigma, M, N=500)

idx = np.argmin(np.abs(S_grid - S_0))
price_cn = V_cn[idx]
Out[18]:
Console
Crank-Nicolson FD price at S = 100: $10.4407

The Crank-Nicolson price is consistent with the other methods. By averaging the explicit and implicit approaches, it maintains stability while improving accuracy, effectively reducing the bias introduced by time discretization.

Accuracy Analysis

The Crank-Nicolson scheme achieves O((Δt)2)O((\Delta t)^2) accuracy in time, compared to O(Δt)O(\Delta t) for both the explicit and implicit schemes. This means that halving the time step reduces the time discretization error by a factor of four rather than two. The improved accuracy comes from the averaging, which cancels the leading-order error terms in the Taylor expansion. For most applications, Crank-Nicolson provides the best balance of accuracy, stability, and computational efficiency.

Out[19]:
Visualization
Line plot showing European call option values versus stock price for explicit, implicit, and Crank-Nicolson schemes.
Comparison of the three finite difference schemes for pricing a European call option. All three methods produce similar option value curves, but they differ in computational requirements and accuracy. The explicit scheme requires many more time steps to maintain stability.