He estado utilizando QuantLib para construir una curva de rendimiento y fijar el precio de un bono. Me pregunto si estoy utilizando el método correcto para crear mi estructura de plazos de rendimiento ( yts
) para el proceso de fijación de precios.
Este es el ejemplo reproducible :
import QuantLib as ql
import math
calculation_date = ql.Date().todaysDate()
ql.Settings.instance().evaluationDate = calculation_date
yts = ql.RelinkableYieldTermStructureHandle()
index = ql.OvernightIndex("USD Overnight Index", 0, ql.USDCurrency(), ql.UnitedStates(ql.UnitedStates.Settlement), ql.Actual360(),yts)
swaps = {
ql.Period("1W"): 0.05064,
ql.Period("2W"): 0.05067,
ql.Period("3W"): 0.05072,
ql.Period("1M"): 0.051021000000000004,
ql.Period("2M"): 0.051391,
ql.Period("3M"): 0.051745,
ql.Period("4M"): 0.05194,
ql.Period("5M"): 0.051980000000000005,
ql.Period("6M"): 0.051820000000000005,
ql.Period("7M"): 0.051584000000000005,
ql.Period("8M"): 0.05131,
ql.Period("9M"): 0.050924,
ql.Period("10M"): 0.050603999999999996,
ql.Period("11M"): 0.050121,
ql.Period("12M"): 0.049550000000000004,
ql.Period("18M"): 0.04558500000000001,
ql.Period("2Y"): 0.042630999999999995,
ql.Period("3Y"): 0.038952,
ql.Period("4Y"): 0.036976,
ql.Period("5Y"): 0.035919,
ql.Period("6Y"): 0.03535,
ql.Period("7Y"): 0.034998,
ql.Period("8Y"): 0.034808,
ql.Period("9Y"): 0.034738000000000005,
ql.Period("10Y"): 0.034712,
ql.Period("12Y"): 0.034801,
ql.Period("15Y"): 0.034923,
ql.Period("20Y"): 0.034662,
ql.Period("25Y"): 0.03375,
ql.Period("30Y"): 0.032826,
ql.Period("40Y"): 0.030834999999999998,
ql.Period("50Y"): 0.02896
}
rate_helpers = []
for tenor, rate in swaps.items():
helper = ql.OISRateHelper(2, tenor, ql.QuoteHandle(ql.SimpleQuote(rate)), index)
rate_helpers.append(helper)
curve = ql.PiecewiseFlatForward(calculation_date, rate_helpers, ql.Actual360())
yts.linkTo(curve)
index = index.clone(yts)
engine = ql.DiscountingSwapEngine(yts)
print("maturity | market | model | zero rate | discount factor | present value")
for tenor, rate in swaps.items():
ois_swap = ql.MakeOIS(tenor, index, rate)
pv = ois_swap.NPV()
fair_rate = ois_swap.fairRate()
maturity_date = ois_swap.maturityDate()
discount_factor = curve.discount(maturity_date)
zero_rate = curve.zeroRate(maturity_date, ql.Actual365Fixed() , ql.Continuous).rate()
print(f" {tenor} | {rate*100:.6f} | {fair_rate*100:.6f} | {zero_rate*100:.6f} | {discount_factor:.6f} | {pv:.6f}")
issue_date = ql.Date(12,1,2022)
maturity_date = ql.Date(12,1,2027)
coupon_frequency = ql.Period(ql.Semiannual)
calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond)
date_generation = ql.DateGeneration.Backward
coupon_rate = 4.550000/100
day_count = ql.Thirty360(ql.Thirty360.USA)
spread = ql.SimpleQuote(89.965 / 10000.0)
schedule = ql.Schedule( issue_date,
maturity_date,
coupon_frequency,
calendar,
ql.Unadjusted,
ql.Unadjusted,
date_generation,
False)
bond = ql.FixedRateBond(2, 100, schedule, [coupon_rate], day_count)
spread_handle = ql.QuoteHandle(spread)
spreaded_curve = ql.ZeroSpreadedTermStructure(yts, spread_handle)
spreaded_curve_handle = ql.YieldTermStructureHandle(spreaded_curve)
bond.setPricingEngine(ql.DiscountingBondEngine(spreaded_curve_handle))
print(f"NPV {bond.NPV()} vs dirty price {bond.dirtyPrice()} - clean price {bond.cleanPrice()}")
Utilizo la estructura temporal de rendimientos ( yts
) vinculada a la curva ( curve
) construido utilizando ql.PiecewiseFlatForward
.
Me pregunto si es correcto utilizar la yts que enlaza con la curva a plazo para fijar el precio del bono.
O, ¿necesito construir una curva de cupón cero para la fijación de precios? En caso afirmativo, ¿cómo puedo construir y utilizar esta curva de cupón cero?
He observado que QuantLib permite la conversión de tipos a plazo a tipos cero utilizando la función zeroRate()
función. ¿Es suficiente esta función para obtener los tipos cupón cero correctos a partir de los tipos a plazo para la fijación del precio de los bonos, o es necesaria una construcción más explícita de una curva cupón cero?
Agradecería cualquier orientación o ejemplo. Gracias.