|
From: Peter C. <pca...@gm...> - 2018-07-27 19:36:04
|
Hi Sonderak,
1. that’s because it creates a schedule with lots of dates; this is not really necessary for the purpose of curve bootstrapping and you can avoid it by setting the parameter telescopicValueDates to true which will speed up things (without changing the resulting curve of course)
2. I don’t think so; the rate helper will be rebuild the next time the curve building is triggered and that will be time consuming again for the reason given in 1. - however this is not what you are observing, right, so I don’t know; does that observation persist with telescopicValueDates set to true?
Best Regards
Peter
> On 27 Jul 2018, at 11:17, Abhishek KANNUR <kan...@gm...> wrote:
>
> Hello,
> I have been working on valuation of interest rate swaps using dual curve bootstrapping. And for this I use OISRateHelper to create a discount term structure using OIS rates. The entire code below :
>
> import QuantLib as ql
> ql.IndexManager.instance().clearHistories()
> import math
> import numpy as np
> import pandas as pd
> import datetime as dt
> #### INPUTS
> date0 = dt.datetime.strptime("2012-07-05", "%Y-%m-%d")
> date1 = dt.datetime.strptime("2012-07-06", "%Y-%m-%d")
> calculation_dates = [ql.Date(date0.day,date0.month,date0.year), ql.Date(date1.day,date1.month,date1.year)]
> fwd_start = 0
> ois_mat = [ql.Period(x) for x in ['1D', '2W', '1M', '2M', '3M', '4M', '5M', '6M',
> '7M', '8M', '9M', '10M', '11M', '12M', '18M', '2Y',
> '30M', '3Y', '4Y', '5Y', '6Y', '7Y', '8Y', '9Y', '10Y',
> '11Y', '12Y', '15Y', '20Y', '25Y', '30Y', '35Y', '40Y',
> '50Y']]
> ois_rates0 = [0.331, 0.162, 0.1525, 0.138, 0.136, 0.134, 0.133, 0.132, 0.135, 0.133, 0.134, 0.133, 0.134, 0.135, 0.146, 0.168, 0.197, 0.263, 0.419, 0.622, 0.8364, 1.006, 1.1625, 1.302, 1.429, 1.544, 1.64, 1.839, 1.93, 1.964, 1.999, 2.0465, 2.097, 2.1675]
> ois_rates1 = [0.329, 0.145, 0.134, 0.129, 0.13, 0.1235, 0.125, 0.145, 0.126, 0.12, 0.127, 0.122, 0.123, 0.125, 0.141, 0.165, 0.192, 0.253, 0.402, 0.595, 0.795, 0.976, 1.131, 1.27, 1.4049, 1.517, 1.611, 1.811, 1.901, 1.94, 1.963, 2.0265, 2.091, 2.173]
> ois_dict0 = dict(zip(ois_mat, [x/100 for x in ois_rates0]))
> ois_dict1 = dict(zip(ois_mat, [x/100 for x in ois_rates1]))
> list_ois_rates_dict = [ois_dict0, ois_dict1]
> deposit_mat = [ql.Period(1, ql.Months), ql.Period(3, ql.Months), ql.Period(6, ql.Months)]#, ql.Period(12, ql.Months)]
> deposit_rates0 = [0.00362, 0.00641, 0.0092]
> deposit_rates1 = [0.00255, 0.00549, 0.00831]
> deposit_dict0 = dict(zip(deposit_mat, deposit_rates0))
> deposit_dict1 = dict(zip(deposit_mat, deposit_rates1))
> list_deposit_rates_dict = [deposit_dict0, deposit_dict1]
> swap_mats = [ql.Period(x, ql.Years) for x in [1,2,3,4,5,6,7,8,9,10,12,15,20,25,30]]
> swap_rates0 = [0.00515, 0.00806, 0.00883, 0.01029, 0.01213, 0.0139, 0.01544, 0.01677, 0.01793, 0.01897, 0.02073, 0.02232, 0.02279, 0.02293, 0.02307]
> swap_rates1 = [0.00465, 0.00744, 0.00802, 0.00931, 0.01104, 0.01288, 0.0145, 0.01591, 0.01713, 0.01824, 0.02006, 0.0217, 0.02229, 0.02246, 0.02263]
> swap_dict0 = dict(zip(swap_mats, swap_rates0))
> swap_dict1 = dict(zip(swap_mats, swap_rates1))
> list_swap_curve_rates_dict = [swap_dict0, swap_dict1]
> libor_rates_dict = deposit_dict0.copy()
> swap_rates_dict = swap_dict0.copy()
> swap_libor_tenors = [ql.Period(x, ql.Months) for x in [6,6,6,6,6,6,6,6,6,6,6,6,6,6,6]]
> settlement_days = 0
> face_value = 100
> fixed_day_count = ql.Thirty360()
> float_day_count = ql.Actual360()
> ois_day_count = ql.Actual360()
> calendar = ql.TARGET()
> list_fixed_coupon_frequency = [ql.Annual for x in range(len(swap_libor_tenors))]
> currency = ql.EURCurrency()
> spread = 0
> business_convention = ql.ModifiedFollowing
> date_generation = ql.DateGeneration.Forward
> end_of_month = False
>
>
>
> ### CALCULATIONS
> fixed_npv = []
> float_npv = []
> swap_npv = []
> swap_fair_rate = []
> ql.IndexManager.instance().clearHistories()
> date_t0 = calculation_dates[0]
> ql.Settings.instance().evaluationDate = date_t0
> effective_start_date = calendar.advance(date_t0, settlement_days + fwd_start, ql.Days)
> discount_term_structure = ql.RelinkableYieldTermStructureHandle()
> forecast_term_structure = ql.RelinkableYieldTermStructureHandle()
> oindex = ql.OvernightIndex("", settlement_days, currency, calendar, ois_day_count, discount_term_structure)
> ######################
> t5 = dt.datetime.now()
> ######################
> ois_quote_map = {}
> ois_helpers_t0 = []
> for r,m in zip(list_ois_rates_dict[0].values(), list_ois_rates_dict[0].keys()):
> quote = ql.SimpleQuote(r)
> helper= ql.OISRateHelper(settlement_days, m, ql.QuoteHandle(quote), oindex)
> ois_helpers_t0.append(helper)
> ois_quote_map[m]=quote
> ######################
> t6 = dt.datetime.now()
> ######################
> deposit_quote_map = {}
> deposit_helpers_t0 = []
> for r,m in zip(list_deposit_rates_dict[0].values(), list_deposit_rates_dict[0].keys()):
> quote = ql.SimpleQuote(r)
> helper = ql.DepositRateHelper(ql.QuoteHandle(quote),m,settlement_days,calendar,
> business_convention,end_of_month,float_day_count)
> deposit_helpers_t0.append(helper)
> deposit_quote_map[m] = quote
> swap_ibor_indices = [ ql.IborIndex("", x, settlement_days, currency, calendar, business_convention, False, float_day_count,
> forecast_term_structure) for x in swap_libor_tenors]
> for sib in swap_ibor_indices:
> sib.addFixing(date_t0, libor_rates_dict[sib.tenor()])
>
> swap_quote_map = {}
> swap_helpers_t0 = []
> for r,m, ibor_index,f in zip(list_swap_curve_rates_dict[0].values(), list_swap_curve_rates_dict[0].keys(),
> swap_ibor_indices, list_fixed_coupon_frequency):
> quote = ql.SimpleQuote(r)
> helper = ql.SwapRateHelper(ql.QuoteHandle(quote),m,calendar,f,business_convention,fixed_day_count, ibor_index,
> ql.QuoteHandle(ql.SimpleQuote(0)),ql.Period(0, ql.Days), discount_term_structure,
> settlement_days)
> swap_helpers_t0.append(helper)
> swap_quote_map[m] = quote
> ######################
> t10 = dt.datetime.now()
> ######################
>
> helpers_t0 = deposit_helpers_t0 + swap_helpers_t0
> swap_curve_t0 = ql.PiecewiseLogCubicDiscount(settlement_days, calendar, helpers_t0, fixed_day_count)
> discount_curve_t0 = ql.PiecewiseLogCubicDiscount(settlement_days, calendar, ois_helpers_t0, fixed_day_count)
> swap_curve_t0.enableExtrapolation()
> discount_curve_t0.enableExtrapolation()
> discount_term_structure.linkTo(discount_curve_t0)
> forecast_term_structure.linkTo(swap_curve_t0)
> swap_engine = ql.DiscountingSwapEngine(discount_term_structure)
> list_irs = []
> for i in range(len(swap_mats)):
> swap_rate = list(swap_rates_dict.values())[i]
> fixed_tenor = ql.Period(list_fixed_coupon_frequency[i])
> float_tenor = swap_ibor_indices[i].tenor()
> fixed_schedule = ql.Schedule(effective_start_date, calendar.advance(effective_start_date, list(swap_rates_dict.keys())[i]),
> fixed_tenor, calendar,
> business_convention, business_convention,
> date_generation, end_of_month)
> float_schedule = ql.Schedule(effective_start_date, calendar.advance(effective_start_date, list(swap_rates_dict.keys())[i]),
> float_tenor, calendar,
> business_convention, business_convention,
> date_generation, end_of_month)
> irs_temp = ql.VanillaSwap(ql.VanillaSwap.Receiver, face_value, fixed_schedule, swap_rate, fixed_day_count,
> float_schedule, swap_ibor_indices[i], spread, float_day_count)
> irs_temp.setPricingEngine(swap_engine)
> if fwd_start > 0:
> fair_swap_rate = irs_temp.fairRate()
> irs = ql.VanillaSwap(ql.VanillaSwap.Receiver, face_value, fixed_schedule, fair_swap_rate, fixed_day_count,
> float_schedule, swap_ibor_indices[i], spread, float_day_count)
> irs.setPricingEngine(swap_engine)
> list_irs.append(irs)
> else:
> list_irs.append(irs_temp)
>
>
> fixed_npv.append([x.fixedLegNPV() for x in list_irs])
> float_npv.append([x.floatingLegNPV() for x in list_irs])
> swap_npv.append([x.NPV() for x in list_irs])
> swap_fair_rate.append([x.fairRate() for x in list_irs])
>
>
> print("ois helpers on date0: " + str((t6 - t5)))
> print("other helpers on date0: " + str((t10 - t6)))
>
> ######################
> t19 = dt.datetime.now()
> ######################
> tdelta = dt.timedelta()
> if len(calculation_dates) > 1:
> for i in range(1, len(calculation_dates)):
> ######################
> t19_1 = dt.datetime.now()
> ######################
> date_ti = calculation_dates[i]
> ql.Settings.instance().evaluationDate = date_ti
> ######################
> t19_2 = dt.datetime.now()
> ######################
> for k in list_ois_rates_dict[i].keys():
> ois_quote_map[k].setValue(list_ois_rates_dict[i][k])
>
> for k in list_deposit_rates_dict[i].keys():
> deposit_quote_map[k].setValue(list_deposit_rates_dict[i][k])
> for k in list_swap_curve_rates_dict[i].keys():
> swap_quote_map[k].setValue(list_swap_curve_rates_dict[i][k])
> fixed_npv.append([x.fixedLegNPV() for x in list_irs])
> float_npv.append([x.floatingLegNPV() for x in list_irs])
> swap_npv.append([x.NPV() for x in list_irs])
> swap_fair_rate.append([x.fairRate() for x in list_irs])
>
> ######################
> tdelta = tdelta + (t19_2 - t19_1)
> ######################
> ######################
> t20 = dt.datetime.now()
> ######################
> print("Calculations for other dates: " + str((t20 - t19)))
> print("Setting evaluation dates for other dates: " + str(tdelta))
>
>
> I have calculated execution time for creating an instance of OISRateHelpers and compared them to execution time for creating instances of DepositRateHelpers and SwapRateHelpers.
>
> ois helpers on date0: 0:00:00.299389
> other helpers on date0: 0:00:00.000999
>
> The output shows that there is a major difference between.
>
> Also, when recalculating the swaps, on other dates (other than date0), it's the ql.Settings.instance().evaluationDate which takes up more time.
>
> Calculations for other dates: 0:00:09.596271
> Setting evaluation dates for other dates: 0:00:09.554356
>
> From this thread <https://quant.stackexchange.com/questions/39671/why-we-should-specify-the-evaluation-date-when-using-quantlib-yield-curve-and-w/40158>, I have come to understand that setting new dates changes reference dates for all the instances declared before.
>
> I am trying to understand :
>
> 1. Why creating instances of OISRateHelpers takes longer than creating instances of SwapRateHelpers/DepositRateHelpers?
>
> 2. The fact that changing evaluation dates is time consuming, is it possible that OISRateHelper is creating 'redundant' dependencies which require notifications for changes in evaluation dates as well? Thus making it time consuming when resetting evaluation dates in ql.Settings?
>
> Thank you!
>
> PS: I have posted this question on Quant.StackExchange.com <https://quant.stackexchange.com/questions/40939/quantlib-in-python-execution-time-with-oisratehelper-compared-to-swap-deposit> <http:/> as well.
>
>
> Best,
> Sonderak
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot_______________________________________________
> QuantLib-users mailing list
> Qua...@li...
> https://lists.sourceforge.net/lists/listinfo/quantlib-users
|