2 votos

Creación de un porcentaje de IRS de tipo variable en QuantLib

Estoy empezando a aprender Quantlib para Python.

Estoy intentando averiguar cómo se crea un swap de tipos de interés en el que el tramo flotante es un porcentaje del índice flotante. Por ejemplo, el tramo flotante sería el 70% del LIBOR de 1M USD.

Cualquier ayuda es muy apreciada.

Nota: Para los curiosos, los swaps del % del LIBOR son una estructura común para las entidades municipales en Estados Unidos. Estas entidades pueden emitir deuda exenta de impuestos y el tramo flotante se ajusta de modo que el % = (1 - tipo impositivo marginal).

4voto

David Radcliffe Puntos 136

Esta característica se denomina "engranaje".

Si miras en https://github.com/lballabio/QuantLib/blob/master/ql/cashflows/floatingratecoupon.hpp , ya ves

Real gearing = 1.0,

Pregunta relacionada: https://stackoverflow.com/questions/40283195/

0 votos

Se agradece mucho. Para Python, ¿sabes si el ajuste de engranaje sólo está disponible para el instrumento ql.NonstandardSwap? No parece estar disponible para ql.Swap o ql.VanillaSwap.

2 votos

Como escribió Luigi en su respuesta, el engranaje no se expone en VanillaSwap . Puede crear FixedLeg y IborLeg (no se sabe cómo decir .withGearings(gearing) en Python) y pasar ambos a Swap . O tal vez no está expuesto en Python en absoluto. Por cierto, ya vimos un bono municipal vinculado al SOFR con engranaje, emitido por la Autoridad de Transporte Metropolitano de Nueva York. bondbuyer.com/news/

2 votos

quantlib-python-docs.readthedocs.io/es/latest/ el NonStandardSwap podría ser una solución.

4voto

Chris Mc Puntos 31

Hay dos maneras de crear el intercambio que desea: (1) creando patas individuales ( ql.FixedRateLeg y IborLeg ) donde se puede proporcionar un engranaje a la ql.IborLeg y construir un swap ( ql.Swap ) con aquellos o (2) Utilizar el ql.NonstandardSwap clase

En primer lugar, definiré el código general que se utilizará en los ejemplos:

import QuantLib as ql
import pandas as pd

yts = ql.YieldTermStructureHandle(ql.FlatForward(2, ql.TARGET(), 0.05, ql.Actual360()))
engine = ql.DiscountingSwapEngine(yts)
index = ql.USDLibor(ql.Period('6M'), yts)

schedule = ql.MakeSchedule(ql.Date(15,6,2021), ql.Date(15,6,2023), ql.Period('6M'))
nominal = [10e6]

1. Creación de patas individuales

Antes de definir un engranaje, podemos construir un simple swap y examinar su pata flotante:

fixedLeg = ql.FixedRateLeg(schedule, index.dayCounter(), nominal, [0.05])
floatingLeg = ql.IborLeg(nominal, schedule, index)
swap = ql.Swap(fixedLeg, floatingLeg)
swap.setPricingEngine(engine)

print(f"Floating leg NPV: {swap.legNPV(1):,.2f}\n")
pd.DataFrame([{
    'fixingDate': cf.fixingDate().ISO(),
    'accrualStart': cf.accrualStartDate().ISO(),
    'accrualEnd': cf.accrualEndDate().ISO(),
    "paymentDate": cf.date().ISO(),
    'gearing': cf.gearing(),
    'forward': cf.indexFixing(),
    'rate': cf.rate(),
    "amount": cf.amount()
} for cf in map(ql.as_floating_rate_coupon, swap.leg(1))])

Observe que, por defecto, el engranaje será 1, por lo que la tasa de la pierna será la misma que la fijación/adelantamiento.

enter image description here

A continuación, utilizamos el parámetro "engranajes" del ql.IborLeg constructor:

floatingLeg = ql.IborLeg(nominal, schedule, index, gearings=[0.7])
swap = ql.Swap(fixedLeg, floatingLeg)
swap.setPricingEngine(engine)

print(f"Floating leg NPV: {swap.legNPV(1):,.2f}\n")
pd.DataFrame([{
    'fixingDate': cf.fixingDate().ISO(),
    'accrualStart': cf.accrualStartDate().ISO(),
    'accrualEnd': cf.accrualEndDate().ISO(),
    "paymentDate": cf.date().ISO(),
    'gearing': cf.gearing(),
    'forward': cf.indexFixing(),
    'rate': cf.rate(),
    "amount": cf.amount()
} for cf in map(ql.as_floating_rate_coupon, swap.leg(1))])

Obsérvese que aquí hemos ajustado la tasa de la pierna para que sea el tiempo de fijación/adelanto del engranaje.

enter image description here

Otra forma, un poco más chapucera, sería multiplicar el nocional por el engranaje de la iborLeg en lugar de utilizar el parámetro de engranaje.

2. NonstandardSwap

Se puede hacer exactamente lo mismo con el ql.NonstandardSwap aunque hay que tener más cuidado con el constructor, ya que espera matrices del nocional, el tipo, los diferenciales, los engranajes, etc., con el mismo tamaño que el respectivo calendario de pagos.

swapType = ql.VanillaSwap.Payer
numDates = (len(schedule)-1)
gearing = [0.7] * numDates
spread = [0.0] * numDates
fixedRateArray = [0.05] * numDates
nominalArray = nominal * numDates
nsSwap = ql.NonstandardSwap(
    swapType, nominalArray, nominalArray,
    schedule, fixedRateArray, index.dayCounter(),
    schedule, index, gearing, spread, index.dayCounter())

nsSwap.setPricingEngine(engine)
print(f"Floating leg NPV: {nsSwap.legNPV(1):,.2f}\n")
pd.DataFrame([{
    'fixingDate': cf.fixingDate().ISO(),
    'accrualStart': cf.accrualStartDate().ISO(),
    'accrualEnd': cf.accrualEndDate().ISO(),
    "paymentDate": cf.date().ISO(),
    'gearing': cf.gearing(),
    'forward': cf.indexFixing(),
    'rate': cf.rate(),
    "amount": cf.amount()
} for cf in map(ql.as_floating_rate_coupon, swap.leg(1))])

enter image description here

0 votos

Gracias por la respuesta tan detallada. Probablemente utilizaré el swap no estándar ya que casi todos los swaps que evaluaría son amortizables y por tanto ya estaré trabajando con arrays. El mapeo del código en el dataframe también es muy útil. Tengo el calendario de pagos, así que puedo utilizarlo y compararlo con el calendario generado por QuantLib.

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