Tengo el siguiente código para poner precio a un suelo (también puede usarse para un cap), y he estado calculando el pago yo mismo, pero creo que QL ya puede hacer esto. Dado que los flujos de efectivo que imprimo no son correctos, ya que no tienen en cuenta el plazo (aquí, solo tengo derecho a 6 meses del nominal pero los flujos de efectivo asumen 1 año), así que quiero obtener el VPN, el valor intrínseco y el valor temporal de cada caplet/floorlet si es posible utilizando funciones de QL desde el motor de precios de cap. He buscado y no logro encontrar una forma de hacer esto.
...
ibor_leg = ql.IborLeg([Nominal], schedule, ibor_index)
# usar ql.Floor para suelo
if Instrumento == 'Cap':
capfloor = ql.Cap(ibor_leg, [strike])
elif Instrumento == 'Suelo':
capfloor = ql.Floor(ibor_leg, [strike])
vols = ql.QuoteHandle(ql.SimpleQuote(volatilidad))
engine = ql.BlackCapFloorEngine(ts_handle, vols)
capfloor.setPricingEngine(engine)
print("Precio:", "${:,.2f}".format(capfloor.NPV()))
# imprimir tabla de flujos de efectivo para comparar con la referencia
# Calcular los flujos de efectivo y los flujos de efectivo descontados para cada caplet
flujos_de_efectivo = capfloor.floatingLeg()
valor_intrinseco = capfloor.NPV()
factores_de_descuento = [term_structure.discount(flujos_de_efectivo.date()) for cashflow in cashflows]
flujos_de_efectivo_descontados = [flujos_de_efectivo.amount() * factor_de_descuento for cashflow,
factor_de_descuento in zip(flujos_de_efectivo,
factores_de_descuento)]
def Pago(tipo_de_opcion, Nominal, F, K, frac_years, tasa_descuento):
if tipo_de_opcion=="Cap":
return max(0, F-K)*Nominal*frac_years*tasa_descuento
elif tipo_de_opcion == "Suelo":
return max(0, K-F)*Nominal*frac_years*tasa_descuento
# Construir los datos de la tabla
# Imprimir el VPN, el valor intrínseco y el valor temporal para cada caplet/suelo en cada fecha de fijación
datos_tabla = []
for i in range(len(calendario)-1):
periodo_inicio = calendario[i]
periodo_fin = calendario[i+1]
periodo = f"{periodo_inicio} - {periodo_fin}"
tasa_descuento = term_structure.zeroRate(periodo_fin, day_count,compounding,compounding_frequency).rate()
tasa_spot = ibor_index.fixing(periodo_inicio)
tasa_forward = term_structure.forwardRate(periodo_inicio, periodo_fin,
day_count,
compounding,
compounding_frequency).rate()
flujo_efectivo = flujos_de_efectivo[i].amount()
factor_de_descuento = factores_de_descuento[i]
frac_years = ql.Actual360().yearFraction(periodo_inicio, periodo_fin)
if Instrumento=='Cap':
valor_intrinseco = Pago('Cap',Nominal,tasa_spot,strike,frac_years,factor_de_descuento)
elif Instrumento == 'Suelo':
valor_intrinseco = Pago('Suelo',Nominal,tasa_spot,strike,frac_years,factor_de_descuento)
flujo_descontado = flujos_de_efectivo_descontados[i]
datos_tabla.append([periodo_inicio.ISO(), periodo_fin.ISO(), tasa_descuento,
tasa_forward, tasa_spot,
"{:,.2f}".format(flujo_efectivo),
factor_de_descuento,
"{:,.2f}".format(flujo_descontado),"{:,.2f}".format(valor_intrinseco) ])
# Imprimir la tabla usando tabulate
encabezados = ["Inicio de Periodo", "Fin de Periodo", "Tasa de Descuento", "Tasa Forward",
"Tasa Spot", "Flujo de Efectivo", "Factor de Descuento", "Flujo de Efectivo Descontado","Valor","Valor Intrínseco", "Valor Temporal"]
print(tabulate(datos_tabla, headers=encabezados))