1 votos

Quantlib - discrepancia con BBG Swap

Estoy tratando de cotizar un swap en CZK a través de Quantlib con datos de BBG, hasta ahora nada complicado pero parece que no puedo igualar los flujos de efectivo de la pata flotante, y el NPV, cuando cotizo mis swaps, incluso si encuentro la tasa Par correcta.

Estoy tratando de realizar el bootstrapping de la curva CZK creando iborindex y luego ayudantes de Depo / FRA / Swap RateHelper

entonces primero creo el índice,

index_ql= ql.IborIndex('PRIBOR6M',ql.Period('6M'),2,ql.CZKCurrency(),ql.CzechRepublic(),ql.ModifiedFollowing,False,
                              ql.Actual360())

luego creo ayudantes y agrego los datos de Depo/FRA y swap. Tenga en cuenta que df_mapping es solo un df que tiene los datos en bruto (los publicaré más tarde)

helpers = []
for index,row in df_mapping.iterrows():
    if row['Type'] == 'Depo':
        rate_ql = ql.QuoteHandle(ql.SimpleQuote(row['Level']/100))
        helpers.append(ql.DepositRateHelper(rate_ql,index_ql))
    elif row['Type'] == 'FRA':
        month_to_start = row['FRAstart']
        month_end = row['FRAend']
        rate_ql = ql.QuoteHandle(ql.SimpleQuote(row['Level']/100))
        #helpers.append(ql.FraRateHelper(rate_ql,int(month_to_start),index_ql))
        helpers.append(ql.FraRateHelper(rate_ql,int(month_to_start),index_ql))
    elif row['Type'] == 'swap':
        rate_ql = ql.QuoteHandle(ql.SimpleQuote(row['Level']/100))
        helpers.append(ql.SwapRateHelper(rate_ql,ql.Period(index),calendar_ql,fixed_paymentFrequency_ql,paymentconvention_ql_fixed,fixed_daycount_ql,index_ql))

entonces creo la curva / yts / enlace de índice / motor etc ...

curve_ql = ql.PiecewiseLogLinearDiscount(date_ql,helpers,fixed_daycount_ql)

yts = ql.RelinkableYieldTermStructureHandle(curve_ql)

# Enlazar índice a la curva de descuento
index_ql = index_ql.clone(yts)   
engine = ql.DiscountingSwapEngine(yts)

una vez que está creado, simplemente creo un swap simple con vencimiento a 10 años y cupón inicial del 4%

new_swap = ql.MakeVanillaSwap(ql.Period('10Y'), index_ql, 
0.04, ql.Period('0D'), swapType=ql.VanillaSwap.Receiver,pricingEngine=engine,
                            Nominal=10e6,fixedLegTenor=ql.Period('1Y'),fixedLegDayCount=fixed_daycount_ql)

con los mismos datos, encuentro un NPV = -471426 vs BBG -476585, igualo las fechas / flujos de efectivo en la pata fija, pero no igualo la tasa reset y los importes de la pata flotante (pero aún así igualo las fechas)

mi pata flotante (no descontada)

pata flotante quantlib

Pata flotante de BBG (ver columna de pagos)

pata flotante BBG

¿Puede darme algún consejo? Creo que el problema está en algún lugar en el cálculo de la tasa forward, que no parece coincidir, pero no tengo idea de por qué. Intenté cambiar el método de interpolación pero no cambia mucho.

Mire a continuación los datos en bruto, por favor avíseme si tiene alguna pregunta, gracias de nuevo por toda su ayuda, datos en bruto

1voto

dotnetcoder Puntos 1262

Por lo que vale, valoré esto en mi propia biblioteca y obtuve un VPN de -471.275, valorado al 2 de octubre de 2023.

No tengo un calendario de vacaciones checo y asumí que la convención de los swaps es Anual Act360 vs Semi Act360.

from rateslib import *

curva = Curve(
    nodes={
        dt(2023, 10, 2): 1.0, dt(2024, 4, 4): 1.0, dt(2024, 5, 4): 1.0,
        dt(2024, 6, 4): 1.0, dt(2024, 7, 4): 1.0, dt(2024, 8, 4): 1.0,
        dt(2024, 9, 4): 1.0, dt(2024, 10, 4): 1.0, dt(2025, 4, 4): 1.0,
        dt(2025, 10, 4): 1.0, dt(2026, 10, 4): 1.0, dt(2027, 10, 4): 1.0,
        dt(2028, 10, 4): 1.0, dt(2029, 10, 4): 1.0, dt(2030, 10, 4): 1.0,
        dt(2031, 10, 4): 1.0, dt(2032, 10, 4): 1.0, dt(2033, 10, 4): 1.0,
        dt(2035, 10, 4): 1.0, dt(2038, 10, 4): 1.0,
    },
    calendar="tgt",
    convention="act360",
    id="crv",
)

args = dict(curves="crv", frequency="S", termination="6m", calendar="tgt")
args2 = dict(
    curves="crv", 
    frequency="A", calendar="tgt", convention="Act360",
    leg2_frequency="S", leg2_convention="act360", leg2_fixing_method="ibor",
)
solver = Solver(
    curves=[curva],
    instruments=[
        FRA(dt(2023, 10, 4), **args),
        FRA(dt(2023, 11, 4), **args),
        FRA(dt(2023, 12, 4), **args),
        FRA(dt(2024, 1, 4), **args),
        FRA(dt(2024, 2, 4), **args),
        FRA(dt(2024, 3, 4), **args),
        FRA(dt(2024, 4, 4), **args),
        FRA(dt(2024, 10, 4), **args),
        IRS(dt(2023, 10, 4), "2y", **args2),
        IRS(dt(2023, 10, 4), "3y", **args2),
        IRS(dt(2023, 10, 4), "4y", **args2),
        IRS(dt(2023, 10, 4), "5y", **args2),
        IRS(dt(2023, 10, 4), "6y", **args2),
        IRS(dt(2023, 10, 4), "7y", **args2),
        IRS(dt(2023, 10, 4), "8y", **args2),
        IRS(dt(2023, 10, 4), "9y", **args2),
        IRS(dt(2023, 10, 4), "10y", **args2),
        IRS(dt(2023, 10, 4), "12y", **args2),
        IRS(dt(2023, 10, 4), "15y", **args2),
    ],
    s=[
        7.01, 6.955, 6.805, 6.52, 6.365, 5.988,
        5.605, 4.268, 5.355, 4.9625, 4.7853, 4.69,
        4.64068, 4.6125, 4.60105, 4.59690, 4.59501,
        4.5750, 4.56
    ],
)

Y el IRS:

irs = IRS(dt(2023, 10, 4), "10Y", notional=-10e6, fixed_rate=4.0, **args2)
irs.npv(solver=solver)
# -471,275.78
irs.cashflows(solver=solver)

introducir descripción de la imagen aquí

Finanhelp.com

FinanHelp es una comunidad para personas con conocimientos de economía y finanzas, o quiere aprender. Puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X