|
From: Aleksis R. <ale...@go...> - 2024-03-18 15:14:26
|
<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div>Thanks for the follow up and the PR, Marcin.</div><div><br></div><div>Look forward to the updated class.</div><div><br></div><div>Aleksis</div><br id="lineBreakAtBeginningOfSignature"><div dir="ltr">Sent from my iPhone</div><div dir="ltr"><br><blockquote type="cite">On Mar 18, 2024, at 10:59, Marcin Rybacki <mry...@gm...> wrote:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="ltr">Hi Aleksis,<div><br></div><div>Thank you for your thorough analysis. You do have a point here and there seems to be a bug in the source code which implies that the curve settlement date should be the same as the instrument settlement date, in order to price the instrument back to par.</div><div><br></div><div>I created a PR that should fix this:<br><a href="https://github.com/lballabio/QuantLib/pull/1930">https://github.com/lballabio/QuantLib/pull/1930</a><br></div><div><br></div><div>Kind regards,</div><div>Marcin</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, 2 Mar 2024 at 19:00, Aleksis Ali Raza <<a href="mailto:ale...@go...">ale...@go...</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>Thanks for reply Marcin. <div><br></div><div>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).</div><div><br></div><div><div style="background-color:rgb(30,31,34);color:rgb(188,190,196)"><pre style="font-family:"JetBrains Mono",monospace;font-size:9pt"><span style="color:rgb(207,142,109)">import </span>QuantLib <span style="color:rgb(207,142,109)">as </span>ql<br><br>today = ql.Date(<span style="color:rgb(42,172,184)">27</span>, ql.October, <span style="color:rgb(42,172,184)">2021</span>)<br>ql.Settings.instance().evaluationDate = today<br><br>calendar = ql.UnitedStates(ql.UnitedStates.FederalReserve)<br>euribor3M_curve = ql.YieldTermStructureHandle(ql.FlatForward(<span style="color:rgb(42,172,184)">0</span>,calendar,<span style="color:rgb(42,172,184)">0.06</span>,ql.Actual360()))<br>euribor3M = ql.IborIndex(<span style="color:rgb(106,171,115)">'c'</span>, ql.Period(<span style="color:rgb(106,171,115)">'3m'</span>), <span style="color:rgb(42,172,184)">2</span>, ql.Currency(), ql.TARGET(),<br> ql.ModifiedFollowing, <span style="color:rgb(207,142,109)">False</span>, ql.Actual365Fixed(),euribor3M_curve)<br>usdlibor3M_curve = ql.YieldTermStructureHandle(ql.FlatForward(<span style="color:rgb(42,172,184)">0</span>,calendar,<span style="color:rgb(42,172,184)">0.02</span>,ql.Actual365Fixed()))<br>usdlibor3M = ql.IborIndex(<span style="color:rgb(106,171,115)">'c'</span>, ql.Period(<span style="color:rgb(106,171,115)">'3m'</span>), <span style="color:rgb(42,172,184)">2</span>, ql.Currency(), calendar,<br> ql.ModifiedFollowing, <span style="color:rgb(207,142,109)">False</span>, ql.Actual360(),usdlibor3M_curve)<br>notional = <span style="color:rgb(42,172,184)">1_000_000<br></span>fx_0 = <span style="color:rgb(42,172,184)">0.85<br></span>start_date = calendar.advance(today, ql.Period(<span style="color:rgb(42,172,184)">2</span>, ql.Days))<br>end_date = calendar.advance(start_date, ql.Period(<span style="color:rgb(42,172,184)">3</span>, ql.Months))<br>tenor = ql.Period(<span style="color:rgb(42,172,184)">3</span>, ql.Months)<br>rule = ql.DateGeneration.Forward<br>convention = ql.Following<br>end_of_month = <span style="color:rgb(207,142,109)">False<br></span>schedule = ql.Schedule(start_date,end_date,tenor,calendar,convention,convention,rule,end_of_month)<br>usd_leg = ((ql.SimpleCashFlow(-notional, schedule[<span style="color:rgb(42,172,184)">0</span>]),)+ ql.IborLeg(<span style="color:rgb(170,73,38)">nominals</span>=[notional],<span style="color:rgb(170,73,38)">schedule</span>=schedule,<span style="color:rgb(170,73,38)">index</span>=usdlibor3M,)<br> + (ql.SimpleCashFlow(notional, schedule[-<span style="color:rgb(42,172,184)">1</span>]),))<br>usd_npv = ql.CashFlows.npv(usd_leg, usdlibor3M_curve, <span style="color:rgb(207,142,109)">True</span>,start_date)<br><span style="color:rgb(136,136,198)">print</span>(usd_npv)<br>quote = -<span style="color:rgb(42,172,184)">0.03<br></span>ccbs_quotes = {<span style="color:rgb(106,171,115)">'3M'</span>: quote}<br>day_counter = euribor3M_curve.dayCounter()<br>ccbs_helpers = [ql.ConstNotionalCrossCurrencyBasisSwapRateHelper(<br> ql.QuoteHandle(ql.SimpleQuote(value)),<br> ql.Period(period),<br> <span style="color:rgb(42,172,184)">2</span>,<br> calendar,<br> convention,<br> end_of_month,<br> usdlibor3M,<br> euribor3M,<br> usdlibor3M_curve,<br> <span style="color:rgb(207,142,109)">True</span>,<br> <span style="color:rgb(207,142,109)">False</span>)<br> <span style="color:rgb(207,142,109)">for </span>period, value <span style="color:rgb(207,142,109)">in </span>ccbs_quotes.items()]<br><br>eur_usd_curve = ql.YieldTermStructureHandle(ql.PiecewiseLogLinearDiscount(<span style="color:rgb(42,172,184)">0</span>, calendar, ccbs_helpers, day_counter))<br>eur_leg = ((ql.SimpleCashFlow(-notional * fx_0, schedule[<span style="color:rgb(42,172,184)">0</span>]),)+ ql.IborLeg(<span style="color:rgb(170,73,38)">nominals</span>=[notional * fx_0],<span style="color:rgb(170,73,38)">schedule</span>=schedule,<span style="color:rgb(170,73,38)">index</span>=euribor3M,<span style="color:rgb(170,73,38)">spreads</span>=[quote])<br> + (ql.SimpleCashFlow(notional * fx_0, schedule[-<span style="color:rgb(42,172,184)">1</span>]),))<br>eur_npv = ql.CashFlows.npv(eur_leg,eur_usd_curve, <span style="color:rgb(207,142,109)">True</span>,start_date)<br><span style="color:rgb(136,136,198)">print</span>(eur_npv)<br>eur_leg_euribor = ((ql.SimpleCashFlow(-notional * fx_0, schedule[<span style="color:rgb(42,172,184)">0</span>]),)+ ql.IborLeg(<span style="color:rgb(170,73,38)">nominals</span>=[notional * fx_0],<span style="color:rgb(170,73,38)">schedule</span>=schedule,<span style="color:rgb(170,73,38)">index</span>=euribor3M,<span style="color:rgb(170,73,38)">spreads</span>=[<span style="color:rgb(42,172,184)">0</span>])<br> + (ql.SimpleCashFlow(notional * fx_0, schedule[-<span style="color:rgb(42,172,184)">1</span>]),))<br>eur_npv_euribor = ql.CashFlows.npv(eur_leg_euribor,euribor3M_curve, <span style="color:rgb(207,142,109)">True</span>,start_date)<br><span style="color:rgb(136,136,198)">print</span>(eur_npv_euribor)<br><br><span style="color:rgb(136,136,198)">print</span>(ccbs_helpers[<span style="color:rgb(42,172,184)">0</span>].impliedQuote())</pre></div></div><div><div><br></div><div><div><blockquote type="cite"><div>On Mar 2, 2024, at 9:33 AM, Marcin Rybacki <<a href="mailto:mry...@gm..." target="_blank">mry...@gm...</a>> wrote:</div><br><div><div dir="auto">Hi Aleksis,</div><div dir="auto"><br></div><div dir="auto">The curve origin (curve settlement date) does not necessarily need to correspond to the settlement convention of the instruments used to construct the curve.</div><div dir="auto">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.</div><div dir="auto"><br></div><div dir="auto">I hope this answers your question.</div><div dir="auto"><br></div><div dir="auto">Kind regards,</div><div dir="auto">Marcin</div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 28 Feb 2024 at 14:05, Aleksis Ali Raza via QuantLib-users <<a href="mailto:qua...@li..." target="_blank">qua...@li...</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>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 <b>curve settlement date</b> (curve_sett in the code below ) as T+2<b>. </b>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.<div><div><br></div><div>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)?</div><div><div><br></div><div>Thanks, Aleksis</div><div><br></div><div><div style="background-color:rgb(30,31,34);color:rgb(188,190,196)"><pre style="font-family:"JetBrains Mono",monospace;font-size:9pt"><span style="color:rgb(234,9,70);font-style:italic"># FX swaps<br></span>fxSwapHelpers = [ql.FxSwapRateHelper(ql.QuoteHandle(q),<br> ql.QuoteHandle(FX),<br> m,<br> <span style="color:rgb(136,136,198)">int</span>(d),<br> calendar,<br> business_convention_base,<br> end_of_month,<br> <span style="color:rgb(207,142,109)">True</span>,<br> collateral_curve)<br> <span style="color:rgb(207,142,109)">for </span>d, q, m <span style="color:rgb(207,142,109)">in </span><span style="color:rgb(136,136,198)">zip</span>(dffxswapsFXspotlag, fxswap_quotes, dffxswapsmaturity)]<br><br><span style="color:rgb(234,9,70);font-style:italic"># xccy basis curve<br></span>swap_helpers_xccybasis = [ql.ConstNotionalCrossCurrencyBasisSwapRateHelper(ql.QuoteHandle(q),<br> m,<br> <span style="color:rgb(136,136,198)">int</span>(d),<br> calendar,<br> business_convention_quote,<br> end_of_month,<br> index_base,<br> index_quote,<br> collateral_curve,<br> <span style="color:rgb(207,142,109)">True</span>,<br> <span style="color:rgb(207,142,109)">False</span>)<br> <span style="color:rgb(207,142,109)">for </span>q, m, d <span style="color:rgb(207,142,109)">in </span><span style="color:rgb(136,136,198)">zip</span>(xccybasisquotes, xccybasismaturies, dfxccybasisFXspotlag)]<br><br>rate_helpers_xccybasis = fxSwapHelpers + swap_helpers_xccybasis<br>curve_basis = curve_interpolation(curve_sett, calendar, rate_helpers_xccybasis, curve_daycount)<br>curve_basis.enableExtrapolation()<br>final_curve_basis = ql.RelinkableYieldTermStructureHandle(curve_basis)</pre></div><div><br></div></div></div></div></div>_______________________________________________<br> QuantLib-users mailing list<br> <a href="mailto:Qua...@li..." target="_blank">Qua...@li...</a><br> <a href="https://lists.sourceforge.net/lists/listinfo/quantlib-users" rel="noreferrer" target="_blank">https://lists.sourceforge.net/lists/listinfo/quantlib-users</a><br> </blockquote></div></div> </div></blockquote></div><br></div></div></div></blockquote></div> </div></blockquote></body></html> |