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 setUp(self): self.calendar = TARGET() self.today = Date(9, 6, 2009) settlement_date = self.calendar.advance(self.today, 2, Days) Settings().evaluation_date = self.today rates = [0.035, 0.035, 0.033, 0.034, 0.034, 0.036, 0.037, 0.039, 0.04] ts = [13, 41, 75, 165, 256, 345, 524, 703] dates = [settlement_date] + [self.calendar.advance(self.today, d, Days) for d in ts] self.day_counter = Actual360() self.term_structure = ZeroCurve(dates, rates, self.day_counter) self.spreads = [SimpleQuote(0.02), SimpleQuote(0.03)] self.spread_dates = [self.calendar.advance(self.today, 8, Months), self.calendar.advance(self.today, 15, Months)] self.spreaded_term_structure = PiecewiseZeroSpreadedTermStructure( self.term_structure, self.spreads, self.spread_dates) self.spreaded_term_structure.extrapolation = True
def test_zanette(self): """ From paper by A. Zanette et al. """ dc = Actual365Fixed() todays_date = today() settings = Settings() settings.evaluation_date = todays_date # constant yield and div curves dates = [todays_date + Period(i, Years) for i in range(3)] rates = [0.04 for i in range(3)] divRates = [0.03 for i in range(3)] r_ts = ZeroCurve(dates, rates, dc) q_ts = ZeroCurve(dates, divRates, dc) s0 = SimpleQuote(100) # Heston model v0 = .1 kappa_v = 2 theta_v = 0.1 sigma_v = 0.3 rho_sv = -0.5 hestonProcess = HestonProcess(risk_free_rate_ts=r_ts, dividend_ts=q_ts, s0=s0, v0=v0, kappa=kappa_v, theta=theta_v, sigma=sigma_v, rho=rho_sv) hestonModel = HestonModel(hestonProcess) # Hull-White kappa_r = 1 sigma_r = .2 hullWhiteProcess = HullWhiteProcess(r_ts, a=kappa_r, sigma=sigma_r) strike = 100 maturity = 1 type = Call maturity_date = todays_date + Period(maturity, Years) exercise = EuropeanExercise(maturity_date) payoff = PlainVanillaPayoff(type, strike) option = VanillaOption(payoff, exercise) def price_cal(rho, tGrid): fd_hestonHwEngine = FdHestonHullWhiteVanillaEngine( hestonModel, hullWhiteProcess, rho, tGrid, 100, 40, 20, 0, True, FdmSchemeDesc.Hundsdorfer()) option.set_pricing_engine(fd_hestonHwEngine) return option.npv calc_price = [] for rho in [-0.5, 0, .5]: for tGrid in [50, 100, 150, 200]: tmp = price_cal(rho, tGrid) print("rho (S,r): %f Ns: %d Price: %f" % (rho, tGrid, tmp)) calc_price.append(tmp) expected_price = [ 11.38, ] * 4 + [ 12.79, ] * 4 + [ 14.06, ] * 4 np.testing.assert_almost_equal(calc_price, expected_price, 2)
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)
forward=SimpleQuote(forward), daycounter=daycounter) dc = Actual365Fixed() todays_date = today() settings = Settings() settings.evaluation_date = todays_date # constant yield and div curves dates = [todays_date + Period(i, Years) for i in range(3)] rates = [0.04 for i in range(3)] divRates = [0.03 for i in range(3)] r_ts = ZeroCurve(dates, rates, dc) q_ts = ZeroCurve(dates, divRates, dc) s0 = SimpleQuote(100) # Heston model v0 = .1 kappa_v = 2 theta_v = 0.1 sigma_v = 0.3 rho_sv = -0.5 hestonProcess = HestonProcess(risk_free_rate_ts=r_ts, dividend_ts=q_ts, s0=s0,
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 option_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(option_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)): print("Failed to reproduce npv") print("strike : %f" % strike) print("maturity : %d" % maturity) print("type : %s" % option_type.name) self.assertAlmostEqual(expected, calculated, delta=tol)
class TestPiecewiseZeroSpreadedTermStructure(unittest.TestCase): def setUp(self): self.calendar = TARGET() self.today = Date(9, 6, 2009) settlement_date = self.calendar.advance(self.today, 2, Days) Settings().evaluation_date = self.today rates = [0.035, 0.035, 0.033, 0.034, 0.034, 0.036, 0.037, 0.039, 0.04] ts = [13, 41, 75, 165, 256, 345, 524, 703] dates = [settlement_date] + [self.calendar.advance(self.today, d, Days) for d in ts] self.day_counter = Actual360() self.term_structure = ZeroCurve(dates, rates, self.day_counter) self.spreads = [SimpleQuote(0.02), SimpleQuote(0.03)] self.spread_dates = [self.calendar.advance(self.today, 8, Months), self.calendar.advance(self.today, 15, Months)] self.spreaded_term_structure = PiecewiseZeroSpreadedTermStructure( self.term_structure, self.spreads, self.spread_dates) self.spreaded_term_structure.extrapolation = True def test_flat_interpolation_left(self): interpolation_date = self.calendar.advance(self.today, 6, Months) t = self.day_counter.year_fraction(self.today, interpolation_date) interpolated_zero_rate = (self.spreaded_term_structure. zero_rate(t, compounding=Continuous).rate) expected_rate = self.term_structure.zero_rate(t, compounding=Continuous).rate + \ self.spreads[0].value self.assertAlmostEqual(interpolated_zero_rate, expected_rate) def test_flat_interpolation_right(self): interpolation_date = self.calendar.advance(self.today, 20, Months) t = self.day_counter.year_fraction(self.today, interpolation_date) interpolated_zero_rate = (self.spreaded_term_structure. zero_rate(t, compounding=Continuous).rate) expected_rate = self.term_structure.zero_rate(t, compounding=Continuous).rate + \ self.spreads[1].value self.assertAlmostEqual(interpolated_zero_rate, expected_rate) def test_linear_interpolation(self): interpolation_date = self.calendar.advance(self.today, 12, Months) t = self.term_structure.time_from_reference(interpolation_date) t1 = self.term_structure.time_from_reference(self.spread_dates[0]) t2 = self.term_structure.time_from_reference(self.spread_dates[1]) interpolated_zero_rate = (self.spreaded_term_structure. zero_rate(t, compounding=Continuous).rate) zero_rate = (self.term_structure. zero_rate(t, compounding=Continuous, frequency=NoFrequency)) expected_rate = zero_rate.rate + \ (t - t1) / (t2 - t1 ) * self.spreads[1].value + \ (t2 - t) / (t2 - t1) * self.spreads[0].value spreaded_rate = InterestRate(expected_rate, zero_rate.day_counter, zero_rate.compounding, zero_rate.frequency) self.assertAlmostEqual(interpolated_zero_rate, spreaded_rate.equivalent_rate(Continuous, NoFrequency, t).rate)