def test_extrapolation(self): rate_helpers = build_helpers() settings = Settings() calendar = TARGET() # must be a business Days dtObs = date(2007, 4, 27) eval_date = calendar.adjust(pydate_to_qldate(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) print('dt Obs: %s\ndt Eval: %s\ndt Settle: %s' % (dtObs, eval_date, settlement_date)) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-2 ts = PiecewiseYieldCurve('discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) # max_date raises an exception without extrapolaiton... self.assertFalse(ts.extrapolation) with self.assertRaisesRegexp( RuntimeError, "1st iteration: failed at 2nd alive instrument"): dtMax = ts.max_date
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 test_extrapolation(self): rate_helpers = build_helpers() settings = Settings() calendar = TARGET() # must be a business Days dtObs = date(2007, 4, 27) eval_date = calendar.adjust(pydate_to_qldate(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) print('dt Obs: %s\ndt Eval: %s\ndt Settle: %s' % (dtObs, eval_date, settlement_date)) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-2 ts = PiecewiseYieldCurve.from_reference_date(BootstrapTrait.Discount, Interpolator.LogLinear, settlement_date, rate_helpers, ts_day_counter, tolerance) # max_date raises an exception without extrapolaiton... self.assertFalse(ts.extrapolation) with self.assertRaises(RuntimeError) as ctx: ts.discount(ts.max_date + 1) self.assertTrue(str(ctx.exception) in ( "time (30.011) is past max curve time (30.0082)", "1st iteration: failed at 2nd alive instrument"))
def test_bump_yieldcurve(self): settings = Settings() settings.evaluation_date = Date(6, 10, 2016) # Market information calendar = TARGET() quotes = [SimpleQuote(0.0096), SimpleQuote(0.0145), SimpleQuote(0.0194)] tenors = [3, 6, 12] deposit_day_counter = Actual365Fixed() convention = ModifiedFollowing end_of_month = True fixing_days = 3 rate_helpers = [DepositRateHelper( quote, Period(month, Months), fixing_days, calendar, convention, end_of_month, deposit_day_counter) for quote, month in zip(quotes, tenors)] ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = PiecewiseYieldCurve( BootstrapTrait.Discount, Interpolator.LogLinear, 2, calendar, rate_helpers, ts_day_counter, tolerance ) old_discount = ts.discount(ts.max_date) # parallel shift of 1 bps for rh in rate_helpers: rh.quote.value += 1e-4 self.assertEqual([q.value for q in quotes], [rh.quote.value for rh in rate_helpers]) new_discount = ts.discount(ts.max_date) self.assertTrue(new_discount < old_discount)
def test_extrapolation(self): rate_helpers = build_helpers() settings = Settings() calendar = TARGET() # must be a business Days dtObs = date(2007, 4, 27) eval_date = calendar.adjust(pydate_to_qldate(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) print('dt Obs: %s\ndt Eval: %s\ndt Settle: %s' % (dtObs, eval_date, settlement_date)) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-2 ts = PiecewiseYieldCurve.from_reference_date(BootstrapTrait.Discount, Interpolator.LogLinear, settlement_date, rate_helpers, ts_day_counter, tolerance) # max_date raises an exception without extrapolaiton... self.assertFalse(ts.extrapolation)
def bootstrap_term_structure(self, interpolator=Interpolator.LogLinear): tolerance = 1.0e-15 settings = Settings() calendar = JointCalendar(UnitedStates(), UnitedKingdom()) # must be a business day eval_date = self._eval_date settings.evaluation_date = eval_date settlement_days = self._params.settlement_days settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) ts = PiecewiseYieldCurve.from_reference_date( BootstrapTrait.Discount, interpolator, settlement_date, self._rate_helpers, DayCounter.from_name(self._termstructure_daycount), tolerance, ) self._term_structure = ts self._discount_term_structure = YieldTermStructure() self._discount_term_structure.link_to(ts) self._forecast_term_structure = YieldTermStructure() self._forecast_term_structure.link_to(ts) return ts
def test_extrapolation(self): rate_helpers = build_helpers() settings = Settings() calendar = TARGET() # must be a business Days dtObs = date(2007, 4, 27) eval_date = calendar.adjust(pydate_to_qldate(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) print('dt Obs: %s\ndt Eval: %s\ndt Settle: %s' % (dtObs, eval_date, settlement_date)) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-2 ts = PiecewiseYieldCurve('discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) # max_date raises an exception without extrapolaiton... self.assertFalse(ts.extrapolation) with self.assertRaisesRegexp(RuntimeError, "1st iteration: failed at 2nd alive instrument"): dtMax = ts.max_date
def test_zero_curve(self): rate_helpers = build_helpers() settings = Settings() calendar = TARGET() # must be a business Days dtObs = date(2007, 4, 27) eval_date = calendar.adjust(pydate_to_qldate(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-2 ts = PiecewiseYieldCurve('discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) # max_date raises an exception... ts.extrapolation = True zr = ts.zero_rate(Date(10, 5, 2027), ts_day_counter, 2) self.assertAlmostEqual(zr.rate, 0.0539332)
def bootstrap_term_structure(self, interpolator=LogLinear): tolerance = 1.0e-15 settings = Settings() calendar = JointCalendar(UnitedStates(), UnitedKingdom()) # must be a business day eval_date = self._eval_date settings.evaluation_date = eval_date settlement_days = self._params.settlement_days settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) ts = PiecewiseYieldCurve[BootstrapTrait.Discount, interpolator].from_reference_date( settlement_date, self._rate_helpers, DayCounter.from_name( self._termstructure_daycount), accuracy=tolerance) self._term_structure = ts self._discount_term_structure = YieldTermStructure() self._discount_term_structure.link_to(ts) self._forecast_term_structure = YieldTermStructure() self._forecast_term_structure.link_to(ts) return ts
def test_zero_curve(self): rate_helpers = build_helpers() settings = Settings() calendar = TARGET() # must be a business Days dtObs = date(2007, 4, 27) eval_date = calendar.adjust(pydate_to_qldate(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-2 ts = PiecewiseYieldCurve.from_reference_date(BootstrapTrait.Discount, Interpolator.LogLinear, settlement_date, rate_helpers, ts_day_counter, tolerance) # max_date raises an exception... ts.extrapolation = True zr = ts.zero_rate(Date(10, 5, 2027), ts_day_counter, 2) self.assertAlmostEqual(zr.rate, 0.0539332, 6)
def test_extrapolation(self): rate_helpers = build_helpers() settings = Settings() calendar = TARGET() # must be a business Days dtObs = date(2007, 4, 27) eval_date = calendar.adjust(pydate_to_qldate(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) print('dt Obs: %s\ndt Eval: %s\ndt Settle: %s' % (dtObs, eval_date, settlement_date)) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-2 ts = PiecewiseYieldCurve.from_reference_date(BootstrapTrait.Discount, Interpolator.LogLinear, settlement_date, rate_helpers, ts_day_counter, tolerance) # max_date raises an exception without extrapolaiton... self.assertFalse(ts.extrapolation) with self.assertRaises(RuntimeError) as ctx: ts.discount(ts.max_date + 1) self.assertTrue( str(ctx.exception) in ( "time (30.011) is past max curve time (30.0082)", "1st iteration: failed at 2nd alive instrument"))
def test_discount_curve(self): settings = Settings() settings.evaluation_date = Date(6, 10, 2016) # Market information calendar = TARGET() quotes = [SimpleQuote(0.0096), SimpleQuote(0.0145), SimpleQuote(0.0194)] tenors = [3, 6, 12] deposit_day_counter = Actual365Fixed() convention = ModifiedFollowing end_of_month = True fixing_days = 3 rate_helpers = [DepositRateHelper( quote, Period(month, Months), fixing_days, calendar, convention, end_of_month, deposit_day_counter) for quote, month in zip(quotes, tenors)] ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = PiecewiseYieldCurve( BootstrapTrait.ForwardRate, Interpolator.BackwardFlat, 2, calendar, rate_helpers, ts_day_counter, tolerance ) dates = [rh.latest_date for rh in rate_helpers] dfs = [ts.discount(d) for d in dates] dates.insert(0, ts.reference_date) dfs.insert(0, 1) ts_discount = DiscountCurve(dates, dfs, ts_day_counter, calendar) self.assertTrue(ts.discount(0.75), ts_discount.discount(0.75))
def zbt_libor_yield(instruments, yields, pricing_date, basis='Actual/Actual (Bond)', compounding_freq='Continuous', maturity_dates=None): """ Bootstrap a zero-coupon curve from libor rates and swap yields Args: instruments: list of instruments, of the form Libor?M for Libor rates and Swap?Y for swap rates yields: market rates pricing_date: the date where market data is observed. Settlement is by default 2 days after pricing_date Optional: compounding_frequency: ... of zero-coupon rates. By default: 'Continuous' Returns: zero_rate: zero-coupon rate maturity_date: ... of corresponding rate """ calendar = TARGET() settings = Settings() # must be a business day eval_date = calendar.adjust(pydate_to_qldate(pricing_date)) settings.evaluation_date = eval_date rates = dict(zip(instruments, yields)) ts = make_term_structure(rates, pricing_date) cnt = DayCounter.from_name(basis) if maturity_dates is None: # schedule of maturity dates from settlement date to last date on # the term structure s = Schedule(effective_date=ts.reference_date, termination_date=ts.max_date, tenor=Period(1, Months), calendar=TARGET()) maturity_dates = [qldate_to_pydate(dt) for dt in s.dates()] cp_freq = Compounding[compounding_freq] zc = [ ts.zero_rate(pydate_to_qldate(dt), day_counter=cnt, compounding=cp_freq).rate for dt in maturity_dates ] return (maturity_dates, zc)
def test_creation(self): settings = Settings() # Market information calendar = TARGET() # must be a business day settings.evaluation_date = calendar.adjust(today()) settlement_date = Date(18, September, 2008) # must be a business day settlement_date = calendar.adjust(settlement_date); quotes = [SimpleQuote(0.0096), SimpleQuote(0.0145), SimpleQuote(0.0194)] tenors = [3, 6, 12] rate_helpers = [] calendar = TARGET() deposit_day_counter = Actual365Fixed() convention = ModifiedFollowing end_of_month = True for quote, month in zip(quotes, tenors): tenor = Period(month, Months) fixing_days = 3 helper = DepositRateHelper( quote, tenor, fixing_days, calendar, convention, end_of_month, deposit_day_counter ) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = PiecewiseYieldCurve[BootstrapTrait.Discount, LogLinear].from_reference_date( settlement_date, rate_helpers, ts_day_counter, accuracy=tolerance ) self.assertIsNotNone(ts) self.assertEqual( Date(18, September, 2008), ts.reference_date) # this is not a real test ... self.assertAlmostEqual(0.9975, ts.discount(Date(21, 12, 2008)), 4) self.assertAlmostEqual(0.9944, ts.discount(Date(21, 4, 2009)), 4) self.assertAlmostEqual(0.9904, ts.discount(Date(21, 9, 2009)), 4) dates, dfs = zip(*ts.nodes) self.assertAlmostEqual(list(dates), ts.dates) self.assertAlmostEqual(list(dfs), ts.data)
def test_relative_yieldcurve(self): settings = Settings() settings.evaluation_date = Date(6, 10, 2016) # Market information calendar = TARGET() quotes = [0.0096, 0.0145, 0.0194] tenors = [3, 6, 12] deposit_day_counter = Actual365Fixed() convention = ModifiedFollowing end_of_month = True fixing_days = 3 rate_helpers = [ DepositRateHelper(quote, Period(month, Months), fixing_days, calendar, convention, end_of_month, deposit_day_counter) for quote, month in zip(quotes, tenors) ] ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts_relative = PiecewiseYieldCurve(BootstrapTrait.Discount, Interpolator.LogLinear, 2, calendar, rate_helpers, ts_day_counter, tolerance) self.assertEqual( ts_relative.reference_date, calendar.advance(settings.evaluation_date, period=Period(2, Days))) settings.evaluation_date = Date(10, 10, 2016) settlement_date = calendar.advance(settings.evaluation_date, period=Period(2, Days)) self.assertEqual(ts_relative.reference_date, settlement_date) ts_absolute = PiecewiseYieldCurve.from_reference_date( BootstrapTrait.Discount, Interpolator.LogLinear, settlement_date, rate_helpers, ts_day_counter, tolerance) self.assertEqual(ts_absolute.data, ts_relative.data) self.assertEqual(ts_absolute.dates, ts_relative.dates) self.assertEqual(ts_absolute.times, ts_relative.times)
def _set_evaluation_date(self, dt_obs): if(~isinstance(dt_obs, Date)): dt_obs = pydate_to_qldate(dt_obs) settings = Settings() calendar = JointCalendar(UnitedStates(), UnitedKingdom()) # must be a business day eval_date = calendar.adjust(dt_obs) settings.evaluation_date = eval_date self._eval_date = eval_date return eval_date
def _cfamounts(coupon_rate, pricing_date, maturity_date, period, basis): """ cash flow schedule """ _period = str_to_frequency(period) evaluation_date = pydate_to_qldate(pricing_date) settings = Settings() settings.evaluation_date = evaluation_date calendar = TARGET() termination_date = pydate_to_qldate(maturity_date) # effective date must be before settlement date, but do not # care about exact issuance date of bond effective_date = Date(termination_date.day, termination_date.month, evaluation_date.year) effective_date = calendar.advance( effective_date, -1, Years, convention=Unadjusted) face_amount = 100.0 redemption = 100.0 fixed_bond_schedule = Schedule( effective_date, termination_date, Period(_period), calendar, ModifiedFollowing, ModifiedFollowing, Backward ) issue_date = effective_date cnt = DayCounter.from_name(basis) settlement_days = 2 bond = FixedRateBond( settlement_days, face_amount, fixed_bond_schedule, [coupon_rate], cnt, Following, redemption, issue_date) res = zip(*bond.cashflows) return(res)
def zbt_libor_yield(instruments, yields, pricing_date, basis='Actual/Actual (Bond)', compounding_freq='Continuous', maturity_dates=None): """ Bootstrap a zero-coupon curve from libor rates and swap yields Args: insruments: list of instruments, of the form Libor?M for Libor rates and Swap?Y for swap rates yields: market rates pricing_date: the date where market data is observed. Settlement is by default 2 days after pricing_date Optional: compounding_frequency: ... of zero-coupon rates. By default: 'Continuous' Returns: zero_rate: zero-coupon rate maturity_date: ... of corresponding rate """ calendar = TARGET() settings = Settings() # must be a business day eval_date = calendar.adjust(pydate_to_qldate(pricing_date)) settings.evaluation_date = eval_date rates = dict(zip(instruments, yields)) ts = make_term_structure(rates, pricing_date) cnt = DayCounter.from_name(basis) if maturity_dates is None: # schedule of maturity dates from settlement date to last date on # the term structure s = Schedule(effective_date=ts.reference_date, termination_date=ts.max_date, tenor=Period(1, Months), calendar=TARGET()) maturity_dates = [qldate_to_pydate(dt) for dt in s.dates()] cp_freq = compounding_from_name(compounding_freq) zc = [ts.zero_rate(date=pydate_to_qldate(dt), day_counter=cnt, compounding=cp_freq).rate for dt in maturity_dates] return (maturity_dates, zc)
def test_excel_example_with_fixed_rate_bond(self): """Port the QuantLib Excel adding bond example to Python. """ todays_date = Date(25, August, 2011) settings = Settings() settings.evaluation_date = todays_date calendar = TARGET() effective_date = Date(10, Jul, 2006) termination_date = calendar.advance(effective_date, 10, Years, convention=Unadjusted) 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) engine = DiscountingBondEngine(discounting_term_structure) bond.set_pricing_engine(engine) self.assertEquals(Date(10, Jul, 2016), termination_date) self.assertEquals(calendar.advance(todays_date, 3, Days), bond.settlement_date()) self.assertEquals(Date(11, Jul, 2016), bond.maturity_date) self.assertAlmostEqual(0.6849, bond.accrued_amount(bond.settlement_date()), 4) self.assertAlmostEqual(102.1154, bond.clean_price, 4)
def _set_evaluation_date(self, dt_obs): if not isinstance(dt_obs, Date): dt_obs = pydate_to_qldate(dt_obs) settings = Settings() calendar = JointCalendar(UnitedStates(), UnitedKingdom()) # must be a business day eval_date = calendar.adjust(dt_obs) settings.evaluation_date = eval_date self._eval_date = eval_date return eval_date
def test_creation(self): settings = Settings() # Market information calendar = TARGET() # must be a business day settings.evaluation_date = calendar.adjust(today()) settlement_date = Date(18, September, 2008) # must be a business day settlement_date = calendar.adjust(settlement_date); quotes = [0.0096, 0.0145, 0.0194] tenors = [3, 6, 12] rate_helpers = [] calendar = TARGET() deposit_day_counter = Actual365Fixed() convention = ModifiedFollowing end_of_month = True for quote, month in zip(quotes, tenors): tenor = Period(month, Months) fixing_days = 3 helper = DepositRateHelper( quote, tenor, fixing_days, calendar, convention, end_of_month, deposit_day_counter ) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = term_structure_factory( 'discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance ) self.assertIsNotNone(ts) self.assertEquals( Date(18, September, 2008), ts.reference_date) # this is not a real test ... self.assertAlmostEquals(0.9975, ts.discount(Date(21, 12, 2008)), 4) self.assertAlmostEquals(0.9944, ts.discount(Date(21, 4, 2009)), 4) self.assertAlmostEquals(0.9904, ts.discount(Date(21, 9, 2009)), 4)
def test_excel_example_with_fixed_rate_bond(self): '''Port the QuantLib Excel adding bond example to Python. ''' todays_date = Date(25, August, 2011) settings = Settings() settings.evaluation_date = todays_date calendar = TARGET() effective_date = Date(10, Jul, 2006) termination_date = calendar.advance(effective_date, 10, Years, convention=Unadjusted) settlement_days = 3 face_amount = 100.0 coupon_rate = 0.05 redemption = 100.0 fixed_bond_schedule = Schedule.from_rule(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() 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) engine = DiscountingBondEngine(discounting_term_structure) bond.set_pricing_engine(engine) self.assertEqual(Date(10, Jul, 2016), termination_date) self.assertEqual(calendar.advance(todays_date, 3, Days), bond.settlement_date()) self.assertEqual(Date(11, Jul, 2016), bond.maturity_date) self.assertAlmostEqual(0.6849, bond.accrued_amount(bond.settlement_date()), 4) self.assertAlmostEqual(102.1154, bond.clean_price, 4)
def test_creation(self): settings = Settings() # Market information calendar = TARGET() # must be a business day settings.evaluation_date = calendar.adjust(today()) settlement_date = Date(18, September, 2008) # must be a business day settlement_date = calendar.adjust(settlement_date); quotes = [SimpleQuote(0.0096), SimpleQuote(0.0145), SimpleQuote(0.0194)] tenors = [3, 6, 12] rate_helpers = [] calendar = TARGET() deposit_day_counter = Actual365Fixed() convention = ModifiedFollowing end_of_month = True for quote, month in zip(quotes, tenors): tenor = Period(month, Months) fixing_days = 3 helper = DepositRateHelper( quote, tenor, fixing_days, calendar, convention, end_of_month, deposit_day_counter ) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = PiecewiseYieldCurve.from_reference_date( BootstrapTrait.Discount, Interpolator.LogLinear, settlement_date, rate_helpers, ts_day_counter, tolerance ) self.assertIsNotNone(ts) self.assertEqual( Date(18, September, 2008), ts.reference_date) # this is not a real test ... self.assertAlmostEqual(0.9975, ts.discount(Date(21, 12, 2008)), 4) self.assertAlmostEqual(0.9944, ts.discount(Date(21, 4, 2009)), 4) self.assertAlmostEqual(0.9904, ts.discount(Date(21, 9, 2009)), 4)
def test_relative_yieldcurve(self): settings = Settings() settings.evaluation_date = Date(6, 10, 2016) # Market information calendar = TARGET() quotes = [0.0096, 0.0145, 0.0194] tenors = [3, 6, 12] deposit_day_counter = Actual365Fixed() convention = ModifiedFollowing end_of_month = True fixing_days = 3 rate_helpers = [DepositRateHelper( quote, Period(month, Months), fixing_days, calendar, convention, end_of_month, deposit_day_counter) for quote, month in zip(quotes, tenors)] ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts_relative = PiecewiseYieldCurve( BootstrapTrait.Discount, Interpolator.LogLinear, 2, calendar, rate_helpers, ts_day_counter, tolerance ) self.assertEqual(ts_relative.reference_date, calendar.advance(settings.evaluation_date, period = Period(2, Days))) settings.evaluation_date = Date(10, 10, 2016) settlement_date = calendar.advance(settings.evaluation_date, period = Period(2, Days)) self.assertEqual(ts_relative.reference_date, settlement_date) ts_absolute = PiecewiseYieldCurve.from_reference_date( BootstrapTrait.Discount, Interpolator.LogLinear, settlement_date, rate_helpers, ts_day_counter, tolerance ) self.assertEqual(ts_absolute.data, ts_relative.data) self.assertEqual(ts_absolute.dates, ts_relative.dates) self.assertEqual(ts_absolute.times, ts_relative.times)
def test_using_settings(self): settings = Settings() evaluation_date = today() # have to set the evaluation date before the test as it is a global # attribute for the whole library ... meaning that previous test_cases # might have set this to another date settings.evaluation_date = evaluation_date self.assertEqual(settings.evaluation_date, evaluation_date) self.assertTrue(settings.version.startswith('1'))
def test_bucket_analysis_option(self): settings = Settings() calendar = TARGET() todays_date = Date(15, May, 1998) settlement_date = Date(17, May, 1998) settings.evaluation_date = todays_date option_type = Put underlying = 40 strike = 40 dividend_yield = 0.00 risk_free_rate = 0.001 volatility = 0.20 maturity = Date(17, May, 1999) daycounter = Actual365Fixed() underlyingH = SimpleQuote(underlying) payoff = PlainVanillaPayoff(option_type, strike) flat_term_structure = FlatForward(reference_date=settlement_date, forward=risk_free_rate, daycounter=daycounter) flat_dividend_ts = FlatForward(reference_date=settlement_date, forward=dividend_yield, daycounter=daycounter) flat_vol_ts = BlackConstantVol(settlement_date, calendar, volatility, daycounter) black_scholes_merton_process = BlackScholesMertonProcess( underlyingH, flat_dividend_ts, flat_term_structure, flat_vol_ts) european_exercise = EuropeanExercise(maturity) european_option = VanillaOption(payoff, european_exercise) analytic_european_engine = AnalyticEuropeanEngine( black_scholes_merton_process) european_option.set_pricing_engine(analytic_european_engine) ba_eo = bucket_analysis([[underlyingH]], [european_option], [1], 0.50, 1) self.assertTrue(2, ba_eo) self.assertTrue(type(tuple), ba_eo) self.assertEqual(1, len(ba_eo[0][0])) self.assertAlmostEqual(-0.4582666150152517, ba_eo[0][0][0])
def make_rate_helper(label, rate, dt_obs, currency='USD'): """ Wrapper for deposit and swaps rate helpers makers For Swaps: assume USD swap fixed rates vs. 6M Libor TODO: make this more general """ if(currency.upper() != 'USD'): raise Exception("Only supported currency is USD.") rate_type, tenor, period = _parse_rate_label(label) if not isinstance(dt_obs, Date): dt_obs = pydate_to_qldate(dt_obs) settings = Settings() calendar = JointCalendar(UnitedStates(), UnitedKingdom()) # must be a business day eval_date = calendar.adjust(dt_obs) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) end_of_month = True if((rate_type == 'SWAP') & (period == 'Y')): liborIndex = Libor( 'USD Libor', Period(6, Months), settlement_days, USDCurrency(), calendar, Actual360() ) spread = SimpleQuote(0) fwdStart = Period(0, Days) helper = SwapRateHelper.from_tenor( SimpleQuote(rate), Period(tenor, Years), calendar, Annual, Unadjusted, Thirty360(), liborIndex, spread, fwdStart) elif((rate_type == 'LIBOR') & (period == 'M')): helper = DepositRateHelper(SimpleQuote(rate), Period(tenor, Months), settlement_days, calendar, ModifiedFollowing, end_of_month, Actual360()) else: raise Exception("Rate type %s not supported" % label) return (helper)
def test_bucket_analysis_option(self): settings = Settings() calendar = TARGET() todays_date = Date(15, May, 1998) settlement_date = Date(17, May, 1998) settings.evaluation_date = todays_date option_type = Put underlying = 40 strike = 40 dividend_yield = 0.00 risk_free_rate = 0.001 volatility = SimpleQuote(0.20) maturity = Date(17, May, 1999) daycounter = Actual365Fixed() underlyingH = SimpleQuote(underlying) payoff = PlainVanillaPayoff(option_type, strike) flat_term_structure = FlatForward(reference_date=settlement_date, forward=risk_free_rate, daycounter=daycounter) flat_dividend_ts = FlatForward(reference_date=settlement_date, forward=dividend_yield, daycounter=daycounter) flat_vol_ts = BlackConstantVol(settlement_date, calendar, volatility, daycounter) black_scholes_merton_process = BlackScholesMertonProcess( underlyingH, flat_dividend_ts, flat_term_structure, flat_vol_ts) european_exercise = EuropeanExercise(maturity) european_option = VanillaOption(payoff, european_exercise) analytic_european_engine = AnalyticEuropeanEngine( black_scholes_merton_process) european_option.set_pricing_engine(analytic_european_engine) delta, gamma = bucket_analysis([underlyingH, volatility], [european_option], shift=1e-4, type=Centered) self.assertAlmostEqual(delta[0], european_option.delta) self.assertAlmostEqual(delta[1], european_option.vega) self.assertAlmostEqual(gamma[0], european_option.gamma, 5)
def heston_helpers(spot, df_option, dtTrade, df_rates): """ Create array of heston options helpers """ DtSettlement = dateToQLDate(dtTrade) settings = Settings() settings.evaluation_date = DtSettlement calendar = TARGET() # convert data frame (date/value) into zero curve # expect the index to be a date, and 1 column of values risk_free_ts = dfToZeroCurve(df_rates['iRate'], dtTrade) dividend_ts = dfToZeroCurve(df_rates['iDiv'], dtTrade) # loop through rows in option data frame, construct # helpers for bid/ask oneDay = datetime.timedelta(days=1) dtExpiry = [dtTrade + int(t*365)*oneDay for t in df_option['TTM']] df_option['dtExpiry'] = dtExpiry options = [] for index, row in df_option.T.iteritems(): strike = row['Strike'] if (strike/spot.value > 1.3) | (strike/spot.value < .7): continue days = int(365*row['TTM']) maturity = Period(days, Days) options.append( HestonModelHelper( maturity, calendar, spot.value, strike, SimpleQuote(row['IVBid']), risk_free_ts, dividend_ts, ImpliedVolError)) options.append( HestonModelHelper( maturity, calendar, spot.value, strike, SimpleQuote(row['IVAsk']), risk_free_ts, dividend_ts, ImpliedVolError)) return {'options':options, 'spot': spot}
def test_all_types_of_piecewise_curves(self): settings = Settings() # Market information calendar = TARGET() todays_date = Date(12, September, 2008) # must be a business day settings.evaluation_date = calendar.adjust(todays_date) settlement_date = Date(18, September, 2008) # must be a business day settlement_date = calendar.adjust(settlement_date) quotes = [ SimpleQuote(0.0096), SimpleQuote(0.0145), SimpleQuote(0.0194) ] tenors = [3, 6, 12] rate_helpers = [] deposit_day_counter = Actual365Fixed() convention = ModifiedFollowing end_of_month = True for quote, month in zip(quotes, tenors): tenor = Period(month, Months) fixing_days = 3 helper = DepositRateHelper(quote, tenor, fixing_days, calendar, convention, end_of_month, deposit_day_counter) rate_helpers.append(helper) tolerance = 1.0e-15 for trait in BootstrapTrait: for interpolation in Interpolator: ts = PiecewiseYieldCurve.from_reference_date( trait, interpolation, settlement_date, rate_helpers, deposit_day_counter, tolerance) self.assertIsNotNone(ts) self.assertEqual(Date(18, September, 2008), ts.reference_date)
def test_bond_schedule_anotherday(self): '''Test date calculations and role of settings when evaluation date set to arbitrary date. This test is known to fail with boost 1.42. ''' todays_date = Date(30, August, 2011) settings = Settings() settings.evaluation_date = todays_date calendar = TARGET() effective_date = Date(10, Jul, 2006) termination_date = calendar.advance( effective_date, 10, Years, convention=Unadjusted) settlement_days = 3 face_amount = 100.0 coupon_rate = 0.05 redemption = 100.0 fixed_bond_schedule = Schedule.from_rule( effective_date, termination_date, Period(Annual), calendar, ModifiedFollowing, ModifiedFollowing, Rule.Backward ) issue_date = effective_date bond = FixedRateBond( settlement_days, face_amount, fixed_bond_schedule, [coupon_rate], ActualActual(ISMA), Following, redemption, issue_date ) self.assertEqual( calendar.advance(todays_date, 3, Days), bond.settlement_date())
def test_all_types_of_piecewise_curves(self): settings = Settings() # Market information calendar = TARGET() todays_date = Date(12, September, 2008) # must be a business day settings.evaluation_date = calendar.adjust(todays_date) settlement_date = Date(18, September, 2008) # must be a business day settlement_date = calendar.adjust(settlement_date); quotes = [SimpleQuote(0.0096), SimpleQuote(0.0145), SimpleQuote(0.0194)] tenors = [3, 6, 12] rate_helpers = [] deposit_day_counter = Actual365Fixed() convention = ModifiedFollowing end_of_month = True for quote, month in zip(quotes, tenors): tenor = Period(month, Months) fixing_days = 3 helper = DepositRateHelper( quote, tenor, fixing_days, calendar, convention, end_of_month, deposit_day_counter ) rate_helpers.append(helper) tolerance = 1.0e-15 for trait in VALID_TRAITS: for interpolation in VALID_INTERPOLATORS: ts = PiecewiseYieldCurve( trait, interpolation, settlement_date, rate_helpers, deposit_day_counter, tolerance ) self.assertIsNotNone(ts) self.assertEqual( Date(18, September, 2008), ts.reference_date)
def test_bond_schedule_today(self): '''Test date calculations and role of settings when evaluation date set to current date. ''' todays_date = today() settings = Settings() settings.evaluation_date = todays_date calendar = TARGET() effective_date = Date(10, Jul, 2006) termination_date = calendar.advance( effective_date, 10, Years, convention=Unadjusted) 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 ) self.assertEquals( calendar.advance(todays_date, 3, Days), bond.settlement_date())
def make_rate_helper(label, rate, dt_obs, currency='USD'): """ Wrapper for deposit and swaps rate helpers makers For Swaps: assume USD swap fixed rates vs. 6M Libor TODO: make this more general """ if(currency.upper() != 'USD'): raise Exception("Only supported currency is USD.") rate_type, tenor, period = _parse_rate_label(label) if not isinstance(dt_obs, Date): dt_obs = pydate_to_qldate(dt_obs) settings = Settings() calendar = JointCalendar(UnitedStates(), UnitedKingdom()) # must be a business day eval_date = calendar.adjust(dt_obs) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) end_of_month = True if((rate_type == 'SWAP') & (period == 'Y')): liborIndex = Libor( 'USD Libor', Period(6, Months), settlement_days, USDCurrency(), calendar, Actual360() ) spread = SimpleQuote(0) fwdStart = Period(0, Days) helper = SwapRateHelper.from_tenor(rate, Period(tenor, Years), calendar, Annual, Unadjusted, Thirty360(), liborIndex, spread, fwdStart) elif((rate_type == 'LIBOR') & (period == 'M')): helper = DepositRateHelper(rate, Period(tenor, Months), settlement_days, calendar, ModifiedFollowing, end_of_month, Actual360()) else: raise Exception("Rate type %s not supported" % label) return (helper)
def set_quotes(self, dt_obs, quotes): self._quotes = quotes if(~isinstance(dt_obs, Date)): dt_obs = pydate_to_qldate(dt_obs) settings = Settings() calendar = JointCalendar(UnitedStates(), UnitedKingdom()) # must be a business day eval_date = calendar.adjust(dt_obs) settings.evaluation_date = eval_date self._eval_date = eval_date self._rate_helpers = [] for quote in quotes: # construct rate helper helper = make_rate_helper(self, quote, eval_date) self._rate_helpers.append(helper)
def heston_pricer(trade_date, options, params, rates, spot): """ Price a list of European options with heston model. """ spot = SimpleQuote(spot) risk_free_ts = df_to_zero_curve(rates[nm.INTEREST_RATE], trade_date) dividend_ts = df_to_zero_curve(rates[nm.DIVIDEND_YIELD], trade_date) process = HestonProcess(risk_free_ts, dividend_ts, spot, **params) model = HestonModel(process) engine = AnalyticHestonEngine(model, 64) settlement_date = pydate_to_qldate(trade_date) settings = Settings() settings.evaluation_date = settlement_date modeled_values = np.zeros(len(options)) for index, row in options.T.iteritems(): expiry_date = row[nm.EXPIRY_DATE] strike = row[nm.STRIKE] option_type = Call if row[nm.OPTION_TYPE] == nm.CALL_OPTION else Put payoff = PlainVanillaPayoff(option_type, strike) expiry_qldate = pydate_to_qldate(expiry_date) exercise = EuropeanExercise(expiry_qldate) option = VanillaOption(payoff, exercise) option.set_pricing_engine(engine) modeled_values[index] = option.net_present_value prices = options.filter( items=[nm.EXPIRY_DATE, nm.STRIKE, nm.OPTION_TYPE, nm.SPOT]) prices[nm.PRICE] = modeled_values prices[nm.TRADE_DATE] = trade_date return prices
def heston_pricer(trade_date, options, params, rates, spot): """ Price a list of European options with heston model. """ spot = SimpleQuote(spot) risk_free_ts = df_to_zero_curve(rates[nm.INTEREST_RATE], trade_date) dividend_ts = df_to_zero_curve(rates[nm.DIVIDEND_YIELD], trade_date) process = HestonProcess(risk_free_ts, dividend_ts, spot, **params) model = HestonModel(process) engine = AnalyticHestonEngine(model, 64) settlement_date = pydate_to_qldate(trade_date) settings = Settings() settings.evaluation_date = settlement_date modeled_values = np.zeros(len(options)) for index, row in options.T.iteritems(): expiry_date = row[nm.EXPIRY_DATE] strike = row[nm.STRIKE] option_type = Call if row[nm.OPTION_TYPE] == nm.CALL_OPTION else Put payoff = PlainVanillaPayoff(option_type, strike) expiry_qldate = pydate_to_qldate(expiry_date) exercise = EuropeanExercise(expiry_qldate) option = VanillaOption(payoff, exercise) option.set_pricing_engine(engine) modeled_values[index] = option.net_present_value prices = options.filter(items=[nm.EXPIRY_DATE, nm.STRIKE, nm.OPTION_TYPE, nm.SPOT]) prices[nm.PRICE] = modeled_values prices[nm.TRADE_DATE] = trade_date return prices
def bootstrap_term_structure(self, interpolator='loglinear'): tolerance = 1.0e-15 settings = Settings() calendar = JointCalendar(UnitedStates(), UnitedKingdom()) # must be a business day eval_date = self._eval_date settings.evaluation_date = eval_date settlement_days = self._params.settlement_days settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) ts = PiecewiseYieldCurve( 'discount', interpolator, settlement_date, self._rate_helpers, DayCounter.from_name(self._termstructure_daycount), tolerance) self._term_structure = ts self._discount_term_structure = YieldTermStructure(relinkable=True) self._discount_term_structure.link_to(ts) self._forecast_term_structure = YieldTermStructure(relinkable=True) self._forecast_term_structure.link_to(ts) return ts
def test_bond_schedule_today(self): '''Test date calculations and role of settings when evaluation date set to current date. ''' todays_date = today() settings = Settings() settings.evaluation_date = todays_date calendar = TARGET() effective_date = Date(10, Jul, 2006) termination_date = calendar.advance(effective_date, 10, Years, convention=Unadjusted) 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) self.assertEquals(calendar.advance(todays_date, 3, Days), bond.settlement_date())
def bootstrap_term_structure(self): tolerance = 1.0e-15 settings = Settings() calendar = JointCalendar(UnitedStates(), UnitedKingdom()) # must be a business day eval_date = self._eval_date settings.evaluation_date = eval_date settlement_days = self._params.settlement_days settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) ts = term_structure_factory( 'discount', 'loglinear', settlement_date, self._rate_helpers, DayCounter.from_name(self._termstructure_daycount), tolerance) self._term_structure = ts self._discount_term_structure = YieldTermStructure(relinkable=True) self._discount_term_structure.link_to(ts) self._forecasting_term_structure = YieldTermStructure(relinkable=True) self._forecasting_term_structure.link_to(ts) return 0
def test_deposit_swap(self): settings = Settings() # Market information calendar = TARGET() # must be a business day eval_date = calendar.adjust(today()) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date); depositData = [[ 1, Months, 4.581 ], [ 2, Months, 4.573 ], [ 3, Months, 4.557 ], [ 6, Months, 4.496 ], [ 9, Months, 4.490 ]] swapData = [[ 1, Years, 4.54 ], [ 5, Years, 4.99 ], [ 10, Years, 5.47 ], [ 20, Years, 5.89 ], [ 30, Years, 5.96 ]] rate_helpers = [] end_of_month = True for m, period, rate in depositData: tenor = Period(m, Months) helper = DepositRateHelper(rate/100, tenor, settlement_days, calendar, ModifiedFollowing, end_of_month, Actual360()) rate_helpers.append(helper) liborIndex = Libor('USD Libor', Period(6, Months), settlement_days, USDCurrency(), calendar, Actual360()) spread = SimpleQuote(0) fwdStart = Period(0, Days) for m, period, rate in swapData: rate = SimpleQuote(rate/100) helper = SwapRateHelper(rate, Period(m, Years), calendar, Annual, Unadjusted, Thirty360(), liborIndex, spread, fwdStart) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = term_structure_factory( 'discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) # this is not a real test ... self.assertAlmostEquals(0.9103, ts.discount(calendar.advance(today(), 2, Years)),3) self.assertAlmostEquals(0.7836, ts.discount(calendar.advance(today(), 5, Years)),3) self.assertAlmostEquals(0.5827, ts.discount(calendar.advance(today(), 10, Years)),3) self.assertAlmostEquals(0.4223, ts.discount(calendar.advance(today(), 15, Years)),3)
def get_term_structure(df_libor, dtObs): settings = Settings() # Market information calendar = TARGET() # must be a business day eval_date = calendar.adjust(dateToDate(dtObs)) settings.evaluation_date = eval_date settlement_days = 2 settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) depositData = [[1, Months, 'Libor1M'], [3, Months, 'Libor3M'], [6, Months, 'Libor6M']] swapData = [[1, Years, 'Swap1Y'], [2, Years, 'Swap2Y'], [3, Years, 'Swap3Y'], [4, Years, 'Swap4Y'], [5, Years, 'Swap5Y'], [7, Years, 'Swap7Y'], [10, Years, 'Swap10Y'], [30, Years, 'Swap30Y']] rate_helpers = [] end_of_month = True for m, period, label in depositData: tenor = Period(m, Months) rate = df_libor.get_value(dtObs, label) helper = DepositRateHelper(SimpleQuote(rate / 100.0), tenor, settlement_days, calendar, ModifiedFollowing, end_of_month, Actual360()) rate_helpers.append(helper) liborIndex = Libor('USD Libor', Period(3, Months), settlement_days, USDCurrency(), calendar, Actual360()) spread = SimpleQuote(0) fwdStart = Period(0, Days) for m, period, label in swapData: rate = df_libor.get_value(dtObs, label) helper = SwapRateHelper.from_tenor( SimpleQuote(rate / 100.0), Period(m, Years), calendar, Semiannual, ModifiedFollowing, Thirty360(), liborIndex, spread, fwdStart) rate_helpers.append(helper) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = PiecewiseYieldCurve('discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) return ts
def _bndprice(bond_yield, coupon_rate, pricing_date, maturity_date, period, basis, compounding_frequency): """ Clean price and accrued interest of a bond """ _period = str_to_frequency(period) evaluation_date = pydate_to_qldate(pricing_date) settings = Settings() settings.evaluation_date = evaluation_date calendar = TARGET() termination_date = pydate_to_qldate(maturity_date) # effective date must be before settlement date, but do not # care about exact issuance date of bond effective_date = Date(termination_date.day, termination_date.month, evaluation_date.year) effective_date = calendar.advance(effective_date, -1, Years, convention=Unadjusted) settlement_date = calendar.advance(evaluation_date, 2, Days, convention=ModifiedFollowing) face_amount = 100.0 redemption = 100.0 fixed_bond_schedule = Schedule(effective_date, termination_date, Period(_period), calendar, ModifiedFollowing, ModifiedFollowing, Backward) issue_date = effective_date cnt = DayCounter.from_name(basis) settlement_days = 2 bond = FixedRateBond(settlement_days, face_amount, fixed_bond_schedule, [coupon_rate], cnt, Following, redemption, issue_date) discounting_term_structure = YieldTermStructure(relinkable=True) cnt_yield = DayCounter.from_name('Actual/Actual (Historical)') flat_term_structure = FlatForward(settlement_days=2, forward=bond_yield, calendar=NullCalendar(), daycounter=cnt_yield, compounding=Compounded, frequency=_period) discounting_term_structure.link_to(flat_term_structure) engine = DiscountingBondEngine(discounting_term_structure) bond.set_pricing_engine(engine) price = bond.clean_price ac = bond.accrued_amount(pydate_to_qldate(settlement_date)) return (price, ac)
def heston_helpers(df_option, dtTrade=None, df_rates=None, ival=None): """ Create array of heston options helpers """ if dtTrade is None: dtTrade = df_option['dtTrade'][0] DtSettlement = datetoQLDate(dtTrade) settings = Settings() settings.evaluation_date = DtSettlement calendar = TARGET() if df_rates is None: df_tmp = DataFrame.filter(df_option, items=['dtExpiry', 'IR', 'IDIV']) grouped = df_tmp.groupby('dtExpiry') df_rates = grouped.agg(lambda x: x[0]) # convert data frame (date/value) into zero curve # expect the index to be a date, and 1 column of values risk_free_ts = dfToZeroCurve(df_rates['R'], dtTrade) dividend_ts = dfToZeroCurve(df_rates['D'], dtTrade) # back out the spot from any forward iRate = df_option['R'][0] iDiv = df_option['D'][0] TTM = df_option['T'][0] Fwd = df_option['F'][0] spot = SimpleQuote(Fwd*np.exp(-(iRate-iDiv)*TTM)) print('Spot: %f risk-free rate: %f div. yield: %f' % (spot.value, iRate, iDiv)) # loop through rows in option data frame, construct # helpers for bid/ask oneDay = datetime.timedelta(days=1) dtExpiry = [dtTrade + int(t*365)*oneDay for t in df_option['T']] df_option['dtExpiry'] = dtExpiry options = [] for index, row in df_option.T.iteritems(): strike = row['K'] if (strike/spot.value > 1.3) | (strike/spot.value < .7): continue days = int(365*row['T']) maturity = Period(days, Days) options.append( HestonModelHelper( maturity, calendar, spot.value, strike, SimpleQuote(row['VB']), risk_free_ts, dividend_ts, ImpliedVolError)) options.append( HestonModelHelper( maturity, calendar, spot.value, strike, SimpleQuote(row['VA']), risk_free_ts, dividend_ts, ImpliedVolError)) return {'options':options, 'spot': spot}
def heston_helpers(df_option, dtTrade=None, df_rates=None, ival=None): """ Create array of heston options helpers """ if dtTrade is None: dtTrade = df_option['dtTrade'][0] DtSettlement = pydate_to_qldate(dtTrade) settings = Settings() settings.evaluation_date = DtSettlement calendar = TARGET() if df_rates is None: df_tmp = DataFrame.filter(df_option, items=['dtExpiry', 'IR', 'IDIV']) grouped = df_tmp.groupby('dtExpiry') df_rates = grouped.agg(lambda x: x[0]) # convert data frame (date/value) into zero curve # expect the index to be a date, and 1 column of values risk_free_ts = df_to_zero_curve(df_rates['R'], dtTrade) dividend_ts = df_to_zero_curve(df_rates['D'], dtTrade) # back out the spot from any forward iRate = df_option['R'][0] iDiv = df_option['D'][0] TTM = df_option['T'][0] Fwd = df_option['F'][0] spot = SimpleQuote(Fwd * np.exp(-(iRate - iDiv) * TTM)) print('Spot: %f risk-free rate: %f div. yield: %f' % \ (spot.value, iRate, iDiv)) # loop through rows in option data frame, construct # helpers for bid/ask oneDay = datetime.timedelta(days=1) dtExpiry = [dtTrade + int(t * 365) * oneDay for t in df_option['T']] df_option['dtExpiry'] = dtExpiry options = [] for index, row in df_option.T.iteritems(): strike = row['K'] if (strike / spot.value > 1.3) | (strike / spot.value < .7): continue days = int(365 * row['T']) maturity = Period(days, Days) options.append( HestonModelHelper(maturity, calendar, spot.value, strike, SimpleQuote(row['VB']), risk_free_ts, dividend_ts, ImpliedVolError)) options.append( HestonModelHelper(maturity, calendar, spot.value, strike, SimpleQuote(row['VA']), risk_free_ts, dividend_ts, ImpliedVolError)) return {'options': options, 'spot': spot}
def test_pricing_bond(): '''Inspired by the C++ code from http://quantcorner.wordpress.com/.''' settings = Settings() # Date setup calendar = TARGET() # Settlement date settlement_date = calendar.adjust(Date(28, January, 2011)) # Evaluation date fixing_days = 1 settlement_days = 1 todays_date = calendar.advance( settlement_date, -fixing_days, Days ) settings.evaluation_date = todays_date # Bound attributes face_amount = 100.0 redemption = 100.0 issue_date = Date(27, January, 2011) maturity_date = Date(31, August, 2020) coupon_rate = 0.03625 bond_yield = 0.034921 discounting_term_structure = YieldTermStructure(relinkable=True) flat_term_structure = FlatForward( reference_date = settlement_date, forward = bond_yield, daycounter = Actual365Fixed(), #actual_actual.ActualActual(actual_actual.Bond), compounding = Compounded, frequency = Semiannual) # have a look at the FixedRateBondHelper to simplify this # construction discounting_term_structure.link_to(flat_term_structure) #Rate fixed_bond_schedule = Schedule( issue_date, maturity_date, Period(Semiannual), UnitedStates(market=GOVERNMENTBOND), Unadjusted, Unadjusted, Backward, False); bond = FixedRateBond( settlement_days, face_amount, fixed_bond_schedule, [coupon_rate], ActualActual(Bond), Unadjusted, redemption, issue_date ) bond.set_pricing_engine(discounting_term_structure) return bond
def test_excel_example_with_floating_rate_bond(self): todays_date = Date(25, August, 2011) settings = Settings() settings.evaluation_date = todays_date calendar = TARGET() effective_date = Date(10, Jul, 2006) termination_date = calendar.advance(effective_date, 10, Years, convention=Unadjusted) settlement_date = calendar.adjust(Date(28, January, 2011)) settlement_days = 3 #1 face_amount = 13749769.27 #2 coupon_rate = 0.05 redemption = 100.0 float_bond_schedule = Schedule(effective_date, termination_date, Period(Annual), calendar, ModifiedFollowing, ModifiedFollowing, Backward) #3 flat_discounting_term_structure = YieldTermStructure(relinkable=True) forecastTermStructure = YieldTermStructure(relinkable=True) dc = Actual360() ibor_index = Euribor6M(forecastTermStructure) #5 fixing_days = 2 #6 gearings = [1, 0.0] #7 spreads = [1, 0.05] #8 caps = [] #9 floors = [] #10 pmt_conv = ModifiedFollowing #11 issue_date = effective_date float_bond = FloatingRateBond(settlement_days, face_amount, float_bond_schedule, ibor_index, dc, fixing_days, gearings, spreads, caps, floors, pmt_conv, redemption, issue_date) flat_term_structure = FlatForward(settlement_days=1, forward=0.055, calendar=NullCalendar(), daycounter=Actual365Fixed(), compounding=Continuous, frequency=Annual) flat_discounting_term_structure.link_to(flat_term_structure) forecastTermStructure.link_to(flat_term_structure) engine = DiscountingBondEngine(flat_discounting_term_structure) float_bond.set_pricing_engine(engine) cons_option_vol = ConstantOptionletVolatility(settlement_days, UnitedStates(SETTLEMENT), pmt_conv, 0.95, Actual365Fixed()) coupon_pricer = BlackIborCouponPricer(cons_option_vol) set_coupon_pricer(float_bond, coupon_pricer) self.assertEquals(Date(10, Jul, 2016), termination_date) self.assertEquals(calendar.advance(todays_date, 3, Days), float_bond.settlement_date()) self.assertEquals(Date(11, Jul, 2016), float_bond.maturity_date) self.assertAlmostEqual( 0.6944, float_bond.accrued_amount(float_bond.settlement_date()), 4) self.assertAlmostEqual(98.2485, float_bond.dirty_price, 4) self.assertAlmostEqual(13500805.2469, float_bond.npv, 4)
def test_pricing_bond(self): '''Inspired by the C++ code from http://quantcorner.wordpress.com/.''' settings = Settings() # Date setup calendar = TARGET() # Settlement date settlement_date = calendar.adjust(Date(28, January, 2011)) # Evaluation date fixing_days = 1 settlement_days = 1 todays_date = calendar.advance(settlement_date, -fixing_days, Days) settings.evaluation_date = todays_date # Bound attributes face_amount = 100.0 redemption = 100.0 issue_date = Date(27, January, 2011) maturity_date = Date(31, August, 2020) coupon_rate = 0.03625 bond_yield = 0.034921 discounting_term_structure = YieldTermStructure(relinkable=True) flat_term_structure = FlatForward( reference_date=settlement_date, forward=bond_yield, daycounter=Actual365Fixed( ), #actual_actual.ActualActual(actual_actual.Bond), compounding=Compounded, frequency=Semiannual) # have a look at the FixedRateBondHelper to simplify this # construction discounting_term_structure.link_to(flat_term_structure) #Rate fixed_bond_schedule = Schedule(issue_date, maturity_date, Period(Semiannual), UnitedStates(market=GOVERNMENTBOND), Unadjusted, Unadjusted, Backward, False) bond = FixedRateBond(settlement_days, face_amount, fixed_bond_schedule, [coupon_rate], ActualActual(Bond), Unadjusted, redemption, issue_date) bond.set_pricing_engine(discounting_term_structure) # tests self.assertTrue(Date(27, January, 2011), bond.issue_date) self.assertTrue(Date(31, August, 2020), bond.maturity_date) self.assertTrue(settings.evaluation_date, bond.valuation_date) # the following assertion fails but must be verified self.assertAlmostEqual(101.1, bond.clean_price, 1) self.assertAlmostEqual(101.1, bond.net_present_value, 1) self.assertAlmostEqual(101.1, bond.dirty_price) self.assertAlmostEqual(0.009851, bond.accrued_amount()) print(settings.evaluation_date) print('Principal: {}'.format(face_amount)) print('Issuing date: {} '.format(bond.issue_date)) print('Maturity: {}'.format(bond.maturity_date)) print('Coupon rate: {:.4%}'.format(coupon_rate)) print('Yield: {:.4%}'.format(bond_yield)) print('Net present value: {:.4f}'.format(bond.net_present_value)) print('Clean price: {:.4f}'.format(bond.clean_price)) print('Dirty price: {:.4f}'.format(bond.dirty_price)) print('Accrued coupon: {:.6f}'.format(bond.accrued_amount())) print('Accrued coupon: {:.6f}'.format( bond.accrued_amount(Date(1, March, 2011))))
def test_pricing_bond(self): '''Inspired by the C++ code from http://quantcorner.wordpress.com/.''' settings = Settings() # Date setup calendar = TARGET() # Settlement date settlement_date = calendar.adjust(Date(28, January, 2011)) # Evaluation date fixing_days = 1 settlement_days = 1 todays_date = calendar.advance( settlement_date, -fixing_days, Days ) settings.evaluation_date = todays_date # Bound attributes face_amount = 100.0 redemption = 100.0 issue_date = Date(27, January, 2011) maturity_date = Date(31, August, 2020) coupon_rate = 0.03625 bond_yield = 0.034921 discounting_term_structure = YieldTermStructure(relinkable=True) flat_term_structure = FlatForward( reference_date = settlement_date, forward = bond_yield, daycounter = Actual365Fixed(), #actual_actual.ActualActual(actual_actual.Bond), compounding = Compounded, frequency = Semiannual) # have a look at the FixedRateBondHelper to simplify this # construction discounting_term_structure.link_to(flat_term_structure) #Rate fixed_bond_schedule = Schedule( issue_date, maturity_date, Period(Semiannual), UnitedStates(market=GOVERNMENTBOND), Unadjusted, Unadjusted, Backward, False); bond = FixedRateBond( settlement_days, face_amount, fixed_bond_schedule, [coupon_rate], ActualActual(Bond), Unadjusted, redemption, issue_date ) bond.set_pricing_engine(discounting_term_structure) # tests self.assertTrue(Date(27, January, 2011), bond.issue_date) self.assertTrue(Date(31, August, 2020), bond.maturity_date) self.assertTrue(settings.evaluation_date, bond.valuation_date) # the following assertion fails but must be verified self.assertAlmostEqual(101.1, bond.clean_price, 1) self.assertAlmostEqual(101.1, bond.net_present_value, 1) self.assertAlmostEqual(101.1, bond.dirty_price) self.assertAlmostEqual(0.009851, bond.accrued_amount()) print settings.evaluation_date print 'Principal: {}'.format(face_amount) print 'Issuing date: {} '.format(bond.issue_date) print 'Maturity: {}'.format(bond.maturity_date) print 'Coupon rate: {:.4%}'.format(coupon_rate) print 'Yield: {:.4%}'.format(bond_yield) print 'Net present value: {:.4f}'.format(bond.net_present_value) print 'Clean price: {:.4f}'.format(bond.clean_price) print 'Dirty price: {:.4f}'.format(bond.dirty_price) print 'Accrued coupon: {:.6f}'.format(bond.accrued_amount()) print 'Accrued coupon: {:.6f}'.format( bond.accrued_amount(Date(1, March, 2011)) )
def test_swap_from_market(self): """ Test that a swap with fixed coupon = fair rate has an NPV=0 Create from market """ eval_date = Date(2, January, 2014) settings = Settings() settings.evaluation_date = eval_date calendar = TARGET() settlement_date = calendar.advance(eval_date, 2, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) length = 5 fixed_rate = .05 floating_spread = 0.0 m = libor_market('USD(NY)') quotes = [('DEP', '1W', SimpleQuote(0.0382)), ('DEP', '1M', SimpleQuote(0.0372)), ('DEP', '3M', SimpleQuote(0.0363)), ('DEP', '6M', SimpleQuote(0.0353)), ('DEP', '9M', SimpleQuote(0.0348)), ('DEP', '1Y', SimpleQuote(0.0345)), ('SWAP', '2Y', SimpleQuote(0.037125)), ('SWAP', '3Y', SimpleQuote(0.0398)), ('SWAP', '5Y', SimpleQuote(0.0443)), ('SWAP', '10Y', SimpleQuote(0.05165)), ('SWAP', '15Y', SimpleQuote(0.055175))] m.set_quotes(eval_date, quotes) m.bootstrap_term_structure() dt = Date(2, January, 2015) df = m.discount(dt) print('discount factor for %s (USD Libor): %f' % (dt, df)) swap = m.create_fixed_float_swap(settlement_date, length, fixed_rate, floating_spread) fixed_l = swap.fixed_leg float_l = swap.floating_leg f = swap.fair_rate print('fair rate: %f' % f) p = swap.net_present_value print('NPV: %f' % p) fixed_npv = swap.fixed_leg_npv float_npv = swap.floating_leg_npv # verify calculation by discounting both legs tot = 0.0 for frc in fixed_l: df = m.discount(frc.date) tot += frc.amount * df print('fixed npv: %f discounted cf: %f' % (fixed_npv, tot)) self.assertAlmostEqual(fixed_npv, -tot) tot = 0.0 for ic in float_l: df = m.discount(ic.date) tot += ic.amount * df print('float npv: %f discounted cf: %f' % (float_npv, tot)) self.assertAlmostEqual(float_npv, tot)
def test_swap_QL(self): """ Test that a swap with fixed coupon = fair rate has an NPV=0 Create from QL objects """ nominal = 100.0 fixedConvention = Unadjusted floatingConvention = ModifiedFollowing fixedFrequency = Annual floatingFrequency = Semiannual fixedDayCount = Thirty360() floatDayCount = Thirty360() calendar = TARGET() settlement_days = 2 eval_date = Date(2, January, 2014) settings = Settings() settings.evaluation_date = eval_date settlement_date = calendar.advance(eval_date, settlement_days, Days) # must be a business day settlement_date = calendar.adjust(settlement_date) termStructure = YieldTermStructure(relinkable=True) termStructure.link_to(FlatForward(settlement_date, 0.05, Actual365Fixed())) index = Libor('USD Libor', Period(6, Months), settlement_days, USDCurrency(), calendar, Actual360(), termStructure) length = 5 fixedRate = .05 floatingSpread = 0.0 maturity = calendar.advance(settlement_date, length, Years, convention=floatingConvention) fixedSchedule = Schedule(settlement_date, maturity, Period(fixedFrequency), calendar, fixedConvention, fixedConvention, Rule.Forward, False) floatSchedule = Schedule(settlement_date, maturity, Period(floatingFrequency), calendar, floatingConvention, floatingConvention, Rule.Forward, False) engine = DiscountingSwapEngine(termStructure, False, settlement_date, settlement_date) for swap_type in [Payer, Receiver]: swap = VanillaSwap(swap_type, nominal, fixedSchedule, fixedRate, fixedDayCount, floatSchedule, index, floatingSpread, floatDayCount, fixedConvention) swap.set_pricing_engine(engine) fixed_leg = swap.fixed_leg floating_leg = swap.floating_leg f = swap.fair_rate print('fair rate: %f' % f) p = swap.net_present_value print('NPV: %f' % p) swap = VanillaSwap(swap_type, nominal, fixedSchedule, f, fixedDayCount, floatSchedule, index, floatingSpread, floatDayCount, fixedConvention) swap.set_pricing_engine(engine) p = swap.net_present_value print('NPV: %f' % p) self.assertAlmostEqual(p, 0)
def test_heston_hw_calibration(self): """ From Quantlib test suite """ print("Testing Heston Hull-White calibration...") ## Calibration of a hybrid Heston-Hull-White model using ## the finite difference HestonHullWhite pricing engine ## Input surface is based on a Heston-Hull-White model with ## Hull-White: a = 0.00883, \sigma = 0.00631 ## Heston : \nu = 0.12, \kappa = 2.0, ## \theta = 0.09, \sigma = 0.5, \rho=-0.75 ## Equity Short rate correlation: -0.5 dc = Actual365Fixed() calendar = TARGET() todays_date = Date(28, March, 2004) settings = Settings() settings.evaluation_date = todays_date r_ts = flat_rate(todays_date, 0.05, dc) ## assuming, that the Hull-White process is already calibrated ## on a given set of pure interest rate calibration instruments. hw_process = HullWhiteProcess(r_ts, a=0.00883, sigma=0.00631) q_ts = flat_rate(todays_date, 0.02, dc) s0 = SimpleQuote(100.0) # vol surface strikes = [50, 75, 90, 100, 110, 125, 150, 200] maturities = [1 / 12., 3 / 12., 0.5, 1.0, 2.0, 3.0, 5.0, 7.5, 10] vol = [ 0.482627, 0.407617, 0.366682, 0.340110, 0.314266, 0.280241, 0.252471, 0.325552, 0.464811, 0.393336, 0.354664, 0.329758, 0.305668, 0.273563, 0.244024, 0.244886, 0.441864, 0.375618, 0.340464, 0.318249, 0.297127, 0.268839, 0.237972, 0.225553, 0.407506, 0.351125, 0.322571, 0.305173, 0.289034, 0.267361, 0.239315, 0.213761, 0.366761, 0.326166, 0.306764, 0.295279, 0.284765, 0.270592, 0.250702, 0.222928, 0.345671, 0.314748, 0.300259, 0.291744, 0.283971, 0.273475, 0.258503, 0.235683, 0.324512, 0.303631, 0.293981, 0.288338, 0.283193, 0.276248, 0.266271, 0.250506, 0.311278, 0.296340, 0.289481, 0.285482, 0.281840, 0.276924, 0.269856, 0.258609, 0.303219, 0.291534, 0.286187, 0.283073, 0.280239, 0.276414, 0.270926, 0.262173 ] start_v0 = 0.2 * 0.2 start_theta = start_v0 start_kappa = 0.5 start_sigma = 0.25 start_rho = -0.5 equityShortRateCorr = -0.5 corrConstraint = HestonHullWhiteCorrelationConstraint( equityShortRateCorr) heston_process = HestonProcess(r_ts, q_ts, s0, start_v0, start_kappa, start_theta, start_sigma, start_rho) h_model = HestonModel(heston_process) h_engine = AnalyticHestonEngine(h_model) options = [] # first calibrate a heston model to get good initial # parameters for i in range(len(maturities)): maturity = Period(int(maturities[i] * 12.0 + 0.5), Months) for j, s in enumerate(strikes): v = SimpleQuote(vol[i * len(strikes) + j]) helper = HestonModelHelper(maturity, calendar, s0.value, s, v, r_ts, q_ts, PriceError) helper.set_pricing_engine(h_engine) options.append(helper) om = LevenbergMarquardt(1e-6, 1e-8, 1e-8) # Heston model h_model.calibrate(options, om, EndCriteria(400, 40, 1.0e-8, 1.0e-4, 1.0e-8)) print("Heston calibration") print("v0: %f" % h_model.v0) print("theta: %f" % h_model.theta) print("kappa: %f" % h_model.kappa) print("sigma: %f" % h_model.sigma) print("rho: %f" % h_model.rho) h_process_2 = HestonProcess(r_ts, q_ts, s0, h_model.v0, h_model.kappa, h_model.theta, h_model.sigma, h_model.rho) hhw_model = HestonModel(h_process_2) options = [] for i in range(len(maturities)): tGrid = np.max((10.0, maturities[i] * 10.0)) hhw_engine = FdHestonHullWhiteVanillaEngine( hhw_model, hw_process, equityShortRateCorr, tGrid, 61, 13, 9, 0, True, FdmSchemeDesc.Hundsdorfer()) hhw_engine.enable_multiple_strikes_caching(strikes) maturity = Period(int(maturities[i] * 12.0 + 0.5), Months) # multiple strikes engine works best if the first option # per maturity has the average strike (because the first # option is priced first during the calibration and # the first pricing is used to calculate the prices # for all strikes # list of strikes by distance from moneyness indx = np.argsort(np.abs(np.array(strikes) - s0.value)) for j, tmp in enumerate(indx): js = indx[j] s = strikes[js] v = SimpleQuote(vol[i * len(strikes) + js]) helper = HestonModelHelper(maturity, calendar, s0.value, strikes[js], v, r_ts, q_ts, PriceError) helper.set_pricing_engine(hhw_engine) options.append(helper) vm = LevenbergMarquardt(1e-6, 1e-2, 1e-2) hhw_model.calibrate(options, vm, EndCriteria(400, 40, 1.0e-8, 1.0e-4, 1.0e-8), corrConstraint) print("Heston HW calibration with FD engine") print("v0: %f" % hhw_model.v0) print("theta: %f" % hhw_model.theta) print("kappa: %f" % hhw_model.kappa) print("sigma: %f" % hhw_model.sigma) print("rho: %f" % hhw_model.rho) relTol = 0.05 expected_v0 = 0.12 expected_kappa = 2.0 expected_theta = 0.09 expected_sigma = 0.5 expected_rho = -0.75 self.assertAlmostEquals(np.abs(hhw_model.v0 - expected_v0) / expected_v0, 0, delta=relTol) self.assertAlmostEquals(np.abs(hhw_model.theta - expected_theta) / expected_theta, 0, delta=relTol) self.assertAlmostEquals(np.abs(hhw_model.kappa - expected_kappa) / expected_kappa, 0, delta=relTol) self.assertAlmostEquals(np.abs(hhw_model.sigma - expected_sigma) / expected_sigma, 0, delta=relTol) self.assertAlmostEquals(np.abs(hhw_model.rho - expected_rho) / expected_rho, 0, delta=relTol)