def setUp(self): settlement_date = today() settings = Settings() settings.evaluation_date = settlement_date daycounter = ActualActual() self.calendar = NullCalendar() i_rate = .1 i_div = .04 self.risk_free_ts = flat_rate(i_rate, daycounter) self.dividend_ts = flat_rate(i_div, daycounter) self.s0 = SimpleQuote(32.0) # Bates model self.v0 = 0.05 self.kappa = 5.0 self.theta = 0.05 self.sigma = 1.0e-4 self.rho = 0.0 self.Lambda = .1 self.nu = .01 self.delta = .001
def flat_rate(forward, daycounter): return FlatForward( forward=SimpleQuote(forward), settlement_days=0, calendar=NullCalendar(), daycounter=daycounter )
def _blsimpv(price, spot, strike, risk_free_rate, time, option_type, dividend): spot = SimpleQuote(spot) daycounter = ActualActual(ISMA) risk_free_ts = FlatForward(today(), risk_free_rate, daycounter) dividend_ts = FlatForward(today(), dividend, daycounter) volatility_ts = BlackConstantVol(today(), NullCalendar(), .3, daycounter) process = BlackScholesMertonProcess(spot, dividend_ts, risk_free_ts, volatility_ts) exercise_date = today() + Period(time * 365, Days) exercise = EuropeanExercise(exercise_date) payoff = PlainVanillaPayoff(option_type, strike) option = EuropeanOption(payoff, exercise) engine = AnalyticEuropeanEngine(process) option.set_pricing_engine(engine) accuracy = 0.001 max_evaluations = 1000 min_vol = 0.01 max_vol = 2 vol = option.implied_volatility(price, process, accuracy, max_evaluations, min_vol, max_vol) return vol
def flat_rate(rate, dc=Actual365Fixed(), reference_date=None): if reference_date is None: return FlatForward(settlement_days=0, calendar=NullCalendar(), forward=rate, daycounter=dc) else: return FlatForward(reference_date, rate, dc)
def test_hull_white_calibration(self): """ Adapted from ShortRateModelTest::testCachedHullWhite() """ today = Date(15, February, 2002) settlement = Date(19, February, 2002) self.settings.evaluation_date = today yield_ts = FlatForward(settlement, forward=0.04875825, settlement_days=0, calendar=NullCalendar(), daycounter=Actual365Fixed()) model = HullWhite(yield_ts, a=0.05, sigma=.005) data = [[1, 5, 0.1148 ], [2, 4, 0.1108 ], [3, 3, 0.1070 ], [4, 2, 0.1021 ], [5, 1, 0.1000 ]] index = Euribor6M(yield_ts) engine = JamshidianSwaptionEngine(model) swaptions = [] for start, length, volatility in data: vol = SimpleQuote(volatility) helper = SwaptionHelper(Period(start, Years), Period(length, Years), vol, index, Period(1, Years), Thirty360(), Actual360(), yield_ts) helper.set_pricing_engine(engine) swaptions.append(helper) # Set up the optimization problem om = LevenbergMarquardt(1.0e-8, 1.0e-8, 1.0e-8) endCriteria = EndCriteria(10000, 100, 1e-6, 1e-8, 1e-8) model.calibrate(swaptions, om, endCriteria) print('Hull White calibrated parameters:\na: %f sigma: %f' % (model.a, model.sigma)) cached_a = 0.0464041 cached_sigma = 0.00579912 tolerance = 1.0e-5 self.assertAlmostEqual(cached_a, model.a, delta=tolerance) self.assertAlmostEqual(cached_sigma, model.sigma, delta=tolerance)
def flat_rate(forward, daycounter): """ Create a flat yield curve, with rate defined according to the specified day-count convention. Used mostly for unit tests and simple illustrations. """ return FlatForward(forward=SimpleQuote(forward), settlement_days=0, calendar=NullCalendar(), daycounter=daycounter)
def setUp(self): self.settings = Settings() self.calendar = NullCalendar() self.today = Date(6, June, 2021) self.settlement_date = self.today + 90 self.settings.evaluation_date = self.today # options parameters self.option_type = Put self.underlying = 80.0 self.strike = 85.0 self.dividend_yield = -0.03 self.risk_free_rate = 0.05 self.volatility = 0.20 # self.maturity = Date(17, May, 1999) self.daycounter = Actual360() self.underlyingH = SimpleQuote(self.underlying) # bootstrap the yield/dividend/vol curves self.flat_term_structure = FlatForward( reference_date=self.today, forward=self.risk_free_rate, daycounter=self.daycounter ) self.flat_dividend_ts = FlatForward( reference_date=self.today, forward=self.dividend_yield, daycounter=self.daycounter ) self.flat_vol_ts = BlackConstantVol( self.today, self.calendar, self.volatility, self.daycounter ) self.black_scholes_merton_process = BlackScholesMertonProcess( self.underlyingH, self.flat_dividend_ts, self.flat_term_structure, self.flat_vol_ts ) self.payoff = PlainVanillaPayoff(self.option_type, self.strike)
def _blsprice(spot, strike, risk_free_rate, time, volatility, option_type='Call', dividend=0.0, calc='price'): """ Black-Scholes option pricing model + greeks. """ _spot = SimpleQuote(spot) daycounter = ActualActual(ISMA) risk_free_ts = FlatForward(today(), risk_free_rate, daycounter) dividend_ts = FlatForward(today(), dividend, daycounter) volatility_ts = BlackConstantVol(today(), NullCalendar(), volatility, daycounter) process = BlackScholesMertonProcess(_spot, dividend_ts, risk_free_ts, volatility_ts) exercise_date = today() + Period(time * 365, Days) exercise = EuropeanExercise(exercise_date) payoff = PlainVanillaPayoff(option_type, strike) option = EuropeanOption(payoff, exercise) engine = AnalyticEuropeanEngine(process) option.set_pricing_engine(engine) if calc == 'price': res = option.npv elif calc == 'delta': res = option.delta elif calc == 'gamma': res = option.gamma elif calc == 'theta': res = option.theta elif calc == 'rho': res = option.rho elif calc == 'vega': res = option.vega elif calc == 'lambda': res = option.delta * spot / option.npv else: raise ValueError('calc type %s is unknown' % calc) return res
def setUp(self): self.settings = Settings() self.calendar = NullCalendar() self.todays_date = Date(15, May, 1998) self.settlement_date = Date(17, May, 1998) self.settings.evaluation_date = self.todays_date # options parameters self.dividend_yield = 0.00 self.risk_free_rate = 0.06 self.volatility = 0.25 self.spot = SimpleQuote(100) self.maturity = Date(17, May, 1999) self.daycounter = Actual365Fixed() self.tol = 1e-2 # bootstrap the yield/dividend/vol curves dates = [self.settlement_date] + \ [self.settlement_date + Period(i + 1, Years) for i in range(40)] rates = [0.01] + \ [0.01 + 0.0002 * np.exp(np.sin(i / 4.0)) for i in range(40)] divRates = [0.02] + \ [0.02 + 0.0001 * np.exp(np.sin(i / 5.0)) for i in range(40)] self.r_ts = ZeroCurve(dates, rates, self.daycounter) self.q_ts = ZeroCurve(dates, divRates, self.daycounter) self.vol_ts = BlackConstantVol( self.settlement_date, self.calendar, self.volatility, self.daycounter ) self.black_scholes_merton_process = BlackScholesMertonProcess( self.spot, self.q_ts, self.r_ts, self.vol_ts ) self.dates = dates
def blsprice(spot, strike, risk_free_rate, time, volatility, option_type='Call', dividend=0.0): """ """ spot = SimpleQuote(spot) daycounter = Actual360() risk_free_ts = FlatForward(today(), risk_free_rate, daycounter) dividend_ts = FlatForward(today(), dividend, daycounter) volatility_ts = BlackConstantVol(today(), NullCalendar(), volatility, daycounter) process = BlackScholesMertonProcess(spot, dividend_ts, risk_free_ts, volatility_ts) exercise_date = today() + 90 exercise = EuropeanExercise(exercise_date) payoff = PlainVanillaPayoff(option_type, strike) option = EuropeanOption(payoff, exercise) engine = AnalyticEuropeanEngine(process) option.set_pricing_engine(engine) return option.npv
settlement_days = 3 face_amount = 100.0 coupon_rate = 0.05 redemption = 100.0 fixed_bond_schedule = Schedule(effective_date, termination_date, Period(Annual), calendar, ModifiedFollowing, ModifiedFollowing, Backward) issue_date = effective_date bond = FixedRateBond(settlement_days, face_amount, fixed_bond_schedule, [coupon_rate], ActualActual(ISMA), Following, redemption, issue_date) discounting_term_structure = YieldTermStructure(relinkable=True) flat_term_structure = FlatForward(settlement_days=1, forward=0.044, calendar=NullCalendar(), daycounter=Actual365Fixed(), compounding=Continuous, frequency=Annual) discounting_term_structure.link_to(flat_term_structure) pricing_engine = DiscountingBondEngine(discounting_term_structure) bond.set_pricing_engine(pricing_engine) print('Settlement date: ', bond.settlement_date()) print('Maturity date:', bond.maturity_date) print('Accrued amount: ', bond.accrued_amount(bond.settlement_date())) print('Clean price:', bond.clean_price)
def test_black_calibration(self): # calibrate a Heston model to a constant volatility surface without # smile. expected result is a vanishing volatility of the volatility. # In addition theta and v0 should be equal to the constant variance todays_date = today() self.settings.evaluation_date = todays_date daycounter = Actual360() calendar = NullCalendar() risk_free_ts = flat_rate(0.04, daycounter) dividend_ts = flat_rate(0.50, daycounter) option_maturities = [ Period(1, Months), Period(2, Months), Period(3, Months), Period(6, Months), Period(9, Months), Period(1, Years), Period(2, Years) ] options = [] s0 = SimpleQuote(1.0) vol = SimpleQuote(0.1) volatility = vol.value for maturity in option_maturities: for moneyness in np.arange(-1.0, 2.0, 1.): tau = daycounter.year_fraction( risk_free_ts.reference_date, calendar.advance( risk_free_ts.reference_date, period=maturity) ) forward_price = s0.value * dividend_ts.discount(tau) / \ risk_free_ts.discount(tau) strike_price = forward_price * np.exp( -moneyness * volatility * np.sqrt(tau) ) options.append( HestonModelHelper( maturity, calendar, s0.value, strike_price, vol, risk_free_ts, dividend_ts ) ) for sigma in np.arange(0.1, 0.7, 0.2): v0 = 0.01 kappa = 0.2 theta = 0.02 rho = -0.75 process = HestonProcess( risk_free_ts, dividend_ts, s0, v0, kappa, theta, sigma, rho ) self.assertEqual(v0, process.v0) self.assertEqual(kappa, process.kappa) self.assertEqual(theta, process.theta) self.assertEqual(sigma, process.sigma) self.assertEqual(rho, process.rho) self.assertEqual(1.0, process.s0().value) model = HestonModel(process) engine = AnalyticHestonEngine(model, 96) for option in options: option.set_pricing_engine(engine) optimisation_method = LevenbergMarquardt(1e-8, 1e-8, 1e-8) end_criteria = EndCriteria(400, 40, 1.0e-8, 1.0e-8, 1.0e-8) model.calibrate(options, optimisation_method, end_criteria) tolerance = 3.0e-3 self.assertFalse(model.sigma > tolerance) self.assertAlmostEqual( model.kappa * model.theta, model.kappa * volatility ** 2, delta=tolerance ) self.assertAlmostEqual(model.v0, volatility ** 2, delta=tolerance)
def test_black_calibration(self): # calibrate a Heston model to a constant volatility surface without # smile. expected result is a vanishing volatility of the volatility. # In addition theta and v0 should be equal to the constant variance todays_date = today() self.settings.evaluation_date = todays_date daycounter = Actual360() calendar = NullCalendar() risk_free_ts = flat_rate(0.04, daycounter) dividend_ts = flat_rate(0.50, daycounter) option_maturities = [ Period(1, Months), Period(2, Months), Period(3, Months), Period(6, Months), Period(9, Months), Period(1, Years), Period(2, Years) ] options = [] s0 = SimpleQuote(1.0) vol = SimpleQuote(0.1) volatility = vol.value for maturity in option_maturities: for moneyness in np.arange(-1.0, 2.0, 1.): tau = daycounter.year_fraction( risk_free_ts.reference_date, calendar.advance( risk_free_ts.reference_date, period=maturity) ) forward_price = s0.value * dividend_ts.discount(tau) / \ risk_free_ts.discount(tau) strike_price = forward_price * np.exp( -moneyness * volatility * np.sqrt(tau) ) options.append( HestonModelHelper( maturity, calendar, s0.value, strike_price, vol, risk_free_ts, dividend_ts ) ) for sigma in np.arange(0.1, 0.7, 0.2): v0 = 0.01 kappa = 0.2 theta = 0.02 rho = -0.75 process = HestonProcess( risk_free_ts, dividend_ts, s0, v0, kappa, theta, sigma, rho ) self.assertEqual(v0, process.v0) self.assertEqual(kappa, process.kappa) self.assertEqual(theta, process.theta) self.assertEqual(sigma, process.sigma) self.assertEqual(rho, process.rho) self.assertEqual(1.0, process.s0.value) model = HestonModel(process) engine = AnalyticHestonEngine(model, 96) for option in options: option.set_pricing_engine(engine) optimisation_method = LevenbergMarquardt(1e-8, 1e-8, 1e-8) end_criteria = EndCriteria(400, 40, 1.0e-8, 1.0e-8, 1.0e-8) model.calibrate(options, optimisation_method, end_criteria) tolerance = 3.0e-3 self.assertFalse(model.sigma > tolerance) self.assertAlmostEqual( model.kappa * model.theta, model.kappa * volatility ** 2, delta=tolerance ) self.assertAlmostEqual(model.v0, volatility ** 2, delta=tolerance)
def test_bsm_hw(self): print("Testing European option pricing for a BSM process" + " with one-factor Hull-White model...") dc = Actual365Fixed() todays_date = today() maturity_date = todays_date + Period(20, Years) settings = Settings() settings.evaluation_date = todays_date spot = SimpleQuote(100) q_ts = flat_rate(todays_date, 0.04, dc) r_ts = flat_rate(todays_date, 0.0525, dc) vol_ts = BlackConstantVol(todays_date, NullCalendar(), 0.25, dc) hullWhiteModel = HullWhite(r_ts, 0.00883, 0.00526) bsm_process = BlackScholesMertonProcess(spot, q_ts, r_ts, vol_ts) exercise = EuropeanExercise(maturity_date) fwd = spot.value * q_ts.discount(maturity_date) / \ r_ts.discount(maturity_date) payoff = PlainVanillaPayoff(Call, fwd) option = VanillaOption(payoff, exercise) tol = 1e-8 corr = [-0.75, -0.25, 0.0, 0.25, 0.75] expectedVol = [ 0.217064577, 0.243995801, 0.256402830, 0.268236596, 0.290461343 ] for c, v in zip(corr, expectedVol): bsm_hw_engine = AnalyticBSMHullWhiteEngine(c, bsm_process, hullWhiteModel) option = VanillaOption(payoff, exercise) option.set_pricing_engine(bsm_hw_engine) npv = option.npv compVolTS = BlackConstantVol(todays_date, NullCalendar(), v, dc) bs_process = BlackScholesMertonProcess(spot, q_ts, r_ts, compVolTS) bsEngine = AnalyticEuropeanEngine(bs_process) comp = VanillaOption(payoff, exercise) comp.set_pricing_engine(bsEngine) impliedVol = comp.implied_volatility(npv, bs_process, 1e-10, 500, min_vol=0.1, max_vol=0.4) if (abs(impliedVol - v) > tol): print("Failed to reproduce implied volatility cor: %f" % c) print("calculated: %f" % impliedVol) print("expected : %f" % v) if abs((comp.npv - npv) / npv) > tol: print("Failed to reproduce NPV") print("calculated: %f" % comp.npv) print("expected : %f" % npv) self.assertAlmostEqual(impliedVol, v, delta=tol) self.assertAlmostEqual(comp.npv / npv, 1, delta=tol)
def test_compare_BsmHW_HestonHW(self): """ From Quantlib test suite """ print("Comparing European option pricing for a BSM " + "process with one-factor Hull-White model...") dc = Actual365Fixed() todays_date = today() settings = Settings() settings.evaluation_date = todays_date tol = 1.e-2 spot = SimpleQuote(100) dates = [todays_date + Period(i, Years) for i in range(40)] rates = [0.01 + 0.0002 * np.exp(np.sin(i / 4.0)) for i in range(40)] divRates = [0.02 + 0.0001 * np.exp(np.sin(i / 5.0)) for i in range(40)] s0 = SimpleQuote(100) r_ts = ZeroCurve(dates, rates, dc) q_ts = ZeroCurve(dates, divRates, dc) vol = SimpleQuote(0.25) vol_ts = BlackConstantVol(todays_date, NullCalendar(), vol.value, dc) bsm_process = BlackScholesMertonProcess(spot, q_ts, r_ts, vol_ts) variance = vol.value * vol.value hestonProcess = HestonProcess(risk_free_rate_ts=r_ts, dividend_ts=q_ts, s0=s0, v0=variance, kappa=5.0, theta=variance, sigma=1e-4, rho=0.0) hestonModel = HestonModel(hestonProcess) hullWhiteModel = HullWhite(r_ts, a=0.01, sigma=0.01) bsmhwEngine = AnalyticBSMHullWhiteEngine(0.0, bsm_process, hullWhiteModel) hestonHwEngine = AnalyticHestonHullWhiteEngine(hestonModel, hullWhiteModel, 128) tol = 1e-5 strikes = [0.25, 0.5, 0.75, 0.8, 0.9, 1.0, 1.1, 1.2, 1.5, 2.0, 4.0] maturities = [1, 2, 3, 5, 10, 15, 20, 25, 30] types = [Put, Call] for type in types: for strike in strikes: for maturity in maturities: maturity_date = todays_date + Period(maturity, Years) exercise = EuropeanExercise(maturity_date) fwd = strike * s0.value * \ q_ts.discount(maturity_date) / \ r_ts.discount(maturity_date) payoff = PlainVanillaPayoff(type, fwd) option = VanillaOption(payoff, exercise) option.set_pricing_engine(bsmhwEngine) calculated = option.npv option.set_pricing_engine(hestonHwEngine) expected = option.npv if ((np.abs(expected - calculated) > calculated * tol) and (np.abs(expected - calculated) > tol)): cp = PAYOFF_TO_STR[type] print("Failed to reproduce npv") print("strike : %f" % strike) print("maturity : %d" % maturity) print("type : %s" % cp) self.assertAlmostEqual(expected, calculated, delta=tol)
def test_compare_bsm_bsmhw_hestonhw(self): dc = Actual365Fixed() todays_date = today() settings = Settings() settings.evaluation_date = todays_date tol = 1.e-2 spot = SimpleQuote(100) dates = [todays_date + Period(i, Years) for i in range(40)] rates = [0.01 + 0.0002 * np.exp(np.sin(i / 4.0)) for i in range(40)] divRates = [0.02 + 0.0001 * np.exp(np.sin(i / 5.0)) for i in range(40)] s0 = SimpleQuote(100) r_ts = ZeroCurve(dates, rates, dc) q_ts = ZeroCurve(dates, divRates, dc) vol = SimpleQuote(0.25) vol_ts = BlackConstantVol(todays_date, NullCalendar(), vol.value, dc) bsm_process = BlackScholesMertonProcess(spot, q_ts, r_ts, vol_ts) payoff = PlainVanillaPayoff(Call, 100) exercise = EuropeanExercise(dates[1]) option = VanillaOption(payoff, exercise) analytic_european_engine = AnalyticEuropeanEngine(bsm_process) option.set_pricing_engine(analytic_european_engine) npv_bsm = option.npv variance = vol.value * vol.value hestonProcess = HestonProcess(risk_free_rate_ts=r_ts, dividend_ts=q_ts, s0=s0, v0=variance, kappa=5.0, theta=variance, sigma=1e-4, rho=0.0) hestonModel = HestonModel(hestonProcess) hullWhiteModel = HullWhite(r_ts, a=0.01, sigma=0.01) bsmhwEngine = AnalyticBSMHullWhiteEngine(0.0, bsm_process, hullWhiteModel) hestonHwEngine = AnalyticHestonHullWhiteEngine(hestonModel, hullWhiteModel, 128) hestonEngine = AnalyticHestonEngine(hestonModel, 144) option.set_pricing_engine(hestonEngine) npv_heston = option.npv option.set_pricing_engine(bsmhwEngine) npv_bsmhw = option.npv option.set_pricing_engine(hestonHwEngine) npv_hestonhw = option.npv print("calculated with BSM: %f" % npv_bsm) print("BSM-HW: %f" % npv_bsmhw) print("Heston: %f" % npv_heston) print("Heston-HW: %f" % npv_hestonhw) self.assertAlmostEqual(npv_bsm, npv_bsmhw, delta=tol) self.assertAlmostEqual(npv_bsm, npv_hestonhw, delta=tol)
def test_replicating_variance_swap(self): """ data from "A Guide to Volatility and Variance Swaps", Derman, Kamal & Zou, 1999 with maturity t corrected from 0.25 to 0.246575 corresponding to Jan 1, 1999 to Apr 1, 1999 """ replicating_option_data = [ { 'type': OptionType.Put, 'strike': 50, 'v': 0.30 }, { 'type': OptionType.Put, 'strike': 55, 'v': 0.29 }, { 'type': OptionType.Put, 'strike': 60, 'v': 0.28 }, { 'type': OptionType.Put, 'strike': 65, 'v': 0.27 }, { 'type': OptionType.Put, 'strike': 70, 'v': 0.26 }, { 'type': OptionType.Put, 'strike': 75, 'v': 0.25 }, { 'type': OptionType.Put, 'strike': 80, 'v': 0.24 }, { 'type': OptionType.Put, 'strike': 85, 'v': 0.23 }, { 'type': OptionType.Put, 'strike': 90, 'v': 0.22 }, { 'type': OptionType.Put, 'strike': 95, 'v': 0.21 }, { 'type': OptionType.Put, 'strike': 100, 'v': 0.20 }, { 'type': OptionType.Call, 'strike': 100, 'v': 0.20 }, { 'type': OptionType.Call, 'strike': 105, 'v': 0.19 }, { 'type': OptionType.Call, 'strike': 110, 'v': 0.18 }, { 'type': OptionType.Call, 'strike': 115, 'v': 0.17 }, { 'type': OptionType.Call, 'strike': 120, 'v': 0.16 }, { 'type': OptionType.Call, 'strike': 125, 'v': 0.15 }, { 'type': OptionType.Call, 'strike': 130, 'v': 0.14 }, { 'type': OptionType.Call, 'strike': 135, 'v': 0.13 }, ] dates = [self.ex_date] call_strikes, put_strikes, call_vols, put_vols = [], [], [], [] # Assumes ascending strikes and same min call and max put strikes for data in replicating_option_data: if data['type'] == OptionType.Call: call_strikes.append(data['strike']) call_vols.append(data['v']) elif data['type'] == OptionType.Put: put_strikes.append(data['strike']) put_vols.append(data['v']) else: raise ValueError("unknown option type") vols = np.zeros((len(replicating_option_data) - 1, 1)) strikes = [] for j, v in enumerate(put_vols): vols[j][0] = v strikes.append(put_strikes[j]) for k in range(1, len(call_vols)): j = len(put_vols) - 1 vols[j + k][0] = call_vols[k] strikes.append(call_strikes[k]) vols_mat = Matrix.from_ndarray(vols) vol_ts = BlackVarianceSurface(self.today, NullCalendar(), dates, strikes, vols_mat, self.dc) stoch_process = BlackScholesMertonProcess(self.spot, self.q_ts, self.r_ts, vol_ts) engine = ReplicatingVarianceSwapEngine(stoch_process, call_strikes, put_strikes, 5.0) variance_swap = VarianceSwap( self.values['type'], self.values['strike'], self.values['nominal'], self.today, self.ex_date, ) variance_swap.set_pricing_engine(engine) calculated = variance_swap.variance expected = self.values['result'] self.assertAlmostEqual(calculated, expected, delta=self.values['tol'])
[ 0.25941, 0.25228, 0.30036, 0.31098, 0.30239, 0.30424, 0.30838, 0.31135, 0.31371, 0.31558, 0.31705, 0.31831, 0.31934, 0.32025, 0.32139, 0.32255, 0.32368, 0.32465, 0.32554, 0.32631, 0.32704, 0.32769, 0.32827, 0.32881 ], [ 0.26127, 0.25202, 0.29568, 0.30506, 0.29631, 0.2984, 0.30283, 0.306, 0.30852, 0.31052, 0.31209, 0.31344, 0.31453, 0.3155, 0.31675, 0.31802, 0.31927, 0.32034, 0.32132, 0.32217, 0.32296, 0.32368, 0.32432, 0.32492 ] ]) vols = Matrix.from_ndarray(data) # Build the Black Variance Surface black_var_surf = BlackVarianceSurface(calculation_date, NullCalendar(), dates, strikes, vols, dc) strike = 600.0 expiry = 0.2 # years # The Surface interpolation routine can be set below (Bilinear is default) #black_var_surf.set_interpolation(Bilinear) #print("black vol bilinear: ", black_var_surf.blackVol(expiry, strike)) #black_var_surf.set_interpolation(Bicubic) #print("black vol bicubic: ", black_var_surf.blackVol(expiry, strike)) local_vol_surface = LocalVolSurface(black_var_surf, flat_term_structure, flat_dividend_ts, spot)