Skip to content
All library documents

Calibrating a Heston Model Across Option Expirations

Article Quant Q&A · Author: user324313

Summary

The question describes using QuantLib to price options from a dataset containing contract start dates, expirations, and strikes. The proposed workflow groups contracts by expiration, supplies implied volatilities and market inputs to Heston model helpers, and optimizes model parameters. The author asks whether fitting parameters separately for each contract or expiration implies different simulated underlying-price behavior, and whether this is an appropriate calibration process.

The material identifies a practical modeling issue: Heston parameters describe a stochastic process, so the scope of calibration matters. Fitting separate parameter sets to individual contracts can produce inconsistent dynamics, whereas calibration typically uses a coherent collection of market option quotes for a given valuation date and shared underlying process. The code and question do not provide a resolution, calibration results, or enough detail to assess data alignment and implementation choices. In particular, the shown loop and inputs leave open how quotes, valuation dates, maturities, rates, dividends, and strikes are selected and synchronized. Treat it as a calibration question rather than evidence that the displayed procedure is valid.

Key ideas

  • Heston parameters govern the dynamics used to simulate the underlying asset.
  • The question groups option inputs by expiration and proposes optimizing model parameters.
  • Calibration scope determines whether contracts share one coherent set of process dynamics.
  • Market quotes and term structures must be aligned with the valuation date and contract maturity.
  • The document raises the modeling question but does not report a calibration answer or results.

Tags

Full text
# Quantlib simulating options with different evaluation dates


# Quantlib simulating options with different evaluation dates












Im given a dataset of option data that looks like this.

```
df:
   start      exp     strike
2013-12-27 2014-01-30 10000
2013-12-27 2014-01-30 10500
2013-12-27 2014-01-30 11500
2014-01-31 2014-02-26 11000
2014-01-31 2014-02-26 12000
2014-01-31 2014-02-26 10000
2014-02-27 2014-03-27 12000
2014-02-27 2014-03-27 13000
2014-02-27 2014-03-27 14000
    .          .        .
    .          .        .
    .          .        .
```

df contains the start & expiration dates and the strike prices of option contracts. My goal is to simulate the option prices per contract. In order to do this, I also simulate the underlying prices using the Heston model. But first I needed to calibrate its parameters using the code below

```
import QuantLib as ql
daycount = ql.Actual365Fixed()
calendar  -ql.UnitedStates()
class Heston(ql.HestonModel):
    def __init__(self,yield_ts, dividend_ts,spot,p,strikes,vol,end, init_params):
        self.init_params=init_params
        self.dividend_ts = dividend_ts
        self.yield_ts = yield_ts
        self.spot =spot 
        self.strikes = strikes
        self.vol =vol
        self.p = p
        self.end = end
        theta, kappa, sigma, rho, v0 = self.init_params
        process=ql.HestonProcess(yield_ts, dividend_ts, ql.QuoteHandle(ql.SimpleQuote(spot)), v0, kappa, theta, sigma, rho)
        super().__init__(process)
        self.engine = ql.AnalyticHestonEngine(self)
        self.vol_surf = ql.HestonBlackVolSurface(ql.HestonModelHandle(self), self.engine.Gatheral)
        self.build_helpers()
               
    def build_helpers(self):
        '''
        Setup the helpers of Heston model based on the following input parameters;
        1. Term structures - yield_ts, dividend_ts
        2. Stock price at expiration date - spot
        3 Week Period between start and end of option contract  - p
        4. Strike - strikes
        5. Implied volatility - vol
        6. parameters- init_params  
        '''

        temp=[]
        self.grid_data = []
        for i, s in enumerate(self.strikes):
            v = self.vol[i]
 
            temp.append( ql.HestonModelHelper(self.p, calendar, int(self.spot), int(s), ql.QuoteHandle(ql.SimpleQuote(float(v))), 
                                              self.yield_ts, self.dividend_ts)  )
 
            self.grid_data.append((self.end,s))
        for x in temp: x.setPricingEngine(self.engine)
        self.helpers=temp 
        self.loss= [x.calibrationError() for x in self.helpers]

for i, (start,exp) in enumerate(zip(df.start.values, df.exp.values)):
    calculation_date = ql.Date(start.day,start.month,start.year)
    expiration_date = ql.Date(exp.day,exp.month,exp.year) 
    
    strikes = df.strikes.loc[df.exp == exp]
    underlying_price = underlying[exp]
    implied_volatility = implied[exp]
    risk_free_rate = riskrate[exp]
    dividend_yield = dividendrate[exp]
    ##Creating term structures## 
    yield_ts = ql.YieldTermStructureHandle(ql.FlatForward(calculation_date, risk_free_interest, dayCount)) 
    dividend_ts = ql.YieldTermStructureHandle(ql.FlatForward(calculation_date,dividend_yield, dayCount))

    t = calendar.businessDaysBetween(calculation_date, expiration_date)
    p = ql.Period(t, ql.Days)
    # build the heston helpers to be used for calculation
    h = Heston(yield_ts,dividend_ts,underlying,p,dum.strikes.values,
            dum.imp.values,expiration_date,init_params=params)
```

`underlying`,`implied`,`riskrate`, and `dividendrate` are dictionaries that contain the information per expiration date of a contract. After this process, I use some optimization techniques to get the parameters. Im kinda confused because since im calibrating the parameters of heston per option contract then does this mean that the behavior of the underlying stock price will also be different? Is this the right process to do it? If not, please someone enlighten me.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.