domokane / FinancePy

A Python Finance Library that focuses on the pricing and risk-management of Financial Derivatives, including fixed-income, equity, FX and credit derivatives.
GNU General Public License v3.0
2.08k stars 316 forks source link

SSVI Calibration: Divide by Zero Error #90

Open armarion opened 3 years ago

armarion commented 3 years ago

I'm attempting to fit an SSVI surface to equity vols following the example in the notebook below, but using SSVI. When I try to fit SSVI though it produces a division by zero error. Am I doing something wrong?

https://github.com/domokane/FinancePy/blob/master/notebooks/market/volatility/EquityVolSurfaceConstructionSVI.ipynb

Full code and traceback

`import numpy as np import matplotlib.pyplot as plt from financepy.market.curves.FinDiscountCurveFlat import FinDiscountCurveFlat from financepy.market.volatility.FinEquityVolSurface import FinEquityVolSurface from financepy.finutils.FinDate import FinDate from financepy.models.FinModelVolatilityFns import FinVolFunctionTypes valueDate = FinDate(11, 1, 2021) stockPrice = 3800.0 # Check expiryDates = [FinDate(11, 2, 2021), FinDate(11, 3, 2021), FinDate(11, 4, 2021), FinDate(11, 7, 2021), FinDate(11,10, 2021), FinDate(11, 1, 2022), FinDate(11, 1, 2023)] strikes = np.array([3037, 3418, 3608, 3703, 3798, 3893, 3988, 4178, 4557], dtype=float) volSurface = [[42.94, 31.30, 25.88, 22.94, 19.72, 16.90, 15.31, 17.54, 25.67], [37.01, 28.25, 24.19, 21.93, 19.57, 17.45, 15.89, 15.34, 21.15], [34.68, 27.38, 23.82, 21.85, 19.83, 17.98, 16.52, 15.31, 18.94], [31.41, 26.25, 23.51, 22.05, 20.61, 19.25, 18.03, 16.01, 15.90], [29.91, 25.58, 23.21, 22.01, 20.83, 19.70, 18.62, 16.63, 14.94], [29.26, 25.24, 23.03, 21.91, 20.81, 19.73, 18.69, 16.76, 14.63], [27.59, 24.33, 22.72, 21.93, 21.17, 20.43, 19.71, 18.36, 16.26]] volSurface = np.array(volSurface) volSurface = volSurface / 100.0 rfrRate = 0.020 # USD discountCurve = FinDiscountCurveFlat(valueDate, rfrRate) divRate = 0.010 # USD dividendCurve = FinDiscountCurveFlat(valueDate, divRate) volFunctionType = FinVolFunctionTypes.SSVI equitySurface = FinEquityVolSurface(valueDate, stockPrice, discountCurve,dividendCurve, expiryDates,strikes,volSurface, volFunctionType) tol = 1e-4 equitySurface.checkCalibration(False, tol)

Failed to converge, will try CG Traceback (most recent call last): File "C:\Users\armar\anaconda3\lib\site-packages\financepy\market\volatility\FinEquityVolSurface.py", line 116, in _solveToHorizon opt = minimize(_obj, xinits, args, method="Nelder-Mead", tol=tol) File "C:\Users\armar\anaconda3\lib\site-packages\scipy\optimize_minimize.py", line 606, in minimize return _minimize_neldermead(fun, x0, args, callback, *options) File "C:\Users\armar\anaconda3\lib\site-packages\scipy\optimize\optimize.py", line 689, in _minimize_neldermead fsim[k] = func(sim[k]) File "C:\Users\armar\anaconda3\lib\site-packages\scipy\optimize\optimize.py", line 427, in function_wrapper return function((wrapper_args + args)) ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\Users\armar\anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 3418, in run_code exec(code_obj, self.user_global_ns, self.user_ns) File "", line 39, in equitySurface = FinEquityVolSurface(valueDate, File "C:\Users\armar\anaconda3\lib\site-packages\financepy\market\volatility\FinEquityVolSurface.py", line 277, in init self._buildVolSurface(finSolverType=finSolverType) File "C:\Users\armar\anaconda3\lib\site-packages\financepy\market\volatility\FinEquityVolSurface.py", line 638, in _buildVolSurface res = _solveToHorizon(s, t, r, q, File "C:\Users\armar\anaconda3\lib\site-packages\financepy\market\volatility\FinEquityVolSurface.py", line 125, in _solveToHorizon opt = minimize(_obj, xinits, args, method="CG", tol=tol) File "C:\Users\armar\anaconda3\lib\site-packages\scipy\optimize_minimize.py", line 610, in minimize return _minimize_cg(fun, x0, args, jac, callback, *options) File "C:\Users\armar\anaconda3\lib\site-packages\scipy\optimize\optimize.py", line 1423, in _minimize_cg sf = _prepare_scalar_function(fun, x0, jac=jac, args=args, epsilon=eps, File "C:\Users\armar\anaconda3\lib\site-packages\scipy\optimize\optimize.py", line 261, in _prepare_scalar_function sf = ScalarFunction(fun, x0, args, grad, hess, File "C:\Users\armar\anaconda3\lib\site-packages\scipy\optimize_differentiable_functions.py", line 76, in init self._update_fun() File "C:\Users\armar\anaconda3\lib\site-packages\scipy\optimize_differentiable_functions.py", line 166, in _update_fun self._update_fun_impl() File "C:\Users\armar\anaconda3\lib\site-packages\scipy\optimize_differentiable_functions.py", line 73, in update_fun self.f = fun_wrapped(self.x) File "C:\Users\armar\anaconda3\lib\site-packages\scipy\optimize_differentiable_functions.py", line 70, in fun_wrapped return fun(x, args) ZeroDivisionError: division by zero `

domokane commented 3 years ago

There is an issue with the starting parameters for the calibration. I will look at this as soon as I get time. It may be a while. Unless you would like to investigate it.

abhi-g80 commented 3 years ago

I am not getting division by zero error but the fit doesn't seem to good. Example, Screenshot 2021-08-03 at 23 24 40

domokane commented 3 years ago

This needs further work. I will look at it as soon as I can.