Skip to main content

Fourier-based European option pricing with Carr-Madan FFT, FRFT, and COS under characteristic-function models.

Project description

fourier-option-pricer

Fast European option pricing via Fourier transform methods under characteristic-function models.

Carr, P., & Madan, D. (1999). Option valuation using the fast Fourier transform. Journal of Computational Finance, 2(4), 61–73. https://doi.org/10.21314/JCF.1999.043

Lewis, A. L. (2001). A simple option formula for general jump-diffusion and other exponential Lévy processes. SSRN Working Paper. https://ssrn.com/abstract=282110 (Heston and Variance Gamma characteristic functions are provided by PyFENG, Prof. Jaehyuk Choi's library.)

Fang, F., & Oosterlee, C. W. (2008). A novel pricing method for European options based on Fourier-cosine series expansions. SIAM Journal on Scientific Computing, 31(2), 826–848. https://doi.org/10.1137/080718061

Junike, G., & Pankrashkin, K. (2022). Precise option pricing by the COS method — how to choose the truncation range. Applied Mathematics and Computation, 421, 126935. https://doi.org/10.1016/j.amc.2022.126935

Extension/novelty inspiration: Ruijter, M. J., Versteegh, M., & Oosterlee, C. W. (2015). On the application of spectral filters in a Fourier option pricing technique. Journal of Computational Finance, 19(1), 75–106. https://doi.org/10.21314/JCF.2015.306 (Used as inspiration for the spectral-filtering layer in the adaptive filtered-COS extension. The project adapts this idea into a tolerance-driven selector over no-filter and filtered COS policies, rather than forcing a single fixed filter.)

Core concept

Fourier pricing exploits the fact that, for most asset models, the characteristic function

$$\phi(u) = \mathbb{E}!\left[e^{iu \ln S_T}\right]$$

is known in closed form even when the option price integral has no analytic solution. Given $\phi$, a European call can be priced by a single numerical integral. The three methods implemented here differ in how they discretise that integral:

Method Key idea
Carr–Madan FFT Damp the payoff, apply FFT to price a whole strike grid at once
Lewis single-integral Parseval identity; avoids the dampening parameter entirely
COS (Fang–Oosterlee) Expand the risk-neutral density in a cosine series on $[a, b]$

Truncation and filtering

The COS method requires choosing a truncation interval $[a,b]$ for the log-price density. Two truncation strategies are implemented:

  • Cumulant rule (Fang & Oosterlee 2008) — sets $[a,b]$ from the first four cumulants of $\ln S_T$.
  • Tolerance rule (Junike & Pankrashkin 2022) — widens $[a,b]$ iteratively until the tail-mass proxy falls below a user-specified tolerance. This is used for stress cases where the cumulant rule can become unreliable or overly wide.

In addition, the project implements an adaptive filtered-COS extension "extension" inspired by Ruijter, Versteegh and Oosterlee (2015), as the Rather than applying one fixed spectral filter, we adapt the idea into a tolerance-driven selector around COS pricing.

  • Why filtering is added: truncation fixes the interval, but COS can still show finite-series ringing near payoff kinks, short maturities, or jump-heavy densities.
  • Candidate filters: the selector keeps plain Junike-COS in the pool and also tests Fejér, Lanczos, raised-cosine, and exponential filters.
  • Selection rule: use the cheapest candidate that meets the tolerance. If a filter does not help, the method falls back to the no-filter Junike choice.

Models

Family Models
Pure diffusion Black–Scholes–Merton
Stochastic volatility Heston, OU-SV
Pure jump / Lévy Variance Gamma, NIG, CGMY
Jump diffusion Kou double-exponential
SV + jumps Bates, Heston–Kou, Heston–CGMY

Installation

pip install fourier-option-pricer

For local development:

git clone https://github.com/nl2992/fourier-option-pricer.git
cd fourier-option-pricer
pip install -e ".[test]"
pytest

Quick start

import numpy as np
import foureng as fe

# Market inputs
fwd = fe.ForwardSpec(S0=100.0, r=0.01, q=0.02, T=1.0)

# Heston model parameters
params = fe.HestonParams(kappa=4.0, theta=0.25, nu=1.0, rho=-0.5, v0=0.04)

# Characteristic function
phi = lambda u: fe.heston_cf_form2(u, fwd, params)

# Strike grid
strikes = np.array([80.0, 90.0, 100.0, 110.0, 120.0])

# Price with COS (standard truncation)
cumulants = fe.heston_cumulants(fwd, params)
grid = fe.cos_auto_grid(cumulants, N=256, L=10.0)
result = fe.cos_prices(phi, fwd, strikes, grid)
print(result.call_prices)

# Price with Carr–Madan FFT
cm_grid = fe.FFTGrid(N=4096, eta=0.25, alpha=1.5)
cm_prices = fe.carr_madan_price_at_strikes(phi, fwd, cm_grid, strikes)
print(cm_prices)

# Implied volatility
atm_iv = fe.implied_vol_newton_safeguarded(
    price=float(result.call_prices[2]),
    inputs=fe.BSInputs(F0=fwd.F0, K=100.0, T=fwd.T, r=fwd.r, q=fwd.q, is_call=True),
)
print(atm_iv)

Improved COS truncation (Junike rule)

grid = fe.cos_improved_grid(cumulants, model="heston", params=params)
result = fe.cos_prices(phi, fwd, strikes, grid)

Extension: adaptive filtered-COS policy layer

The Junike-style COS policy improves truncation-range selection, but COS accuracy is controlled by both the truncation interval and the finite cosine expansion. As an extension, this repo adds an adaptive filtered-COS overlay inspired by Ruijter, Versteegh and Oosterlee's spectral-filtering work for Fourier option pricing.

The filter is applied to the COS expansion coefficients and is tested as one candidate inside a deterministic numerical-policy search. The adaptive selector compares vanilla COS, Junike-COS, and filtered Junike-COS, then selects the fastest candidate satisfying a target error tolerance.

This extension does not claim filtered-COS universally dominates Junike-COS. The intended object is the adaptive selector, which can choose no filter where filtering is unnecessary.

Usage:

from foureng.pipeline import price_strip
from foureng.utils.spectral_filters import COSFilterSpec
from foureng.utils.grids import COSGridPolicy

policy = COSGridPolicy(
    mode="benchmark",
    truncation="tolerance",
    centered=True,
    dx_target=0.01,
    L=10.0,
    eps_trunc=1e-10,
    max_N=8192,
    width_fallback=0.0,
)

prices = price_strip(
    "vg",
    "cos_filtered",
    strikes,
    fwd,
    params,
    grid=(policy, COSFilterSpec("exponential", order=8)),
)

For the full adaptive grid-search selector (comparing vanilla, Junike, and filtered candidates):

from foureng.experiments.cos_filter_grid_search import (
    default_filtered_cos_candidates,
    run_filtered_cos_grid_search,
    select_fastest_under_tolerance,
)

df = run_filtered_cos_grid_search(
    model="vg", strikes=strikes, fwd=fwd, params=params,
    reference=reference_prices, tol=1e-6,
)
best = select_fastest_under_tolerance(df, tol=1e-6)

References:

  • Junike, G. and Pankrashkin, K. (2022), "Precise option pricing by the COS method — How to choose the truncation range," Applied Mathematics and Computation, 421, 126935.
  • Ruijter, M. J., Versteegh, M. and Oosterlee, C. W. (2015), "On the application of spectral filters in a Fourier option pricing technique," Journal of Computational Finance.
  • Junike, G. (2024), "On the number of terms in the COS method for European option pricing," Numerische Mathematik.

Available spectral filters: "none" (identity), "fejer", "lanczos", "raised_cosine", "exponential" (order-p tunable).

Demo notebook

An interactive demo is available at notebooks/demo.ipynb:

Open In Colab

API reference

ForwardSpec(S0, r, q, T)

Parameter Type Description
S0 float Spot price
r float Continuously compounded risk-free rate
q float Dividend yield or foreign rate
T float Time to maturity in years

Provides F0 (forward price) and disc (discount factor).

Model parameter classes

Class Model
HestonParams(kappa, theta, nu, rho, v0) Heston stochastic volatility
VGParams(sigma, nu, theta) Variance Gamma
KouParams(sigma, lam, p, eta1, eta2) Kou double-exponential jump diffusion
BatesParams(...) Bates (Heston + Poisson jumps)
CGMYParams(C, G, M, Y) CGMY pure-jump Lévy
NIGParams(alpha, beta, delta) Normal Inverse Gaussian

cos_prices(phi, fwd, strikes, grid)

Parameter Type Description
phi callable Characteristic function phi(u)
fwd ForwardSpec Market inputs
strikes (K,) array Strike prices
grid COSGrid Truncation grid from cos_auto_grid or cos_improved_grid

Returns a COSResult with fields strikes and call_prices.

carr_madan_price_at_strikes(phi, fwd, grid, strikes)

Parameter Type Description
phi callable Characteristic function
fwd ForwardSpec Market inputs
grid FFTGrid(N, eta, alpha) FFT grid
strikes (K,) array Strike prices

Returns (K,) array of call prices.

cos_auto_grid(cumulants, N, L) / cos_improved_grid(cumulants, model, params)

Parameter Type Description
cumulants cumulant object From heston_cumulants, vg_cumulants, etc.
N int Number of COS expansion terms
L float Truncation multiplier (standard rule only)
model str Model name, e.g. "heston" (improved rule only)
params param dataclass Model parameters (improved rule only)

Returns a COSGrid.

implied_vol_newton_safeguarded(price, inputs)

Parameter Type Description
price float Option price
inputs BSInputs BSInputs(F0, K, T, r, q, is_call)

Returns implied volatility as float.

Extended methodology and results

Detailed numerical experiments, replication notes, runtime benchmarks, and implementation commentary are kept outside the README to keep this page concise.

See:

docs/methodology_and_results.md

This document records:

  • the Fang-Oosterlee COS replication workflow;
  • the Carr-Madan benchmark setup;
  • the Monte Carlo comparison setup;
  • COS truncation-interval behaviour;
  • improved COS grid logic;
  • runtime and error reporting rules;
  • model-by-model observations;
  • known numerical limitations;
  • adaptive filtered-COS extension (spectral filters + policy grid-search selector).

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fourier_option_pricer-0.3.0.tar.gz (113.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fourier_option_pricer-0.3.0-py3-none-any.whl (94.6 kB view details)

Uploaded Python 3

File details

Details for the file fourier_option_pricer-0.3.0.tar.gz.

File metadata

  • Download URL: fourier_option_pricer-0.3.0.tar.gz
  • Upload date:
  • Size: 113.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for fourier_option_pricer-0.3.0.tar.gz
Algorithm Hash digest
SHA256 557acdb89eafad4fd3d6717400bbb173f33e05c83887b0db5a63ea80cafeff9f
MD5 54a686255859724912bfdf1650e098da
BLAKE2b-256 8732ef43e45df4358273b5445c988e5519b5feca2a74a4822dc598650b9a2927

See more details on using hashes here.

File details

Details for the file fourier_option_pricer-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for fourier_option_pricer-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5a44db771a2ac9c1cab26f9795fc0c0d4c4c145c03382e27e015582e7e66e80f
MD5 886f467b73cee29ff7d65530b2cb5223
BLAKE2b-256 02356b080f86e53b405280219c84a96bfef1ec3098f224187db9a8576591be6d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page