|
From: Aleksis A. R. <ale...@go...> - 2024-03-02 18:30:44
|
Thanks for reply Marcin.
Agreed, but unfortunately the only way I can get the xccy swaps to price to par is by having a curve settlement set to 2 and PVing the cashflows to the sett’t date. I’ve spent some on this but can’t find a work around. Below is a toy example illustrating this problem (a copy/paste will run it). The only way I get a zero npv for the xccy swap is by having a curve sett of T+2 in all curves (euribor3M_curve, usdlibor3M_curve and eur_usd_curve).
import QuantLib as ql
today = ql.Date(27, ql.October, 2021)
ql.Settings.instance().evaluationDate = today
calendar = ql.UnitedStates(ql.UnitedStates.FederalReserve)
euribor3M_curve = ql.YieldTermStructureHandle(ql.FlatForward(0,calendar,0.06,ql.Actual360()))
euribor3M = ql.IborIndex('c', ql.Period('3m'), 2, ql.Currency(), ql.TARGET(),
ql.ModifiedFollowing, False, ql.Actual365Fixed(),euribor3M_curve)
usdlibor3M_curve = ql.YieldTermStructureHandle(ql.FlatForward(0,calendar,0.02,ql.Actual365Fixed()))
usdlibor3M = ql.IborIndex('c', ql.Period('3m'), 2, ql.Currency(), calendar,
ql.ModifiedFollowing, False, ql.Actual360(),usdlibor3M_curve)
notional = 1_000_000
fx_0 = 0.85
start_date = calendar.advance(today, ql.Period(2, ql.Days))
end_date = calendar.advance(start_date, ql.Period(3, ql.Months))
tenor = ql.Period(3, ql.Months)
rule = ql.DateGeneration.Forward
convention = ql.Following
end_of_month = False
schedule = ql.Schedule(start_date,end_date,tenor,calendar,convention,convention,rule,end_of_month)
usd_leg = ((ql.SimpleCashFlow(-notional, schedule[0]),)+ ql.IborLeg(nominals=[notional],schedule=schedule,index=usdlibor3M,)
+ (ql.SimpleCashFlow(notional, schedule[-1]),))
usd_npv = ql.CashFlows.npv(usd_leg, usdlibor3M_curve, True,start_date)
print(usd_npv)
quote = -0.03
ccbs_quotes = {'3M': quote}
day_counter = euribor3M_curve.dayCounter()
ccbs_helpers = [ql.ConstNotionalCrossCurrencyBasisSwapRateHelper(
ql.QuoteHandle(ql.SimpleQuote(value)),
ql.Period(period),
2,
calendar,
convention,
end_of_month,
usdlibor3M,
euribor3M,
usdlibor3M_curve,
True,
False)
for period, value in ccbs_quotes.items()]
eur_usd_curve = ql.YieldTermStructureHandle(ql.PiecewiseLogLinearDiscount(0, calendar, ccbs_helpers, day_counter))
eur_leg = ((ql.SimpleCashFlow(-notional * fx_0, schedule[0]),)+ ql.IborLeg(nominals=[notional * fx_0],schedule=schedule,index=euribor3M,spreads=[quote])
+ (ql.SimpleCashFlow(notional * fx_0, schedule[-1]),))
eur_npv = ql.CashFlows.npv(eur_leg,eur_usd_curve, True,start_date)
print(eur_npv)
eur_leg_euribor = ((ql.SimpleCashFlow(-notional * fx_0, schedule[0]),)+ ql.IborLeg(nominals=[notional * fx_0],schedule=schedule,index=euribor3M,spreads=[0])
+ (ql.SimpleCashFlow(notional * fx_0, schedule[-1]),))
eur_npv_euribor = ql.CashFlows.npv(eur_leg_euribor,euribor3M_curve, True,start_date)
print(eur_npv_euribor)
print(ccbs_helpers[0].impliedQuote())
> On Mar 2, 2024, at 9:33 AM, Marcin Rybacki <mry...@gm...> wrote:
>
> Hi Aleksis,
>
> The curve origin (curve settlement date) does not necessarily need to correspond to the settlement convention of the instruments used to construct the curve.
> So, you can safely set it to T+0 and both FX swaps and cross currency swaps, that you use to build the term structure, should price back to par.
>
> I hope this answers your question.
>
> Kind regards,
> Marcin
>
> On Wed, 28 Feb 2024 at 14:05, Aleksis Ali Raza via QuantLib-users <qua...@li... <mailto:qua...@li...>> wrote:
>> Perhaps this is a naive question but when bootstrapping a cross currency curve using FXSwapHelper for short end and ConstNotionalCrossCurrencyBasisSwapHelper for the long end, I’m running into an issue where I need to specify the curve settlement date (curve_sett in the code below ) as T+2. This is to reflect correct valuation of the cross currency swaps when priced off the curve. However, for FXSwapHelpers curve_sett should be T+0 - this is so that ON and TN FX swaps can be used in the helpers and repriced correctly. The code used is below.
>>
>> How does one get around this issue (without having to work with two separate curves, or without leaving out ON and TN from the FXSwapHelpers)?
>>
>> Thanks, Aleksis
>>
>> # FX swaps
>> fxSwapHelpers = [ql.FxSwapRateHelper(ql.QuoteHandle(q),
>> ql.QuoteHandle(FX),
>> m,
>> int(d),
>> calendar,
>> business_convention_base,
>> end_of_month,
>> True,
>> collateral_curve)
>> for d, q, m in zip(dffxswapsFXspotlag, fxswap_quotes, dffxswapsmaturity)]
>>
>> # xccy basis curve
>> swap_helpers_xccybasis = [ql.ConstNotionalCrossCurrencyBasisSwapRateHelper(ql.QuoteHandle(q),
>> m,
>> int(d),
>> calendar,
>> business_convention_quote,
>> end_of_month,
>> index_base,
>> index_quote,
>> collateral_curve,
>> True,
>> False)
>> for q, m, d in zip(xccybasisquotes, xccybasismaturies, dfxccybasisFXspotlag)]
>>
>> rate_helpers_xccybasis = fxSwapHelpers + swap_helpers_xccybasis
>> curve_basis = curve_interpolation(curve_sett, calendar, rate_helpers_xccybasis, curve_daycount)
>> curve_basis.enableExtrapolation()
>> final_curve_basis = ql.RelinkableYieldTermStructureHandle(curve_basis)
>>
>> _______________________________________________
>> QuantLib-users mailing list
>> Qua...@li... <mailto:Qua...@li...>
>> https://lists.sourceforge.net/lists/listinfo/quantlib-users
|