He estado trabajando en la valoración de los swaps de tipos de interés con doble curva de arranque. Y para esto yo uso OISRateHelper para crear un descuento término estructura utilizando las tasas OIS. Todo el código a continuación :
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))
He calculado el tiempo de ejecución para la creación de una instancia de OISRateHelpers comparación con el tiempo de ejecución para la creación de instancias de DepositRateHelpers y SwapRateHelpers.
ois helpers on date0: 0:00:00.299389
other helpers on date0: 0:00:00.000999
El resultado muestra que existe una gran diferencia entre.
También, al recalcular los swaps, en otras fechas (aparte de date0), es el ql.Los ajustes.instancia().evaluationDate que se tarda más tiempo.
Calculations for other dates: 0:00:09.596271
Setting evaluation dates for other dates: 0:00:09.554356
A partir de este hilo, he llegado a comprender que la configuración de las nuevas fechas de los cambios de fechas de referencia para todas las instancias declarado antes.
Estoy tratando de entender :
¿Por qué la creación de instancias de OISRateHelpers toma más tiempo que la creación de instancias de SwapRateHelpers/DepositRateHelpers?
El hecho de que el cambio de fechas de evaluación es mucho tiempo, es posible que OISRateHelper es la creación de 'redundante' dependencias que requieren las notificaciones de cambios en las fechas de evaluación así? Por lo tanto lo que es el tiempo que consume al restablecer fechas de evaluación en la cv.Configuración?
Gracias!