Open somdipdatta opened 2 months ago
Furthermore, localvol using scipy RegularGridInterpolator is very slow. (See https://github.com/scipy/scipy/issues/18010) Find alternative. If the grid is uniform, then the index search can be avoided.
An LVMC model that uses this interpolator?
from scipy.interpolate import RegularGridInterpolator
import numpy as np
import time
def create_interp():
times = [0.01, 0.2, 1.0]
strikes = [-5.0, -0.5, -0.1, 0.0, 0.1, 0.5, 5.0]
vols = np.array(
[
[2.713, 0.884, 0.442, 0.222, 0.032, 0.032, 0.032],
[2.187, 0.719, 0.372, 0.209, 0.032, 0.032, 0.032],
[1.237, 0.435, 0.264, 0.200, 0.101, 0.032, 0.032],
]
)
volinterp = RegularGridInterpolator(
(times, strikes), vols, fill_value=None, bounds_error=False
)
return volinterp
def create_interp_two_step():
times = [0.01, 0.2, 1.0]
strikes = [-5.0, -0.5, -0.1, 0.0, 0.1, 0.5, 5.0]
vols = np.array(
[
[2.713, 0.884, 0.442, 0.222, 0.032, 0.032, 0.032],
[2.187, 0.719, 0.372, 0.209, 0.032, 0.032, 0.032],
[1.237, 0.435, 0.264, 0.200, 0.101, 0.032, 0.032],
]
)
t_len = len(times)
def interp(args):
t, x_vec = args
i_left = np.searchsorted(times, t, side="left")
i_right = np.searchsorted(times, t, side="right")
if i_left == i_right:
if i_right == 0:
y = vols[0]
elif i_right == t_len:
y = vols[-1]
else:
i_left -= 1
t_right = times[i_right]
t_left = times[i_left]
den = t_right - t_left
y = (
vols[i_left]
+ (vols[i_right] - vols[i_left]) * (t - t_left) / den
)
else:
y = vols[i_left]
return np.interp(x_vec, strikes, y)
return interp
if __name__ == "__main__":
# interp = create_interp()
interp = create_interp_two_step()
t = 0.1
x_vec = np.linspace(-0.1, 0.1, 100_000)
start = time.time()
for i in range(100):
res = interp((t, x_vec))
end = time.time()
print(f"{end - start:5.4f} {res}")
A prototype is currently implemented in https://github.com/qatwalk/eq/blob/main/src/model/localvol.py
It is generally useful, therefore it should be incorporated in finmc itself.