Exact Simulation Workbook

This runs a couple of simulations to demonstrate the "exact" method for selected one dimensional processes.

First, it runs a simulation of equations 5.1 and 5.2 from the reference paper using the Euler scheme. The code outputs (some of) the paths generated. It also outputs the volatility smile. Note that the volatility smile matches the smile in Figure 1 on page 18 of the reference paper.

Next, it runs a simulation of the same two processes, this time using the "exact" method. The smiles for both equations and simulation types are saved in the data.frame allImpVols for a plot comparison at the end.

The output for each method is the $E[max(X_T-K, 0)]$ for a range of K, along with the implied volatility. Each method also generates a plot of (some of) the simulated paths.

Also included are two toy examples for a mean reverting and a linear deterministic drift process, though they appear insufficient at the moment.


In [1]:
source('coefficients.r')
source('general_euler.r')
source('driftless_exact.r')
source('drifted_exact.r')
source('simulations.r')

Global Parameters


In [2]:
T <- 1
X0 <- 1
strikes <- seq(0.6, 1.5, by=0.1)
allImpVols <- data.frame(K=strikes) # Save to global object for overlaid plots

Euler scheme

Parameters


In [10]:
numPathsEuler <- 100000
numStepsEuler <- 100

Driftless process (equation 5.1)

$$ X_0=1, \,\,\,\, dX_t=\frac{2\sigma}{1+X_t^2}dW_t $$

In [4]:
# Some other mu and sigma functions to try out
#sigma <- make_affine_coefficient(1, 0) # Black-Scholes with sigma <- 1
#mu <- make_mean_reverting_coefficient(0.8, 1.0)
#sigma <- make_constant_coefficient(1)

euler51_process <- General_Euler(numPathsEuler, numStepsEuler,
                                 mu=make_constant_coefficient(0),
                                 sigma=sigma_from_paper,
                                 T=T, X0=X0)
run_euler(euler51_process, strikes, T, X0, make_call_payoff, saveColumn='Euler 5.1')


     K       price implied.vol
1  0.6 0.455488580   0.6281230
2  0.7 0.372404542   0.5584488
3  0.8 0.294480052   0.4995221
4  0.9 0.223292453   0.4489999
5  1.0 0.160506109   0.4050818
6  1.1 0.107730927   0.3664784
7  1.2 0.066328833   0.3326321
8  1.3 0.036703417   0.3031279
9  1.4 0.017671503   0.2767620
10 1.5 0.007135797   0.2531539

Drifted process (equation 5.2)

$$ Y_0=0, \,\,\,\, dY_t = \frac{2\sigma X_t}{\left(1+X_t^2\right)^2}dt+dW_t \,\,\,\, \mbox{where} \,\,\,\, 2\sigma Y_t = X_t-X_0+\frac{X_t^3 - X_0^3}3 $$

In [11]:
euler52_process <- General_Euler(numPathsEuler, numStepsEuler,
                                 mu_from_paper,
                                 sigma=make_constant_coefficient(1),
                                 T=T, X0=X0,
                                 convert_y_to_x=convert_y_to_x_1d,
                                 convert_x_to_y=convert_x_to_y_1d)
run_euler(euler52_process, strikes, T, X0, make_call_payoff, saveColumn='Euler 5.2')


     K       price implied.vol
1  0.6 0.456038338   0.6307215
2  0.7 0.372744755   0.5597479
3  0.8 0.294793239   0.5005225
4  0.9 0.223559448   0.4497435
5  1.0 0.160743657   0.4056896
6  1.1 0.108085286   0.3673693
7  1.2 0.066698774   0.3336291
8  1.3 0.037002525   0.3040942
9  1.4 0.017879348   0.2776905
10 1.5 0.007257338   0.2540541

Exact method

Parameters


In [4]:
numPathsExact <- 100000
beta <- 0.2

Driftless process (equation 5.1)

$$ X_0=1, \,\,\,\, dX_t=\frac{2\sigma}{1+X_t^2}dW_t $$

In [7]:
exact51_process <- Driftless_Exact(numPathsExact, beta, sigma_from_paper, sigma_deriv_from_paper, T, X0)
run_exact(exact51_process, strikes, T, X0, make_call_payoff, saveColumn='Exact 5.1')


     K       price implied.vol
1  0.6 0.456869377   0.6346382
2  0.7 0.372522078   0.5588977
3  0.8 0.294288719   0.4989108
4  0.9 0.223048340   0.4483199
5  1.0 0.160357740   0.4047022
6  1.1 0.107874792   0.3668401
7  1.2 0.066589766   0.3333354
8  1.3 0.037119059   0.3044701
9  1.4 0.017360816   0.2753654
10 1.5 0.006707502   0.2499145

Drifted process (equation 5.2)

$$ Y_0=0, \,\,\,\, dY_t = \frac{2\sigma X_t}{\left(1+X_t^2\right)^2}dt+dW_t \,\,\,\, \mbox{where} \,\,\,\, 2\sigma Y_t = X_t-X_0+\frac{X_t^3 - X_0^3}3 $$

In [8]:
exact52_process <- Drifted_Exact(numPathsExact, beta,
                                 mu_from_paper,
                                 sigma0=1,
                                 T=T, X0=X0,
                                 convert_y_to_x=convert_y_to_x_1d,
                                 convert_x_to_y=convert_x_to_y_1d)
run_exact(exact52_process, strikes, T, X0, make_call_payoff, saveColumn='Exact 5.2')


     K       price implied.vol
1  0.6 0.456626343   0.6334942
2  0.7 0.374661379   0.5670482
3  0.8 0.297464443   0.5090441
4  0.9 0.226802350   0.4587756
5  1.0 0.164179420   0.4144847
6  1.1 0.111679569   0.3764012
7  1.2 0.070038925   0.3425956
8  1.3 0.039796876   0.3130189
9  1.4 0.019894414   0.2864734
10 1.5 0.008548289   0.2631619

Comparing Implied Volatilities

The following plot aims to mirror Figure 1 on page 18 of the reference paper.


In [9]:
matplot(allImpVols$K, allImpVols[names(allImpVols)!='K']*100,
        xlab='K', ylab='Imp. Vol. x 100', type='l', lty=1, las=1)
legend('topright', inset=.2, legend=names(allImpVols)[names(allImpVols)!='K'], lty=1, col=1:(ncol(allImpVols)-1))


Further Examples

These appear broken at this time. Possibly non-convergent/invalid stock processes.

Example mean reverting process

$$ X_0=1, \,\,\,\, dX_t=0.8(X_t-1)dt+dW_t $$

In [ ]:
drifted_process <- Drifted_Exact(numPathsExact, beta,
                                 mu=make_mean_reverting_coefficient(-.8, 1),
                                 sigma0=1,
                                 T=T, X0=1)
run_exact(drifted_process, strikes, T, X0, saveColumn='Mean Reverting Exact')

Example linear drift process

$$ X_0=1, \,\,\,\, dX_t=tdt+dW_t $$

In [ ]:
lin_drift_euler_process <- General_Euler(numPathsEuler, numStepsEuler,
                                         mu=function(t,x) t,
                                         sigma=make_constant_coefficient(1),
                                         X0=1)
run_euler(lin_drift_euler_process, strikes, T, X0=1, saveColumn='Linear Drift Euler')

lin_drift_exact_process <- Drifted_Exact(numPathsExact, beta, mu=function(t,x) t, sigma0=1, X0=1)
run_exact(lin_drift_exact_process, strikes, T, X0=1, saveColumn='Linear Drift Exact')