3 votos

QuantLib en Python : el tiempo de Ejecución con OISRateHelper en comparación con el Swap/Depósito RateHelper

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 :

  1. ¿Por qué la creación de instancias de OISRateHelpers toma más tiempo que la creación de instancias de SwapRateHelpers/DepositRateHelpers?

  2. 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!

1voto

John61590 Puntos 11

He enviado la misma pregunta a la quantlib lista de correo. Y la solución fue establecer telescopicValueDates = True de OISRateHelpers.

OISRateHelper crea un programa con un montón de fechas; esto no es realmente es necesario para el propósito de la curva de arranque y puede evitar estableciendo el parámetro telescopicValueDates a true, lo que aumentará la velocidad de las cosas (sin cambiar la curva resultante de curso).

Finanhelp.com

FinanHelp es una comunidad para personas con conocimientos de economía y finanzas, o quiere aprender. Puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X