|
From: Abhishek K. <kan...@gm...> - 2018-07-27 18:36:59
|
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>
as well.
Best,
Sonderak
|