4 votos

Intercambiar Bootstrapping con quantlib

He estado tratando de obtener las tasas cero de la curva del Swap chileno con Quantlib en Python, pero no he podido configurar los parámetros correctamente. Este es mi código:

import QuantLib as ql
import pandas as pd

#Custom Calendar with Chilean Holidays
def create_calendar_chile(start_year,n_years):
    Chile = ql.WeekendsOnly()
    days = [1,14,15,1,21,26,2,16,15,18,19,9,27,1,19,8,17,25,31]
    months = [1,4,4,5,5,6,8,9,9,10,10,11,12,12,12,12]
    name = ['Año Nuevo','Viernes Santo','Sabado Santo','Dia del Trabajo','Dia de las Glorias Navales','San Pedro y San Pablo','Elecciones Primarias','Dia de la Virgen del Carmen','Asuncion de la Virgen','Independencia Nacional','Glorias del Ejercito','Encuentro de dos mundos','Día de las Iglesias Evangélicas y Protestantes','Día de todos los Santos','Elecciones Presidenciales y Parlamentarias','Inmaculada Concepción','Segunda vuelta Presidenciales','Navidad','Feriado Bancario']
    for i in range(n_years+1):
        for x,y in zip(days,months):
            date = ql.Date(x,y,start_year+i)
            Chile.addHoliday(date)

    return Chile

today = ql.Date(25, 10, 2017)
ql.Settings.instance().evaluationDate = today

swap_clp = [2.46, 2.40, 2.40, 2.41, 2.54, 2.68, 3.01, 3.3, 3.53, 3.69, 3.87, 4.02, 4.13, 4.23, 4.38, 4.38, 4.56]
terms = [3,6,9,12,18,2,3,4,5,6,7,8,9,10,12,15,20]
## SWAP Parameters ##
calendar = create_calendar_chile(2001,50)
bussiness_convention = ql.Following
day_count = ql.Actual360()

#Overnigth Rate
TPM = 2.5
depo_helper = [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(TPM/100)),ql.Period(1,ql.Days),1,calendar,ql.Unadjusted,False,ql.Actual360())]

#Swap Rates
swap_helpers = []
for i in range(len(terms)):
    if i < 4:
        coupon_frequency = ql.Once
        tenor = ql.Period(terms[i],ql.Months)
        rate = swap_clp[i]
        swap_helpers.append(ql.SwapRateHelper(ql.QuoteHandle(ql.SimpleQuote(rate/100.0)),tenor, calendar,coupon_frequency, bussiness_convention,day_count,ql.Euribor3M()))
    else:
        coupon_frequency = ql.Semiannual
        tenor = ql.Period(terms[i],ql.Years)
        rate = swap_clp[i]
        swap_helpers.append(ql.SwapRateHelper(ql.QuoteHandle(ql.SimpleQuote(rate/100.0)),tenor, calendar,coupon_frequency, bussiness_convention,day_count,ql.Euribor3M()))

#Yield Curve
rate_helpers = depo_helper + swap_helpers
yieldcurve = ql.PiecewiseLinearZero(today,rate_helpers,day_count)

spots = []
tenors = []
for d in yieldcurve.dates():
    yrs = day_count.yearFraction(today, d)
    compounding = ql.Simple
    freq = ql.Annual
    zero_rate = yieldcurve.zeroRate(yrs, compounding, freq)
    tenors.append(yrs)
    eq_rate = zero_rate.equivalentRate(day_count,compounding,freq,today,d).rate()
    spots.append(100*eq_rate)

datatable = {'Dates':yieldcurve.dates(),'Tenors':tenors,'spots':spots}
df = pd.DataFrame.from_dict(datatable)

Y estoy obteniendo los siguientes resultados:

>>> df
                 Dates     Tenors     spots
0   October 25th, 2017   0.000000  0.000000
1   October 27th, 2017   0.005556  2.500087
2   January 29th, 2018   0.266667  2.461170
3     April 27th, 2018   0.511111  2.401418
4      July 27th, 2018   0.763889  2.401059
5   October 29th, 2018   1.025000  2.410821
6   October 28th, 2019   2.036111  2.739493
7   October 27th, 2020   3.050000  3.141727
8   October 27th, 2021   4.063889  3.529495
9   October 27th, 2022   5.077778  3.875600
10  October 27th, 2023   6.091667  4.157661
11  October 28th, 2024   7.111111  4.495323
12  October 27th, 2025   8.122222  4.817217
13  October 27th, 2026   9.136111  5.100542
14  October 27th, 2027  10.150000  5.390948
15  October 29th, 2029  12.186111  5.945168
16  October 27th, 2032  15.225000  6.352031
17  October 29th, 2035  18.272222  2.707640
18  October 27th, 2037  20.297222  8.655828

Los tipos cero son erróneos según Bloomberg boostrap (dejando de lado pequeñas diferencias en los tipos y fechas). Estoy utilizando el índice Euribor3M en el Swap Helpers pero supongo que está mal. ¿Cómo podría configurar un índice personalizado en python? Además, los niveles de los ceros parecen ser un poco altos en comparación con los ceros reales:

Bloomberg:
Date    Days    Term    InstType    Mid Zero
26-10-2017  1   O/N CASH    2,500   2,500
30-01-2018  97  3 MO    CASH    2,460   2,460
30-04-2018  187 6 MO    CASH    2,400   2,400
30-07-2018  278 9 MO    CASH    2,400   2,400
30-10-2018  370 1 YR    CASH    2,410   2,410
30-04-2019  552 18 MO   CASH    2,540   2,540
30-10-2019  735 2 YR    SWAP    2,680   2,684
30-10-2020  1101    3 YR    SWAP    3,010   3,024
29-10-2021  1465    4 YR    SWAP    3,300   3,327
28-10-2022  1829    5 YR    SWAP    3,540   3,582
30-10-2023  2196    6 YR    SWAP    3,700   3,752
30-10-2024  2562    7 YR    SWAP    3,870   3,939
30-10-2025  2927    8 YR    SWAP    4,030   4,119
30-10-2026  3292    9 YR    SWAP    4,140   4,243
29-10-2027  3656    10 YR   SWAP    4,230   4,346
30-10-2032  5484    15 YR   SWAP    4,380   4,502
30-10-2037  7310    20 YR   SWAP    4,560   4,742

3voto

Brad Tutterow Puntos 5628

Probablemente ya lo hayas deducido, ya que mencionas en los comentarios que los tipos de Bloomberg se componen semestralmente. Sin embargo, los tipos más altos tienen que ver con la convención de capitalización que estás eligiendo. Estás pidiendo tipos con capitalización simple, y eso anula la frecuencia anual que estás pasando y hace que los tipos sean más altos de lo que esperas. Utilizando Compounded y Semiannual devuelve valores mucho más cercanos a los que has citado.

2voto

Jed Puntos 6

Para el 2,707 que se obtiene en el año 18, hay un error en su código. El tenor de 18 meses se carga como 18 años

#Swap Rates
swap_helpers = []
for i in range(len(terms)):
    if i < 4:  # should be i < 5!!! 
        ...

Sin embargo, no conozco las convenciones utilizadas para las tasas de Bloomberg como para comentar la diferencia.

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