# SVI calibration

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));

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.

I'd probably use a different solver, e.g. use BFGS in scipy:
result = optimize.minimize(targetfunction, bound, tol=1e-8, method="BFGS")

That seems to do the job. I don't know much about scipy.optimize.differential_evolution but it seems to fail minimising your loss function.
• I randomly selected the initial guess, in this case it just happened to be the first 5 elements from 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). Commented Jan 14, 2023 at 16:38