Actualmente estoy trabajando en la construcción de una curva de rendimiento utilizando swaps OIS. Sin embargo, estoy encontrando un problema con la fecha de inicio del flujo de caja que estoy luchando por entender. Aquí está una versión simplificada de mi código:
Ejemplo reproducible
import QuantLib as ql
calculation_date = ql.Date().todaysDate() #When I posted this on Quant exchange the date was 25/5/2023
ql.Settings.instance().evaluationDate = calculation_date
index = ql.OvernightIndex("USD Overnight Index", 2, ql.USDCurrency(), ql.UnitedStates(ql.UnitedStates.Settlement), ql.Actual360())
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)
yts = ql.RelinkableYieldTermStructureHandle()
curve = ql.PiecewiseSplineCubicDiscount(calculation_date, rate_helpers, ql.Actual360())
yts.linkTo(curve)
index = index.clone(yts)
engine = ql.DiscountingSwapEngine(yts)
print("maturity | market | model")
for tenor, rate in swaps.items():
schedule = ql.Schedule(calculation_date,
calculation_date + tenor,
ql.Period('1D'),
ql.UnitedStates(ql.UnitedStates.GovernmentBond),
ql.ModifiedFollowing,
ql.ModifiedFollowing,
ql.DateGeneration.Forward,
False)
swap = ql.OvernightIndexedSwap(ql.OvernightIndexedSwap.Payer,
1.0,
schedule,
0.01,
ql.Actual360(),
index)
swap.setPricingEngine(engine)
print(f" {tenor} | {rate:.6f} | {swap.fairRate():.6f}")
El problema al que me enfrento es que la fecha de inicio del flujo de caja de los swaps aparece dos días antes de la fecha de evaluación (23 de mayo de 2023 y fecha de evaluación 25 de mayo de 2023), lo que no se ajusta a mis expectativas. He establecido la fecha de evaluación como la fecha actual en mi código, por lo que la fecha de inicio del flujo de caja debería estar en la fecha de evaluación o después de ella.
File "AAA", line 173, in build_curve_v2 print(f" {tenor} | {rate:.6f} | {swap.fairRate():.6f}") ^^^^^^^^^^^^^^^ File "AAA", line 12, in <module> bootstrap.Curve_Build() RuntimeError: 2nd leg: Missing USD Overnight IndexSN Actual/360 fixing for May 23rd, 2023
Sospecho que puede haber algún error en mi método de bootstrapping o en la forma en que construyo la curva de rendimiento. Cualquier orientación o sugerencia sobre cómo resolver este problema sería muy apreciada.
Una posible explicación : Cuando un OvernightIndexedSwap
se crea el calendario del tramo flotante, cuya primera fecha es T+2 días antes del inicio del swap, siendo T el inicio del swap. En mi caso, si el swap comienza en la fecha de evaluación del 25 de mayo de 2023, el calendario del tramo flotante comenzará el 23 de mayo de 2023. En consecuencia, es necesario fijar el tipo a un día el 23 de mayo de 2023.