## CharFuncPricing.jl

Julia package to provide reference European option prices for stochastic volatility models with a known characteristic function, such as the Heston stochastic volatility model.
Author jherekhealy
Popularity
4 Stars
Updated Last
1 Year Ago
Started In
June 2020

# Package CharFuncPricing

Status Coverage

Julia package to provide reference European option prices for stochastic volatility models with a known characteristic function, such as the Heston stochastic volatility model. For the Heston and Schobel-Zhu models, a function provides the first, second and fourth cumulants through analytical formulas.

The code is not meant for production purpose and does not always cater for corner cases. It however supports arbitrary precision via the Nemo package.

## Installation

In a Julia REPL, enter pkg mode (by pressing ]) and run:

(v1.0) pkg> add CharFuncPricing

Julia version 1.2 or higher is required.

## Cos method

### Float64 Usage

Start by creating a HestonParams structure, which represents the parameters of the Heston model: v0, κ, θ, ρ, σ.

params = HestonParams(v0, κ, θ, ρ, σ)

Then make a CosCharFuncPricer structure via makeCosCharFuncPricer. This function will store the relevant m values of the characteristic function for the range [a,b] defined by l deviations using the cumulants rule a = c1 - l * sqrt(c2+sqrt(c4)), b = c1 + l * sqrt(c2+sqrt(c4)).

cf = DefaultCharFunc(params)
pricer = makeCosCharFuncPricer(cf, τ, m, l)

And price vanilla call and puts of a given strike as following

priceEuropean(pricer, false, strike, forward, τ, df)

The second parameter specifies whether we want to price a call (true) or a put (false). The last parameter specifies the discount factor to maturity.

The first, second and fourth cumulants are given by

c1,c2,c4 = computeCumulants(params, τ)

### Nemo Usage

The only difference is to make sure the parameters are of ArbField type (real arbitrary precision), the function makeCosCharFuncPricer should also be called on the AcbField type.

using Nemo
R = ArbField(256)
CC = AcbField(256)
cf = NemoCharFunc{HestonParams{arb}}(params, CC)
pricer = makeCosCharFuncPricer(cf, τ, m, l)

### Float64 Example

Here is how to price a put option with parameters

r=0.01; q=0.02
κ=4.0; θ=0.25; σ=1.0; ρ=-0.5; v0=0.04
τ = 1.0
spot = 100.0; strike = 80.0
spot *= exp((r - q) * τ)
df = exp(-r * τ)
params = HestonParams(v0, κ, θ, ρ, σ)
cf = DefaultCharFunc(params)
l = 32; m = 1024
pricer = makeCosCharFuncPricer(cf, τ, m, l)
priceEuropean(pricer, false, strike, spot, τ, df)

The result is 7.95887811325676.

### Nemo Example
```julia
using Nemo
using CharFuncPricing

R = ArbField(256)
CC = AcbField(256)
r = R(QQ(1, 100)); q = R(QQ(2, 100))
κ = R(4.0); θ = R(QQ(1, 4)); σ = R(1.0); v0 = R(QQ(4, 100)); ρ = R(-0.5);
τ = R(1.0)
spot = R(100); strike = R(80)
isCall = false
spot *= exp((r - q) * τ)
df = exp(-r * τ)
params = HestonParams(v0, κ, θ, ρ, σ)
cf = NemoCharFunc{HestonParams{arb}}(params, CC)
l = 48; m = 1024*4
pricer = makeCosCharFuncPricer(cf, τ, m, l)
priceEuropean(pricer, isCall, strike, spot, τ, df)

The result is:

7.95887811325676828521326060761429303089865693725960319205094095681790030 +/- 4.83e-72.

With l=64; m=1024*8, we obtain:

7.95887811325676828521326060761429303089865693725960319205094095681878397 +/- 3.71e-72.

## Andersen-Lake

### Float64 Example

It starts similarly as for the Cos method, the only change is how to build the pricer variable.

pricer = ALCharFuncPricer(cf)
priceEuropean(pricer, false, strike, spot, τ, df)

The result is 7.9588781132567705.

### BigFloat Example

We use BigFloat for the Heston parameters and option characteristics, as well as in the quadrature tolerance.

r=BigFloat("0.01"); q=BigFloat("0.02")
κ=BigFloat(4.0); θ=BigFloat("0.25"); σ=BigFloat(1.0); ρ=BigFloat("-0.5"); v0=BigFloat("0.04")
τ = BigFloat(1.0)
spot = BigFloat(100.0); strike = BigFloat(80.0)
spot *= exp((r - q) * τ)
df = exp(-r * τ)
params = HestonParams(v0, κ, θ, ρ, σ)
cf = DefaultCharFunc{HestonParams{BigFloat},Complex{BigFloat}}(params)
priceEuropean(pricer, false, strike, spot, τ, df)

The result is

7.95887811325676828521326060761429303089865693725960319205094095681918541918632

This is the adaptive Flinn quadrature using the transformation to (-1, 1) interval. No truncation is involved.

### Float64 Example

With a quadrature tolerance of 1e-8:

pricer = AdaptiveFlinnCharFuncPricer(cf, τ, qTol = 1e-8)
priceEuropean(pricer, false, strike, spot, τ, df)

The result is 7.958878112874899

### BigFloat Example

The adaptive Flinn pricer works with high accuracy, but does not perform very well then. It is more intended for the calculation of prices with a absolute error tolerance of around 1e-8 or 1e-10.

pricer = AdaptiveFlinnCharFuncPricer(cf, τ, qTol = BigFloat(1e-24))
priceEuropean(pricer, false, strike, spot, τ, df)

The result is

7.958878113256768285213257572750089190600415520655780637746847607110529890012863

and the effective accuracy is 3e-24. In total, length(pricer.kcos[1,:])=31511 points are used, compared to 295 for an tolerance of 1e-10. For a tolerance of 1e-32, 450799 points are used. This means that algorithm is asymptotically linear on this example.

## Testing

In a Julia REPL session, enter pkg mode and run test CharFuncPricing.

Unit tests verify the call and put option prices against the reference prices of Alan Lewis in double and arbitrary precision. In fact, the implementation here gives more precise results (minimum accuracy of 1e-60 while Alan Lewis numbers are only accurate up to 1e-25).

Cumulants are checked against a Taylor series algorithmic differentiation.

## References

Andersen, L.B.G. and Lake, M. (2018) [Robust high-precision option pricing by Fourier transforms: Contour deformations and double-exponential quadrature](SSRN 3231626)

Fang, F. and Oosterlee, C. W. (2008) A novel pricing method for European options based on Fourier-cosine series expansions

Healy, J. (2021) Applied Quantitative Finance for Equity Derivatives

Le Floc'h, F. (2020) An adaptive Filon quadrature for stochastic volatility models

### Used By Packages

No packages found.