1

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. enter image description here

User2089
  • 31
  • 3

1 Answers1

2

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.

enter image description here

oronimbus
  • 1,901
  • 1
  • 8
  • 22
  • Thank you for your answer. the minimizer you have used needs some starting point which are not available. Morever I have used your correction but I did not have the same shape as yours – User2089 Jan 14 '23 at 13:20
  • 1
    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). – oronimbus Jan 14 '23 at 16:38