Note
Go to the end to download the full example code or to run this example in your browser via JupyterLite.
Ikeda-Kunitomo double barriers#
A double knock-out dies if the price leaves a corridor \((L, U)\). Naoto Ikeda and Masaaki Kunitomo (1992) solved it, even for curved (exponential) barriers, with an infinite series of images reflected alternately through both boundaries. The terms decay like \(e^{-2n^2\ln^2(U/L)/\sigma^2T}\), so two or three are plenty unless the corridor is very narrow. Unlike a vanilla call, a double knock-out call loses value as volatility rises: more paths hit a barrier.
import matplotlib.pyplot as plt
import numpy as np
from financialkit.exotic_options import double_barrier_price, plot_barrier_paths
from financialkit.integrators import gbm_paths
K, L, U, T, r = 100.0, 80.0, 130.0, 0.5, 0.05
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
t, paths = gbm_paths(100.0, r, 0.25, T, 100, 40, rng=0)
plot_barrier_paths(t, paths, [L, U], ax=axes[0])

<Axes: title={'center': '12 of 40 paths knocked out'}, xlabel='time t', ylabel='price $S_t$'>
The corridor value and its volatility#
<matplotlib.legend.Legend object at 0x116d77a10>
How many images?#
The error of the series truncated at \(|n| \le N\), against \(N = 20\).
for width, (lo, hi) in (("wide", (60.0, 160.0)), ("medium", (80.0, 130.0)), ("narrow", (95.0, 110.0))):
ref = double_barrier_price(100.0, 100.0, lo, hi, T, r, 0.3, n_terms=20)
err = [abs(double_barrier_price(100.0, 100.0, lo, hi, T, r, 0.3, n_terms=n) - ref) + 1e-17 for n in range(0, 6)]
axes[2].semilogy(range(0, 6), err, "o-", label=f"{width}: ({lo:g}, {hi:g})")
axes[2].set_xlabel("terms N")
axes[2].set_ylabel("truncation error")
axes[2].legend()
fig.tight_layout()
plt.show()
Total running time of the script: (0 minutes 0.730 seconds)