|
From: Luigi B. <lui...@gm...> - 2023-12-01 16:21:55
|
Yes, CashFlows.npv uses the settle date as you would expect; you can check its implementation at < https://github.com/lballabio/QuantLib/blob/v1.32/ql/cashflows/cashflows.cpp#L425 >. I'm not sure that it's the only way to do it (you might try something by passing the cash flows to the Bond constructors) but it's probably the least complicated. Hope this helps, Luigi On Fri, Dec 1, 2023 at 3:29 PM Philippe Hatstadt < phi...@ex...> wrote: > Thanks Luigi. > Let me provide more color. The exercise above is part of a python unit > test and in fact, what I am testing is that .NPV(settle_date) matches > .dirtyPrice(settle_date). I found an old post on this forum that explains > that .NPV() can only price to ql.Settings.instance().evaluationDate. This > is why I tried setting the latter to settle_date and call .NPV() again but > maybe it also rebuilds my curve and changes things, so that doesn't seem > like a good idea. What I did that made it work was simply to return > .NPV(evaluationDate) / curve.discount(settle_date). Then the values match > perfectly. So far so good. > Now let's go back to why I was writing such a unit test to begin with, > because to your point, use dirtyPrice(settle_date) and be happy. Well not > quite. The instrument I am pricing is a funky GNMA fixed rate amortizing > bond via OAS. As a result, I do not use YieldToMaturity, but instead, for > each OAS path, I must value the cash flows on a curve shifted by a > z-spread, bond_engine = ql.DiscountingBondEngine(curve_handle) and > exos_bond.setPricingEngine(bond_engine) > The amortization It is *not* a standard amortization table like a > conventional mortgage, so we wrote the cash flow model including > involuntary prepay curve but the structure has a 14d payment lag on monthly > cash flows, and the ex-coupon date is the last day of the month. Settle lag > is T+2. In other words, if I buy a bond and it settles on 11/30, I am > buying the entire 11/01-11/30 coupon. On the other hand, if it settles, on > 12/01, I am not, but I have to pay one day of accrued. I am unaware of any > QL bond instrument that can correctly accept arbitrary cash flows and also > accept a 14d settle lag. If one existed, I would instantiate it and attempt > to use .dirtyPrice() although I don't even think that would work since I > need to price on a curve and not use a flat yield to maturity. > > So, my plan is to instead do something like this: > cfs = [ql.SimpleCashFlow(cashflow, d) for d, cashflow in zip(dates, leg) ] > pv = ql.CashFlows.npv(cfs, discountTermStructure, False, settle_date) > and I would need to make sure to generate the ex-coupon date myself when > generating the cash flow vector. > > So I wanted to confirm that the approach above is the only valid one for > this funky instrument to be priced via prepay/OAS on a curve. So can you > confirm that ql.CashFlows.npv) does correctly PV to the settle_date (> > reference date) so that I don't have to do the roll forward manually? I > suppose I can write a unit test for that as well but wanted to know for > sure. > > Philippe Hatstadt > > > On Fri, Dec 1, 2023 at 5:34 AM Luigi Ballabio <lui...@gm...> > wrote: > >> Hello Philippe, >> instead of NPV, use bond.cleanPrice() or bond.dirtyPrice() instead. >> Those two methods take the settlement days into account. >> >> Luigi >> >> >> On Thu, Nov 30, 2023 at 1:24 AM Philippe Hatstadt via QuantLib-users < >> qua...@li...> wrote: >> >>> I am building a ql.YieldTermStructureHandle with US treasury bonds that >>> settle T+1. Since the method is bootystrapping, I expect each bond sued to >>> build the curve to repcie itself 100% accurateIy when pricing any of the >>> bonds used to build the curve on such curve. >>> To test that, I compute the bonds dirty price by first assigning a >>> pricing engine via my_bond.set_pricing_engine_from_curve(curve_handle) and >>> then calling my_bond.NPV(). While the above returns a value, it does not >>> return a value exactly equal to the dirty price of the bond using the >>> closed-form my_bond.dirtyPrice(*args, settle_date) method. the values >>> differ by about 0.013, whihc is about euqal to 100 *(1-1/(1+.05/365)), >>> meaning that the difference is about one day of discounting at a 5% rate, >>> close to market rates. >>> This strongly indicates that thre NPV() method discounts the cash flows >>> to T+0 = trade_date, and not to the T+1 settle date. >>> So how can I instruct my_bond.NPV() to use a given settle date? I looked >>> in the documentation of both python and C++ and it doesn't seem like there >>> is any way to do that? >>> One thing I tried to do is ql.Settings.instance().evaluationDate = >>> settle_date just before I call .NPV() but it does exactly the opposite and >>> appears to add one more day of discounting instead of reducing it. >>> >>> Any advice is appreciated. >>> >>> >>> Regards Philippe Hatstadt 203-252-0408 pha...@ma... >>> >>> >>> _______________________________________________ >>> QuantLib-users mailing list >>> Qua...@li... >>> https://lists.sourceforge.net/lists/listinfo/quantlib-users >>> >> _______________________________________________ >> QuantLib-users mailing list >> Qua...@li... >> https://lists.sourceforge.net/lists/listinfo/quantlib-users >> > > 1370 Broadway, Suite 1450 | New York, NY | 10018 > > [image: https://www.exosfinancial.com/] <https://www.exosfinancial.com/> [image: > https://www.linkedin.com/company/meetexos/about/] > <https://www.linkedin.com/company/meetexos/about/> > > Broker-Dealer services offered through Exos Securities LLC, Member SIPC, > FINRA. For important disclosures including Form CRS and Regulation BI click > here <https://www.exosfinancial.com/general-disclosures>. > > > Confidentiality Notice: The information contained in this email > (including attachments) is only for the personal and confidential use of > the sender and recipient named above. If the reader is not the intended > recipient, you are notified that you have received this message in error > and that any review, dissemination, copying or distribution is prohibited. > If you have received this communication in error, please notify the sender > immediately by e-mail and delete or destroy the original message and all > copies. > |