Skip to content
All library documents

Correcting Terminal Payoff Ordering in FFT Binomial Option Pricing

Article Quant Q&A · Author: ThisIsGonnaBeCool

Summary

This exchange diagnoses an error in a proposed fast Fourier transform implementation for pricing a European call option with a Cox-Ross-Rubinstein binomial model. The problem was the ordering of terminal underlying prices: the code built them from the lowest value upward, while the probability vector and transform calculation required the reverse ordering. The accepted correction starts from the all-up terminal price and steps downward across the vector.

The question reports that increasing the number of steps made the computed option value much larger, and the answer says the corrected terminal vector produces expected results. The discussion is narrowly focused on array ordering in this implementation. It does not derive the transform formula, assess numerical convergence, or examine assumptions such as the option model, input calibration, and discretization.

Key ideas

  • The terminal underlying-price vector was ordered inconsistently with the transform calculation.
  • The corrected vector starts at the all-up terminal price and decreases by replacing up moves with down moves.
  • The answer reports that correcting this ordering resolves the implausible output behavior.
  • The exchange does not provide a general derivation or broader validation of the pricing method.

Tags

Full text
# Option pricing using discrete fourier transform (python)


# Option pricing using discrete fourier transform (python)












I am trying to implement the pricing formula for a European (call) option given in Ales Cerny's paper "Introduction to Fast Fourier Transform in Finance" (paper can be found here), as follows:

My python code below does not return the correct answer, and in particular if I significantly increase the number of steps then I get a much larger answer. Where have I gone wrong?

```
import numpy as np
from numpy.fft import fft, ifft

def price_vanilla_option(s: float,
                         k: float,
                         r: float,
                         ro: float,
                         t: float) -> float:
    """
    price vanilla option using Fast Fourier Transform
    """

    steps = 1023  # 2^n - 1 for efficient fft
    d_t = t / steps
    discount = 1/(1 + r * d_t)

    # use CRR probabilities
    u = np.exp(ro * np.sqrt(d_t))
    d = np.exp(-ro * np.sqrt(d_t))
    p = (np.exp(r * d_t) - d)/(u - d)

    # set up terminal vector and prob vector
    c_n = np.zeros(steps + 1)
    c_n[0] = s * (d ** steps)
    for i in range(1, steps + 1):
        c_n[i] = c_n[i - 1] * u / d
    c_n = np.maximum(c_n - k, 0)
    p_vec = np.pad([p, 1 - p], (0, steps - 1))

    # fast fourier transform
    c_0 = fft(ifft(c_n) * np.power(fft(p_vec) * discount, steps))
    return np.real(c_0[0])
```

## Answer by ThisIsGonnaBeCool (score 1, accepted)

https://quant.stackexchange.com/a/60930

In case this is useful for anyone else who comes across this, the issue was that I had set up my vector of terminal values the wrong way round (ie from smallest to largest rather than largest to smallest). The code to set up the terminal vector should read as follows:

```
# set up terminal vector and prob vector
c_n = np.zeros(steps + 1)
c_n[0] = s * (u ** steps)
for i in range(1, steps + 1):
   c_n[i] = c_n[i - 1] * d / u
c_n = np.maximum(c_n - k, 0)
```

With this change, the code then produces the expected results.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.