"La respuesta corta es que la frecuencia de los pagos flotantes está determinada por la Programación
de un IborIndex
(o OvernightIndex
). Por lo tanto, si definimos lo siguiente
ibor_index= ql.IborIndex(
"MyIndex",
ql.Period("1Y"),
0,
ql.SEKCurrency(),
ql.Sweden(),
ql.ModifiedFollowing,
False,
ql.Actual360(),
ts_handle,
)
Se puede interpretar que los cupones del ZeroCouponSwap
tendrán una frecuencia de 1Y, es decir, cada día de pago de cupón ocurrirá 1Y entre ellos.
Si consideramos una respuesta más detallada. Entonces encontré la definición de ZeroCouponSwap
muy útil al investigar esta clase en particular. Además, supongamos que queremos replicar la siguiente cantidad de este particular ZeroCouponSwap
para comprender completamente cómo se valora la pierna flotante de ZeroCouponSwap
:
import QuantLib as ql
import pandas as pd
# Establecer la fecha de referencia
ref_date = ql.Date(1, 1, 2022)
ql.Settings.instance().evaluationDate = ql.Date(1, 1, 2022)
dfs = [1, 0.965, 0.94] # factores de descuento
fechas = [
ql.Date(1, 1, 2022),
ql.Date(1, 1, 2023),
ql.Date(1, 1, 2025),
] # fechas de vencimiento de los factores de descuento
day_counter = ql.Actual360()
# Crear la curva de descuento
curva = ql.DiscountCurve(fechas, dfs, day_counter)
# La curva no estará vinculada en caso de que deseemos actualizar las comillas más adelante
ts_handle = ql.YieldTermStructureHandle(curva)
custom_index= ql.IborIndex(
"MyIndex",
ql.Period("1Y"),
0,
ql.SEKCurrency(),
ql.Sweden(),
ql.ModifiedFollowing,
False,
ql.Actual360(),
ts_handle,
)
start_date= ql.Date(1,1,2022)
end_date = ql.Date(1,1,2024)
nominal= 10e6
swap = ql.ZeroCouponSwap(
ql.Swap.Payer,
nominal,
start_date,
end_date,
0.02,
day_counter,
custom_index,
ql.Sweden(),
)
engine = ql.DiscountingSwapEngine(ts_handle)
swap.setPricingEngine(engine)
pd.DataFrame([{
'fechaFijacion': cf.fixingDate().ISO(),
'inicioAcumulación': cf.accrualStartDate().ISO(),
'finAcumulación': cf.accrualEndDate().ISO(),
'periodoAcumulación': cf.accrualPeriod(),
"fechaPago": cf.date().ISO(),
'forward': cf.indexFixing(),
'tasa': cf.rate(),
"cantidad": cf.amount(),
} for cf in map(ql.as_floating_rate_coupon, swap.leg(1))])
El código anterior producirá los siguientes valores:
fechaFijacion
inicioAcumulación
finAcumulación
periodoAcumulación
fechaPago
forward
tasa
cantidad
2023-06-05
2022-02-03
2024-06-03
2.363888889
2024-06-03
0.0130119
0.021911
517947.6
Luego, en referencia al enlace mencionado anteriormente, la tasa flotante de los cupones para ZeroCouponSwap
se calcula mediante:
$$R^{FLT} = \left[ \prod_{k=0}^{K-1} (1+\alpha(T_{k},T_{k+1}) L(T_{k},T_{k+1})) -1 \right]$$
Por lo tanto, nuestro objetivo es identificar los atributos que QuantLib utiliza para calcular el monto de la tasa flotante. Sin embargo, al inspeccionar el código fuente de QuantLib, se observará que la pierna flotante de ZeroCouponSwap consta simplemente de SubPeriodsCoupon. Para simplificar este proceso, podemos usar el siguiente código para determinar los atributos exactos que se emplean (ya que entendí que los pagos de cupones flotantes no se encuentran en la clase original ZeroCouponSwap
):
import QuantLib as ql
import pandas as pd
# Establecer la fecha de referencia
ql.Settings.instance().evaluationDate = ql.Date(1, 1, 2022)
dfs = [1, 0.965, 0.94] # factores de descuento
fechas = [
ql.Date(1, 1, 2022),
ql.Date(1, 1, 2023),
ql.Date(1, 1, 2025),
] # fechas de vencimiento de los factores de descuento
day_counter = ql.Actual360()
# Crear la curva de descuento
curva = ql.DiscountCurve(fechas, dfs, day_counter)
# La curva no estará vinculada en caso de que deseemos actualizar las comillas más adelante
ts_handle = ql.YieldTermStructureHandle(curva)
custom_index= ql.IborIndex(
"MyIndex",
ql.Period("1Y"),
0,
ql.SEKCurrency(),
ql.Sweden(),
ql.ModifiedFollowing,
False,
ql.Actual360(),
ts_handle,
)
start_date= ql.Date(1,1,2022)
end_date = ql.Date(1,1,2024)
cupon = ql.SubPeriodsCoupon(ql.Date(3,6,2024), 1e7, start_date, end_date, 0, custom_index)
cupon.setPricer(ql.CompoundingRatePricer())
print(f'{cupon.amount() = }')
Esto nos dará el mismo monto que ZeroCouponSwap
. Por lo tanto, dado la ecuación que se encontró en la documentación, llegamos a
fechas_fijacion_cupon = cupon.fixingDates()
fijaciones_sub_periodos = []
for fecha_fijacion in fechas_fijacion_cupon:
fijaciones_sub_periodos.append(custom_index.fixing(fecha_fijacion))
fracciones_sub_periodos = cupon.dt()
factor_compuesto = 1
for fijacion, frac in zip(fijaciones_sub_periodos, fracciones_sub_periodos):
factor_compuesto *= 1+fijacion * frac
tasa = ((factor_compuesto-1) / cupon.accrualPeriod())
Lo cual produce el número 0.021910825388354933. Este es el número que se utiliza para obtener el monto de la pierna flotante. Al multiplicar este valor por $10^6$ y accrualPeriod
llegamos al monto exacto.
Espero que la forma más eficiente de ver los días de pago de cupones sea usando coupon.valueDates()
que se crea con ql.MakeSchedule
utilizando start_date
, end_date
y ql.Period
para ver los flujos de efectivo de la pierna flotante.
0 votos
Relacionados: quant.stackexchange.com/questions/65559 y quant.stackexchange.com/questions/77369
0 votos
@DimitriVulis Gracias por responder. Pero mi publicación es específica para la configuración y ajustes del swap sin cupón BRL. Déjame saber tus pensamientos sobre mi publicación.