From: Stats S. <sta...@gm...> - 2025-07-30 11:23:07
|
Thanks, Luigi. Will do. On Fri, Jul 25, 2025 at 7:04 PM Luigi Ballabio <lui...@gm...> wrote: > Hi—it turns out that the rates coming out of the spreaded curve are not as > expected. If you calculate the original rates from the curve and then add > the spread, as you did in your sample code, you get > > >>> zero_rates = [ handle.zeroRate( l.date(), daycount, ql.Compounded, > ql.Monthly ).rate() for ii,l in enumerate(leg) ] > >>> print([r + zspread for r in zero_rates]) > [0.054693695527939915, 0.05243448138456887] > > while if you extract the same rates from the spreaded curve you get > > >>> print([ zspreaded_handle.zeroRate( l.date(), daycount, ql.Compounded, > ql.Monthly ).rate() for ii,l in enumerate(leg) ]) > [0.05502806821107864, 0.05226732979489501] > > The problem seems to be that the curve and the added spread have two > different day counters (act/360 for the curve and 30/360 for the spread) > and somehow ZeroSpreadedTermStructure fails to account for that. If the > two day counters are the same (either both 30/360 or both act/360) the > problem disappears, which is probably why nobody noticed until now. > > May you open an issue on GitHub so someone can pick it up and analyse it > further? Thanks! > > Luigi > > > > On Tue, Jun 10, 2025 at 6:17 AM Stats Student <sta...@gm...> > wrote: > >> Hi - I have been trying to use the spread from ql.CashFlows.zSpread to >> discount cash flows. I am able to use it in ZeroSpreadedTermStructure and >> get the right numbers. >> But I would like to understand how to replicate the same output by hand. >> The NPV I get is very close, but there is still a small difference which I >> suspect will likely get bigger over longer periods. >> >> Does anyone know what is causing this discrepancy? Thanks in advance. >> >> >> >> zspread: 0.009989751634951987 ( from ql.CashFlows.zSpread ) >> >> >> zSpread / ZeroSpreadedTermStructure npv: 198.6780*623718125 (CORRECT)* >> >> >> zSpread manual npv: 198.6780*7379166345* >> >> >> >> ########################################### >> >> >> import QuantLib as ql >> >> daycount = ql.Thirty360(ql.Thirty360.USA) >> >> start = ql.Date(1, 1, 2025) >> >> ql.Settings.instance().evaluationDate = start >> >> rates = ( ['SOFR1D', 4.3564348072], ['SOFR1W', 4.3493027605], ['SOFR1M', >> 4.3238954677], ['SOFR3M', 4.3084328938], ['SOFR6M', 4.2045895664] ) >> >> sofr_index = ql.Sofr() >> >> ois_helpers = [] >> >> for period, rate in rates: >> tenor = period.replace('SOFR','') >> ois_helpers.append( ql.OISRateHelper(0, >> ql.Period ( tenor ), >> >> ql.QuoteHandle(ql.SimpleQuote(rate/100)), >> sofr_index) ) >> >> curve = ql.PiecewiseLogCubicDiscount( start, ois_helpers, ql.Actual360() ) >> >> handle = ql.YieldTermStructureHandle( curve ) >> >> leg = ql.Leg( [ ql.SimpleCashFlow( 100, ql.Date(1,2,2025) ), >> ql.SimpleCashFlow( 100, ql.Date(1,3,2025) ) ] ) >> >> spreaded_npv = 198.6780623718125 >> >> zspread = ql.CashFlows.zSpread(leg, spreaded_npv, curve, daycount, >> ql.Compounded, ql.Monthly, True) >> >> print(f"zspread: {zspread}") # zspread: 0.009989751634951987 >> >> zspread_quote = ql.SimpleQuote( zspread ) >> >> zspreaded_curve = ql.ZeroSpreadedTermStructure( handle, >> ql.QuoteHandle(zspread_quote), ql.Compounded, ql.Monthly, daycount ) >> >> zspreaded_handle = ql.YieldTermStructureHandle( zspreaded_curve ) >> >> zspreaded_npv = ql.CashFlows.npv(leg, zspreaded_handle, True) >> >> print(f"zSpread ZeroSpreadedTermStructure npv: {zspreaded_npv}") # zSpread >> npv: 198.6780623718125 (MATCH) >> >> zero_rates = [ handle.zeroRate( l.date(), daycount, ql.Compounded, >> ql.Monthly ).rate() for ii,l in enumerate(leg) ] >> >> # zero_rates = [ handle.zeroRate( (ii+1)/12, ql.Compounded, ql.Monthly >> ).rate() for ii,l in enumerate(leg) ] # 198.67814955576728 (BIGGER >> DELTA) >> >> zpread_manual_npv = 100 / (1 + (zero_rates[0] + zspread) / 12) + 100 / ( >> 1 + (zero_rates[1] + zspread) / 12 ) ** 2 >> >> print(f"zSpread manual npv: {zpread_manual_npv}\n") # manual zSpread >> npv: 198.67807379166345 (*NO MATCH*) >> >> >> >> _______________________________________________ >> QuantLib-users mailing list >> Qua...@li... >> https://lists.sourceforge.net/lists/listinfo/quantlib-users >> > |