0
$\begingroup$

Does anyone have experience with the Python QuantLib function HestonBlackVolSurface? I'm trying to produce a 3D plot of the volatility surface as done in the example

http://gouthamanbalaraman.com/blog/volatility-smile-heston-model-calibration-quantlib-python.html

Here is my attempt, based on the data of the example

import QuantLib as quant
heston_vol_surface = quant.HestonBlackVolSurface(
                        quant.HestonModelHandle(model),
                        quant.AnalyticHestonEngine.Gatheral)

strikes_grid = np.arange(strikes[0], strikes[-1],10)
expiry = 1.0
implied_vols = [heston_vol_surface.blackVol(expiry, s)
                for s in strikes_grid]

I understand that I need to pass the the volatility term structure, but my knowledge of QuantLib is too limited right now. Thanks for you help.

$\endgroup$
3
$\begingroup$

Here is something I did, maybe it helps:

https://colab.research.google.com/drive/1M1YJncdswd-A9SgIOAjw6g6Se7NHU9mG?usp=sharing

$\endgroup$
2
  • 2
    $\begingroup$ You should include the content from your link. It would be helpful for future viewers should the link break. $\endgroup$
    – amdopt
    May 20 '20 at 13:21
  • $\begingroup$ @Ege Yilmaz thanks, that really helped a lot! $\endgroup$
    – FunnyBuzer
    May 21 '20 at 11:05
3
$\begingroup$

Here is a snip that will create and plot a Heston vol surface

import numpy as np
import QuantLib as ql
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# Utility function to plot vol surfaces (can pass in ql.BlackVarianceSurface objects too)
def plot_vol_surface(vol_surface, plot_years=np.arange(0.1, 2, 0.1), plot_strikes=np.arange(80, 120, 1)):
    fig = plt.figure()
    ax = fig.gca(projection='3d')

    X, Y = np.meshgrid(plot_strikes, plot_years)
    Z = np.array([vol_surface.blackVol(float(y), float(x)) 
                  for xr, yr in zip(X, Y) 
                      for x, y in zip(xr,yr) ]
                 ).reshape(len(X), len(X[0]))

    surf = ax.plot_surface(X,Y,Z, rstride=1, cstride=1, linewidth=0.1)

    fig.colorbar(surf, shrink=0.5, aspect=5)

# World State setup
spot = 100
rate = 0.0
today = ql.Date(1, 7, 2020)

# Set up the flat risk-free curves
riskFreeCurve = ql.FlatForward(today, rate, ql.Actual365Fixed())
flat_ts = ql.YieldTermStructureHandle(riskFreeCurve)
dividend_ts = ql.YieldTermStructureHandle(riskFreeCurve)

# Setting up a Heston model with dummy parameters (roughly 10% constant BS vol)
v0 = 0.01; kappa = 0.01; theta = 0.01; rho = 0.0; sigma = 0.01

process = ql.HestonProcess(flat_ts, dividend_ts, ql.QuoteHandle(ql.SimpleQuote(spot)), v0, kappa, theta, sigma, rho)

# Boilerplate to get to the Vol Surface object
heston_model = ql.HestonModel(process)
heston_handle = ql.HestonModelHandle(heston_model)
heston_vol_surface = ql.HestonBlackVolSurface(heston_handle)

# Plot the vol surface ...
plot_vol_surface(heston_vol_surface)

Produces:

Heston Vol Surface

$\endgroup$
2
  • $\begingroup$ thanks for sharing your code! I noticed that the Feller condition is not guaranteed to hold when performing the calibration. Are you aware of any way to impose it when calibrating the parameters? $\endgroup$
    – FunnyBuzer
    Oct 6 '20 at 13:06
  • $\begingroup$ Good question. It depends how you calibrate. The most common calibration method for Heston is least-squares via the Levenberg-Marquardt method. Many other techniques are possible, several are discussed in this excellent blog post: gouthamanbalaraman.com/blog/…. In particular, you could very easily include a penalty term for Feller in any of the cost functions, which would encourage your fitter to keep it positive (at the cost of a less-good fit to observed vanilla prices) $\endgroup$
    – StackG
    Oct 6 '20 at 14:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.