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 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 test_hull_white_creation(self): """ Basic instantiation of a Hull-White model """ today = Date(15, February, 2002) self.settings.evaluation_date = today yield_ts = flat_rate(forward=0.04875825, daycounter=Actual360()) model = HullWhite(yield_ts, a=0.0001, sigma=.1) p = model.params() self.assertEqual(p[0], model.a) self.assertAlmostEqual(p[1], model.sigma)
def test_hull_white_creation(self): """ Basic instantiation of a Hull-White model """ today = Date(15, February, 2002) self.settings.evaluation_date = today yield_ts = flat_rate(forward=0.04875825, daycounter=Actual360()) model = HullWhite(yield_ts, a=0.0001, sigma=.1) p = model.params() self.assertEqual(p[0], model.a) self.assertAlmostEqual(p[1], model.sigma)
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)