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 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 _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 test_yield(self): rates_data = [('Libor1M',.01), ('Libor3M', .015), ('Libor6M', .017), ('Swap1Y', .02), ('Swap2Y', .03), ('Swap3Y', .04), ('Swap5Y', .05), ('Swap7Y', .06), ('Swap10Y', .07), ('Swap20Y', .08)] settlement_date = pydate_to_qldate('01-Dec-2013') rate_helpers = [] for label, rate in rates_data: h = make_rate_helper(label, rate, settlement_date) rate_helpers.append(h) 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 ) zc = zero_rate(ts, (200, 300), settlement_date) # not a real test - just verify execution self.assertAlmostEqual(zc[1][0], 0.0189, 2)
def test_yield(self): rates_data = [('Libor1M',.01), ('Libor3M', .015), ('Libor6M', .017), ('Swap1Y', .02), ('Swap2Y', .03), ('Swap3Y', .04), ('Swap5Y', .05), ('Swap7Y', .06), ('Swap10Y', .07), ('Swap20Y', .08)] settlement_date = pydate_to_qldate('01-Dec-2013') rate_helpers = [] for label, rate in rates_data: h = make_rate_helper(label, rate, settlement_date) rate_helpers.append(h) 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 ) zc = zero_rate(ts, (200, 300), settlement_date) # not a real test - just verify execution self.assertAlmostEqual(zc[1][0], 0.0189, 2)
def test_yield(self): rates_data = [('Libor1M',SimpleQuote(.01)), ('Libor3M', SimpleQuote(.015)), ('Libor6M', SimpleQuote(.017)), ('Swap1Y', SimpleQuote(.02)), ('Swap2Y', SimpleQuote(.03)), ('Swap3Y', SimpleQuote(.04)), ('Swap5Y', SimpleQuote(.05)), ('Swap7Y', SimpleQuote(.06)), ('Swap10Y', SimpleQuote(.07)), ('Swap20Y', SimpleQuote(.08))] settlement_date = pydate_to_qldate('01-Dec-2013') rate_helpers = [] for label, rate in rates_data: h = make_rate_helper(label, rate, settlement_date) rate_helpers.append(h) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = PiecewiseYieldCurve( 'discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance ) zc = zero_rate(ts, (200, 300), settlement_date) # not a real test - just verify execution self.assertAlmostEqual(zc[1][0], 0.0189, 2)
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_yield(self): rates_data = [ ("Libor1M", 0.01), ("Libor3M", 0.015), ("Libor6M", 0.017), ("Swap1Y", 0.02), ("Swap2Y", 0.03), ("Swap3Y", 0.04), ("Swap5Y", 0.05), ("Swap7Y", 0.06), ("Swap10Y", 0.07), ("Swap20Y", 0.08), ] settlement_date = pydate_to_qldate("01-Dec-2013") rate_helpers = [] for label, rate in rates_data: h = make_rate_helper(label, rate, settlement_date) rate_helpers.append(h) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = term_structure_factory("discount", "loglinear", settlement_date, rate_helpers, ts_day_counter, tolerance) zc = zero_rate(ts, (200, 300), settlement_date) # not a real test - just verify execution self.assertAlmostEqual(zc[1][0], 0.0189, 2)
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 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_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_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 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_converter_1(self): ql_today_1 = today() py_today = datetime.date.today() ql_today_2 = pydate_to_qldate(py_today) self.assertEquals(ql_today_1.day, ql_today_2.day) self.assertEquals(ql_today_1.month, ql_today_2.month) self.assertEquals(ql_today_1.year, ql_today_2.year)
def test_converter_2(self): ql_1 = Date(20, Nov, 2005) ql_2 = pydate_to_qldate('20-Nov-2005') self.assertEquals(ql_1.day, ql_2.day) self.assertEquals(ql_1.month, ql_2.month) self.assertEquals(ql_1.year, ql_2.year)
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 test_converter_2(self): ql_1 = Date(20, Nov, 2005) ql_2 = pydate_to_qldate('20-Nov-2005') self.assertEquals(ql_1.day, ql_2.day) self.assertEquals(ql_1.month, ql_2.month) self.assertEquals(ql_1.year, ql_2.year)
def test_converter_1(self): ql_today_1 = today() py_today = datetime.date.today() ql_today_2 = pydate_to_qldate(py_today) self.assertEquals(ql_today_1.day, ql_today_2.day) self.assertEquals(ql_today_1.month, ql_today_2.month) self.assertEquals(ql_today_1.year, ql_today_2.year)
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 next_imm_date(reference_date, tenor): """ Third Wednesday of contract month """ dt = qldate_from_pydate(reference_date) for k in range(tenor): tmp = imm.next_date(dt) dt = pydate_to_qldate(tmp) return pydate_from_qldate(dt)
def next_imm_date(reference_date, tenor): """ Third Wednesday of contract month """ dt = qldate_from_pydate(reference_date) for k in range(tenor): tmp = imm.next_date(dt) dt = pydate_to_qldate(tmp) return pydate_from_qldate(dt)
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 _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 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 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 zero_rate(term_structure, days, dt_settlement, calendar=TARGET()): """ Compute zero-coupon rate, continuous ACT/365 from settlement date to given maturity expressed in calendar days Return - array of maturity dates - array of zero-coupon rates """ dtMat = [calendar.advance(pydate_to_qldate(dt_settlement), d, Days) for d in days] df = np.array([term_structure.discount(dt) for dt in dtMat]) dtMat = [qldate_to_pydate(dt) for dt in dtMat] dtToday = qldate_to_pydate(dt_settlement) dt = np.array([(d - dtToday).days / 365.0 for d in dtMat]) zc = -np.log(df) / dt return (dtMat, zc)
def zero_rate(term_structure, days, dt_settlement, calendar=TARGET()): """ Compute zero-coupon rate, continuous ACT/365 from settlement date to given maturity expressed in calendar days Return - array of maturity dates - array of zero-coupon rates """ dtMat = [calendar.advance(pydate_to_qldate(dt_settlement), d, Days) for d in days] df = np.array([term_structure.discount(dt) for dt in dtMat]) dtMat = [qldate_to_pydate(dt) for dt in dtMat] dtToday = qldate_to_pydate(dt_settlement) dt = np.array([(d - dtToday).days / 365.0 for d in dtMat]) zc = -np.log(df) / dt return (dtMat, zc)
def make_term_structure(rates, dt_obs): """ rates is a dictionary-like structure with labels as keys and rates (decimal) as values. TODO: Make it more generic """ settlement_date = pydate_to_qldate(dt_obs) rate_helpers = [] for label in rates.keys(): r = rates[label] h = make_rate_helper(label, r, settlement_date) rate_helpers.append(h) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = PiecewiseYieldCurve('discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) return ts
def make_term_structure(rates, dt_obs): """ rates is a dictionary-like structure with labels as keys and rates (decimal) as values. TODO: Make it more generic """ settlement_date = pydate_to_qldate(dt_obs) rate_helpers = [] for label in rates.keys(): r = rates[label] h = make_rate_helper(label, r, settlement_date) rate_helpers.append(h) ts_day_counter = ActualActual(ISDA) tolerance = 1.0e-15 ts = term_structure_factory('discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) return ts
def make_term_structure(rates, dt_obs): """ rates is a dictionary-like structure with labels as keys and rates (decimal) as values. TODO: Make it more generic """ settlement_date = pydate_to_qldate(dt_obs) rate_helpers = [] for label in rates.keys(): r = rates[label] h = make_rate_helper(label, r, settlement_date) rate_helpers.append(h) 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 ) 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 test_swap_from_market(self): """ Test that a swap with fixed coupon = fair rate has an NPV=0 Create from market """ eval_date = Date(02, 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', 0.0382), ('DEP', '1M', 0.0372), ('DEP', '3M', 0.0363), ('DEP', '6M', 0.0353), ('DEP', '9M', 0.0348), ('DEP', '1Y', 0.0345), ('SWAP', '2Y', 0.037125), ('SWAP', '3Y', 0.0398), ('SWAP', '5Y', 0.0443), ('SWAP', '10Y', 0.05165), ('SWAP', '15Y', 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.leg(0) print fixed_l.to_str() float_l = swap.leg(1) print float_l.to_str() 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 a, dt in fixed_l.items: df = m.discount(pydate_to_qldate(dt)) tot += a * df print('fixed npv: %f discounted cf: %f' % (fixed_npv, tot)) self.assertAlmostEquals(fixed_npv, -tot) tot = 0.0 for a, dt in float_l.items: df = m.discount(pydate_to_qldate(dt)) tot += a * df print('float npv: %f discounted cf: %f' % (float_npv, tot)) self.assertAlmostEquals(float_npv, tot)
def test_zero_curve(self): try: 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)) depositData = [[1, Months, 'Libor1M', 5.32], [3, Months, 'Libor3M', 5.35], [6, Months, 'Libor6M', 5.35]] swapData = [[1, Years, 'Swap1Y', 5.31], [2, Years, 'Swap2Y', 5.06], [3, Years, 'Swap3Y', 5.00], [4, Years, 'Swap4Y', 5.01], [5, Years, 'Swap5Y', 5.04], [7, Years, 'Swap7Y', 5.12], [10, Years, 'Swap10Y', 5.22], [30, Years, 'Swap30Y', 5.44]] rate_helpers = [] end_of_month = True for m, period, label, rate in depositData: tenor = Period(m, Months) 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, rate in swapData: 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-2 ts = PiecewiseYieldCurve('discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) # max_date raises an exception... dtMax = ts.max_date print('max date: %s' % dtMax) except RuntimeError as e: print('Exception (expected):\n%s' % e) self.assertTrue(True) except Exception: self.assertFalse()
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(02, 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', 0.0382), ('DEP', '1M', 0.0372), ('DEP', '3M', 0.0363), ('DEP', '6M', 0.0353), ('DEP', '9M', 0.0348), ('DEP', '1Y', 0.0345), ('SWAP', '2Y', 0.037125), ('SWAP', '3Y', 0.0398), ('SWAP', '5Y', 0.0443), ('SWAP', '10Y', 0.05165), ('SWAP', '15Y', 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.leg(0) print fixed_l.to_str() float_l = swap.leg(1) print float_l.to_str() 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 a, dt in fixed_l.items: df = m.discount(pydate_to_qldate(dt)) tot += a * df print('fixed npv: %f discounted cf: %f' % (fixed_npv, tot)) self.assertAlmostEquals(fixed_npv, -tot) tot = 0.0 for a, dt in float_l.items: df = m.discount(pydate_to_qldate(dt)) tot += a * df print('float npv: %f discounted cf: %f' % (float_npv, tot)) self.assertAlmostEquals(float_npv, tot)
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_zero_curve(self): try: 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)) depositData = [[1, Months, 'Libor1M', 5.32], [3, Months, 'Libor3M', 5.35], [6, Months, 'Libor6M', 5.35]] swapData = [[1, Years, 'Swap1Y', 5.31], [2, Years, 'Swap2Y', 5.06], [3, Years, 'Swap3Y', 5.00], [4, Years, 'Swap4Y', 5.01], [5, Years, 'Swap5Y', 5.04], [7, Years, 'Swap7Y', 5.12], [10, Years, 'Swap10Y', 5.22], [30, Years, 'Swap30Y', 5.44]] rate_helpers = [] end_of_month = True for m, period, label, rate in depositData: tenor = Period(m, Months) 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, rate in swapData: 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-2 ts = PiecewiseYieldCurve('discount', 'loglinear', settlement_date, rate_helpers, ts_day_counter, tolerance) # max_date raises an exception... dtMax = ts.max_date print('max date: %s' % dtMax) except RuntimeError as e: print('Exception (expected):\n%s' % e) self.assertTrue(True) except Exception: self.assertFalse()
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 = 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}