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.
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.
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))])