I am trying to calibrate SVI model using the following code
import numpy as np
from scipy import optimize
from matplotlib import pyplot as plt
spot = 1.3444
forward = 1.342782
t = 30 / 365.0
vols = np.array([9.420, 9.772, 9.237, 10.144, 9.196, 10.724, 9.265, 11.161, 9.390, 11.908, 9.751]) / 100
strikes = np.array([1.34342148, 1.35800697, 1.32950654, 1.37006384, 1.31948358, 1.38700437, 1.30670715,
1.39978993, 1.29765089, 1.42124726, 1.28287975])
total_implied_variance = t * vols ** 2
def sviraw(k, param):
a = param[0];
b = param[1];
m = param[2];
rho = param[3];
sigma = param[4];
totalvariance = a + b * (rho * (k - m) + np.sqrt((k - m)** 2 + sigma**2));
return totalvariance
def targetfunction(x):
value=0
for i in range(11):
model_total_implied_variance = sviraw(np.log(strikes[i] / forward), x);
value =value+(total_implied_variance[i] - model_total_implied_variance) ** 2;
return value**0.5
bound = [(1e-5, max(total_implied_variance)),(1e-3, 0.99),(min(strikes), max(strikes)),(-0.99, 0.99),(1e-3, 0.99)]
result = optimize.differential_evolution(targetfunction,bound,tol=1e-8)
x=result.x
K = np.linspace(-0.5, 0.5, 60)
newVols = [np.sqrt(sviraw(logmoneyness, x)/t) for logmoneyness in K]
plt.plot(np.log(strikes / forward), vols, marker='o', linestyle='none', label='market')
plt.plot(K, newVols, label='SVI')
plt.title("vol curve")
plt.grid()
plt.legend()
plt.show()
But I am getting the following curve that does not fit the input.


bound. You can use e.g.x_0 = [0, max(total_implied_variance), 0, 1, min(strikes)]but a better approach would be using e.g. what Le Floc'h (2014). – oronimbus Jan 14 '23 at 16:38