5 votos

Bootstrap con QuantLib: Intercambio justo o VAN cero

En toda la brevedad

  1. ¿Cuál es la condición de terminación utilizada en el bootstrapping de curvas de QuantLib?
  2. ¿Puedo modificar esta configuración para adaptarla a mis necesidades, por ejemplo, puedo ajustarla a una mayor precisión?

Antecedentes

Al realizar el bootstrapping de las curvas de descuento y proyección, una condición necesaria es que las curvas implícitas pongan precio al instrumentos de referencia en el mercado, es decir, valorar los instrumentos que se suministraron originalmente al algoritmo de construcción de la curva lo más cerca posible de sus precios de entrada. Con una curva que utiliza un mecanismo de interpolación local ( bootstrap iterativo ), supondría que todos los instrumentos de referencia se reajustan a los precios de mercado con un error mínimo, es decir

Supongamos un mecanismo de curva/bootstrap que utilice la interpolación local, por ejemplo, la interpolación lineal de los factores de descuento logarítmicos. Dada una comilla de mercado, y dada la curva construida "hasta ahora", el mecanismo bootstrap selecciona el "próximo" instrumento de referencia y actualiza la curva desplazando un tipo en un punto del nodo hasta que el instrumento de referencia tenga un precio de mercado.

Mi observación y pregunta

Vuelvo a fijar el precio de mis instrumentos de referencia en la curva que acabo de calcular y descubro que éstos no tienen un precio tan cercano a cero como habría supuesto, véase el ejemplo mínimo que aparece a continuación:

import QuantLib as ql

today = ql.Date(23,ql.June,2020)
ql.Settings.instance().evaluationDate = today
eonia = ql.Eonia()

Suponiendo comillas OIS "planas" en el mercado al 1% por tenor y recogiendo las ayudas a la construcción de la curva:

quotes = {str(k)+'Y' : ql.SimpleQuote(0.01) for k in range(1,21)}
ois_helpers = []    
for k,v in quotes.items():
    ois_helpers.append(ql.OISRateHelper(
        settlementDays = 2, 
        tenor = ql.Period(k), 
        rate = ql.QuoteHandle(v), 
        index = eonia, 
        telescopicValueDates =True))

eonia_curve = ql.PiecewiseLinearZero(2,ql.TARGET(),ois_helpers,ql.Actual365Fixed())
val_curve   = ql.YieldTermStructureHandle(eonia_curve)

Crear otro eonia_index esta vez con una curva de proyección adjunta; y un motor de valoración:

eonia_index = ql.Eonia(val_curve)
swap_engine = ql.DiscountingSwapEngine(val_curve)

Ahora configuro los instrumentos de referencia como instrumentos "reales" y obtengo sus VAN. Tenga en cuenta que asumo un nocional de 1 million currs:

print('TENOR \t PV \t fairrate% \t fairrate% + fairspread%')
for p in quotes.keys():
    schedule = ql.MakeSchedule(today, today + ql.Period(p), ql.Period('1d'), calendar=ql.TARGET())
    fixedRate = quotes[p].value()
    ois_swap = ql.OvernightIndexedSwap(
        ql.OvernightIndexedSwap.Receiver, 
        1E6, 
        schedule, 
        fixedRate, 
        ql.Actual360(),
        eonia_index)
    ois_swap.setPricingEngine(swap_engine)
    print(p + "\t" + 
        str(round(ois_swap.NPV(),2)) + " \t " + 
        str(round(ois_swap.fairRate()*100,4)) + "\t\t" +
        str(100*(ois_swap.fairRate()+ois_swap.fairSpread())))

Resultando en

TENOR    NPV     fairrate%   fairrate% + fairspread%
1Y  50.25    0.995      1.0
2Y  100.55   0.995      1.0
3Y  149.95   0.995      1.0
4Y  199.23   0.995      1.0
5Y  247.63   0.995      1.0
6Y  295.67   0.995      1.0
7Y  343.23   0.995      1.0
8Y  390.7    0.995      1.0
9Y  437.44   0.995      1.0
10Y 483.46   0.995      1.0
11Y 529.01   0.995      1.0
12Y 574.48   0.995      1.0
13Y 619.49   0.995      1.0
14Y 663.69   0.995      1.0
15Y 707.68   0.995      1.0
16Y 751.11   0.995      1.0
17Y 794.1    0.995      1.0
18Y 836.66   0.995      1.0
19Y 879.03   0.995      1.0
20Y 920.98   0.995      1.0

Evidentemente, el tipo justo implícito no es exactamente el 1%, pero el tipo justo implícito más el diferencial implícito dan el 1%. Además, el VAN de cada swap está cerca, pero no "muy" cerca de cero.

Me pregunto si

  1. ¿hay algo raro en la configuración de mis instrumentos?
  2. Qué condición terminal está aplicando aquí la metodología bootstrap de QuantLib, y
  3. Si puedo poner límites más estrictos a ese mecanismo.

Muchas gracias por cualquier aportación/opinión/consejo.

Mi configuración

He construido la curva de descuento siguiendo el QuantLib Python Cookbook de Luigi y Goutham a partir de 2019-JUNIO-01; estoy utilizando el QuantLib Python SWIG; versión 1.19.

6voto

Chris Mc Puntos 31

El problema es que no se está valorando lo mismo, y por dos razones:

  1. Los instrumentos de vainilla que está valorando deben comenzar en la fecha de contado y tener un vencimiento con ese comienzo como referencia
  2. La frecuencia del tramo fijo del swap OIS debe ser anual.

Si cambias tu código a:

print('TENOR \t PV \t fairrate% \t fairrate% + fairspread%')
calendar = ql.TARGET()
for p in quotes.keys():
    start = calendar.advance(today, 2, ql.Days)
    schedule = ql.MakeSchedule(start, calendar.advance(start, ql.Period(p)), ql.Period('1Y'), calendar=calendar)
    fixedRate = quotes[p].value()
    ois_swap = ql.OvernightIndexedSwap(
        ql.OvernightIndexedSwap.Receiver, 
        1E6, 
        schedule, 
        fixedRate, 
        ql.Actual360(),
        eonia_index)

    ois_swap.setPricingEngine(swap_engine)
    print(p + "\t" + 
        str(round(ois_swap.NPV(),2)) + " \t \t" + 
        str(round(ois_swap.fairRate()*100,4)) + "\t\t" +
        str(100*(ois_swap.fairRate()+ois_swap.fairSpread())))

Obtendrás la salida correcta.

Esto también se puede comprobar extrayendo los instrumentos de los ayudantes:

print('TENOR \t PV \t fairrate% \t fairrate% + fairspread%')
for idx, p in enumerate(quotes.keys()):
    ois_swap = ois_helpers[idx].swap()
    ois_swap.setPricingEngine(swap_engine)
    print(p + "\t" + 
        str(round(ois_swap.NPV(),2)) + " \t \t" + 
        str(round(ois_swap.fairRate()*100,4)) + "\t\t" +
        str(100*(ois_swap.fairRate()+ois_swap.fairSpread())))

0 votos

Muchas gracias, David.

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