You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
(60) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(18) |
Feb
(4) |
Mar
(6) |
Apr
(2) |
May
|
Jun
(12) |
Jul
(48) |
Aug
(6) |
Sep
(3) |
Oct
(24) |
Nov
(15) |
Dec
(18) |
2002 |
Jan
(39) |
Feb
(12) |
Mar
(80) |
Apr
(72) |
May
(46) |
Jun
(27) |
Jul
(23) |
Aug
(34) |
Sep
(65) |
Oct
(71) |
Nov
(19) |
Dec
(14) |
2003 |
Jan
(44) |
Feb
(59) |
Mar
(18) |
Apr
(62) |
May
(54) |
Jun
(27) |
Jul
(46) |
Aug
(15) |
Sep
(44) |
Oct
(36) |
Nov
(19) |
Dec
(12) |
2004 |
Jan
(26) |
Feb
(33) |
Mar
(47) |
Apr
(63) |
May
(36) |
Jun
(65) |
Jul
(80) |
Aug
(163) |
Sep
(65) |
Oct
(39) |
Nov
(36) |
Dec
(39) |
2005 |
Jan
(97) |
Feb
(78) |
Mar
(64) |
Apr
(64) |
May
(48) |
Jun
(55) |
Jul
(89) |
Aug
(57) |
Sep
(51) |
Oct
(111) |
Nov
(86) |
Dec
(76) |
2006 |
Jan
(84) |
Feb
(103) |
Mar
(143) |
Apr
(92) |
May
(55) |
Jun
(58) |
Jul
(71) |
Aug
(57) |
Sep
(74) |
Oct
(59) |
Nov
(8) |
Dec
(32) |
2007 |
Jan
(60) |
Feb
(40) |
Mar
(50) |
Apr
(26) |
May
(61) |
Jun
(120) |
Jul
(119) |
Aug
(48) |
Sep
(121) |
Oct
(66) |
Nov
(103) |
Dec
(43) |
2008 |
Jan
(60) |
Feb
(109) |
Mar
(92) |
Apr
(106) |
May
(82) |
Jun
(59) |
Jul
(67) |
Aug
(118) |
Sep
(131) |
Oct
(56) |
Nov
(37) |
Dec
(69) |
2009 |
Jan
(75) |
Feb
(76) |
Mar
(103) |
Apr
(78) |
May
(61) |
Jun
(35) |
Jul
(66) |
Aug
(69) |
Sep
(166) |
Oct
(46) |
Nov
(72) |
Dec
(65) |
2010 |
Jan
(48) |
Feb
(57) |
Mar
(93) |
Apr
(85) |
May
(123) |
Jun
(82) |
Jul
(98) |
Aug
(121) |
Sep
(146) |
Oct
(86) |
Nov
(72) |
Dec
(34) |
2011 |
Jan
(96) |
Feb
(55) |
Mar
(73) |
Apr
(57) |
May
(33) |
Jun
(74) |
Jul
(89) |
Aug
(71) |
Sep
(103) |
Oct
(76) |
Nov
(52) |
Dec
(61) |
2012 |
Jan
(48) |
Feb
(54) |
Mar
(78) |
Apr
(60) |
May
(75) |
Jun
(59) |
Jul
(33) |
Aug
(66) |
Sep
(43) |
Oct
(46) |
Nov
(75) |
Dec
(51) |
2013 |
Jan
(112) |
Feb
(72) |
Mar
(49) |
Apr
(48) |
May
(42) |
Jun
(44) |
Jul
(80) |
Aug
(19) |
Sep
(33) |
Oct
(37) |
Nov
(38) |
Dec
(98) |
2014 |
Jan
(113) |
Feb
(93) |
Mar
(49) |
Apr
(106) |
May
(97) |
Jun
(155) |
Jul
(87) |
Aug
(127) |
Sep
(85) |
Oct
(48) |
Nov
(41) |
Dec
(37) |
2015 |
Jan
(34) |
Feb
(50) |
Mar
(104) |
Apr
(80) |
May
(82) |
Jun
(66) |
Jul
(41) |
Aug
(84) |
Sep
(37) |
Oct
(65) |
Nov
(83) |
Dec
(52) |
2016 |
Jan
(68) |
Feb
(35) |
Mar
(42) |
Apr
(35) |
May
(54) |
Jun
(75) |
Jul
(45) |
Aug
(52) |
Sep
(60) |
Oct
(52) |
Nov
(36) |
Dec
(64) |
2017 |
Jan
(92) |
Feb
(59) |
Mar
(35) |
Apr
(53) |
May
(83) |
Jun
(43) |
Jul
(65) |
Aug
(68) |
Sep
(46) |
Oct
(75) |
Nov
(40) |
Dec
(49) |
2018 |
Jan
(68) |
Feb
(54) |
Mar
(48) |
Apr
(58) |
May
(51) |
Jun
(44) |
Jul
(40) |
Aug
(68) |
Sep
(35) |
Oct
(15) |
Nov
(7) |
Dec
(37) |
2019 |
Jan
(43) |
Feb
(7) |
Mar
(22) |
Apr
(21) |
May
(31) |
Jun
(39) |
Jul
(73) |
Aug
(45) |
Sep
(47) |
Oct
(89) |
Nov
(19) |
Dec
(69) |
2020 |
Jan
(52) |
Feb
(63) |
Mar
(45) |
Apr
(59) |
May
(42) |
Jun
(57) |
Jul
(30) |
Aug
(29) |
Sep
(75) |
Oct
(64) |
Nov
(96) |
Dec
(22) |
2021 |
Jan
(14) |
Feb
(24) |
Mar
(35) |
Apr
(58) |
May
(36) |
Jun
(15) |
Jul
(18) |
Aug
(31) |
Sep
(30) |
Oct
(33) |
Nov
(27) |
Dec
(16) |
2022 |
Jan
(35) |
Feb
(22) |
Mar
(14) |
Apr
(20) |
May
(44) |
Jun
(53) |
Jul
(25) |
Aug
(56) |
Sep
(11) |
Oct
(47) |
Nov
(22) |
Dec
(36) |
2023 |
Jan
(30) |
Feb
(17) |
Mar
(31) |
Apr
(48) |
May
(31) |
Jun
(7) |
Jul
(25) |
Aug
(26) |
Sep
(61) |
Oct
(66) |
Nov
(19) |
Dec
(21) |
2024 |
Jan
(37) |
Feb
(29) |
Mar
(26) |
Apr
(26) |
May
(34) |
Jun
(9) |
Jul
(27) |
Aug
(13) |
Sep
(3) |
Oct
|
Nov
|
Dec
|
From: Amine I. <ami...@gm...> - 2024-09-19 13:54:17
|
> Hi all, > > I am trying to run the test suite for QL under a Mac OS environment. I have successfully built the library, but trying to run the series of tests under Xcode, the MacOS IDE. > > Any help on how to proceed would be very much appreciated. > > Thanks. > > Amine |
From: Luigi B. <lui...@gm...> - 2024-09-19 10:07:36
|
Hi, an update: it turns out that sometimes SubPeriodsLeg doesn't do the right thing, see < https://implementingquantlib.substack.com/p/coupons-with-multiple-resets>. I'll try to get a fix in the library in one of the next releases. Luigi On Tue, Aug 27, 2024 at 9:11 AM Luigi Ballabio <lui...@gm...> wrote: > Hi, > as Arkadiy says, they will have the same fixing, but there are other > problems as well. > > One is that, unfortunately, Period(7, Days) is not the same as one week; > it's 7 business days instead. You need Period(1, Weeks). We'll have to > try and disambiguate it sometime, but it's everywhere in the library so > we'll have to be careful. > > Another is that NonstandardSwap creates floating-rate coupons with a > single initial fixing, regardless of the tenor of the passed index; so > coupons will take the 1-week fixing at the beginning of their tenor and > accrue it for the whole three months without compounding. To get the > behavior you want, there's no built-in instrument but you can build the two > legs manually and pass them to the Swap class. You'll have to use FixedLeg > for the fixed coupons and SubPeriodsLeg for the floating leg; the latter > builds a sequence of SubPeriodsCoupon instances, which have the compounding > behavior you want. > > I'll try to publish an example when I get a chance to work on it, but in > the meantime I hope this helps to point you in the right direction. > > Luigi > > > On Tue, Aug 27, 2024 at 5:46 AM Arkadiy Naumov <ark...@gm...> > wrote: > >> Hi Jack, >> >> It looks like your test is undermined by your using the flat 5% curve, >> forcing your resets, no matter the frequency, to generate exactly the same >> interest over the 3M period. It’s just that the fixing for the daily resets >> will be slightly smaller than that for weekly resets, and that in turn will >> be smaller than the fixing for the quarterly resets (to account for the >> compounding). I would try creating curve with a few tenors, and re-running >> the test with that new curve. >> >> Sent from my iPad >> >> On Aug 26, 2024, at 10:09 PM, Spectrum <jac...@gm...> wrote: >> >> >> >> In the QuantLib python document, there is an example for creating a >> custom OvernightIndex: >> >> name = 'CNYRepo7D' >> fixingDays = 1 >> currency = ql.CNYCurrency() >> calendar = ql.China() >> dayCounter = ql.Actual365Fixed() >> overnight_index = ql.OvernightIndex(name, fixingDays, currency, calendar, dayCounter) >> >> >> In this example, a CNYRepo7D index is created as an OvernightIndex. But, >> the CNYRepo7D has a coupon reset frequency of 7 days, not daily. So the >> coupon should compound every week, not everyday. Is this example correct? >> >> I then tried to use ql.IborIndex to model CNYRepo7D, where I created an >> IborIndex with a ql.Period(7, ql.Days). I also tried an IborIndex with a >> Period of 3M. But the result seems to be identical. I created a swap with a >> flat curve of 5% and printed out the floating leg cash flow. All 3 indexes >> (Overnight, 7D Ibor, 3M Ibor) give me the same cash flow for the dummy swap. >> >> What is the correct way to model a swap where its reset frequency is >> different from the payment frequency? >> >> import QuantLib as ql >> >> today = ql.Date(24,8,2024) >> >> # create a flat curve of 5% >> rate = 0.05 >> dayCounter = ql.Actual365Fixed() >> interest_rate = ql.QuoteHandle(ql.SimpleQuote(rate)) >> flat_curve = ql.FlatForward(today, ql.QuoteHandle(ql.SimpleQuote(rate)), dayCounter) >> curve_handle = ql.YieldTermStructureHandle(flat_curve) >> >> currency = ql.CNYCurrency() >> calendar = ql.China() >> >> >> def print_floating_cashflow_given_index(index): >> # Add the fixing >> index.addFixing(ql.Date(23, 8, 2024), 0.05) >> # Create a 1Y swap with Quarterly Payment Frequency >> maturity_date = calendar.advance(today, 1, ql.Years, ql.Unadjusted) >> schedule = ql.Schedule(today, maturity_date, ql.Period(3, ql.Months), calendar, ql.ModifiedFollowing, >> ql.ModifiedFollowing, ql.DateGeneration.Forward, False) >> schedule_len = len(schedule) - 1 >> coupon_swap = ql.NonstandardSwap(ql.VanillaSwap.Receiver, >> [1] * schedule_len, >> [1] * schedule_len, >> schedule, >> [0.05] * schedule_len, >> dayCounter, >> schedule, >> index, >> [1.] * schedule_len, >> [0] * schedule_len, >> dayCounter, >> False, >> True) >> for cf in coupon_swap.floatingLeg(): >> print(cf.date(), cf.amount()) >> >> # create Overnight Index >> fixingDays = 1 >> overnight_index = ql.OvernightIndex('CNYRepo7D', >> fixingDays, >> currency, >> calendar, >> dayCounter, >> curve_handle) >> print('Overnight Index Floating CashFlow') >> print_floating_cashflow_given_index(overnight_index) >> >> # create Ibor Weekly Index >> ibor_weekly_index = ql.IborIndex( >> 'CNY_Weekly', >> ql.Period(7, ql.Days), >> 1, >> currency, >> calendar, >> ql.ModifiedFollowing, >> False, >> dayCounter, >> curve_handle >> ) >> print('Weekly Ibor Index Floating CashFlow') >> print_floating_cashflow_given_index(ibor_weekly_index) >> >> # create Ibor Quarterly Index >> ibor_quarterly_index = ql.IborIndex( >> 'CNY_Quarterly', >> ql.Period(3, ql.Months), >> 1, >> currency, >> calendar, >> ql.ModifiedFollowing, >> False, >> dayCounter, >> curve_handle >> ) >> print('Quarterly Ibor Index Floating CashFlow') >> print_floating_cashflow_given_index(ibor_quarterly_index) >> >> >> Output >> >> Overnight Index Floating CashFlow >> November 25th, 2024 0.012465753424657534 >> February 24th, 2025 0.012543774790186646 >> May 26th, 2025 0.012543774790186868 >> August 25th, 2025 0.012543774790186868 >> August 25th, 2025 1.0 >> Weekly Ibor Index Floating CashFlow >> November 25th, 2024 0.012465753424657534 >> February 24th, 2025 0.012543774790186646 >> May 26th, 2025 0.012543774790186868 >> August 25th, 2025 0.012543774790186868 >> August 25th, 2025 1.0 >> Quarterly Ibor Index Floating CashFlow >> November 25th, 2024 0.012465753424657534 >> February 24th, 2025 0.012543774790186646 >> May 26th, 2025 0.012543774790186868 >> August 25th, 2025 0.012543774790186868 >> August 25th, 2025 1.0 >> >> >> Thanks >> >> Jack >> >> >> _______________________________________________ >> 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 >> > |
From: groot <Iam...@pr...> - 2024-09-02 22:59:19
|
Hi, I'm using QuantLib to construct the zero and forward rate curve from Par rates on US Treasuries. I wrote my own functions in VBA to do this but QuantLib is more powerful and I'd prefer to use it. The expected values for spot and forward rates on Treasury securities with maturities less than or equal to one year should be the same as the par rates, as these are zero coupon securities. That's not what I'm getting back from PiecewiseLogCubicDiscount. Here is the data. YieldCurve mat par spot forward 0.0833 0.0551 5.64883080311542E-02 4.18176348266894E-02 0.1666 0.0535 5.47499199251955E-02 4.02285021906204E-02 0.25 0.0525 5.35238049390581E-02 3.89048578349651E-02 0.3333 0.0513 0.052182971638125 3.77235258294319E-02 0.5 0.0492 4.97392724591892E-02 3.60274287153215E-02 1 0.0436 4.35928952862372E-02 3.42467385575433E-02 2 0.039 3.89088657643741E-02 3.37267785665316E-02 3 0.0373 3.71786411067594E-02 3.43993196709811E-02 5 0.0365 3.64823149467199E-02 0.036027062681081 7 0.0371 0.036389795652668 3.81708676362535E-02 10 0.0381 3.66862340641292E-02 3.94642932892748E-02 20 0.0418 0.037082733401077 3.98780830344536E-02 30 0.041 3.74317594975078E-02 4.07055565483423E-02 My code is written in VB.net. Is there any sample code out there that does what I'm trying to do? It can be in Python, C++. Regards, |
From: Luigi B. <lui...@gm...> - 2024-08-28 15:08:21
|
Glad it worked out — and thanks, it was an interesting check. Luigi On Tue, Aug 27, 2024 at 12:32 PM Charles Allderman <ch...@al...> wrote: > I have found the source of the difference. The section below needs a > compounded annual rate and not a continuous rate. > > ql.ZeroCouponInflationSwapHelper( > ql.makeQuoteHandle(implied_infl_curve.zeroRate(maturity,ql. > Actual365Fixed(),ql.Compounded).rate()), # Continuous, Annual > observation_lag, > maturity, > calendar, > ql.Following, > day_counter, > index, > interpolation, > nominal_curve, > ) > > > > > > On Tue, Aug 27, 2024 at 10:11 AM Charles Allderman <ch...@al...> > wrote: > >> @Luigi Ballabio <lui...@gm...> posted this very >> informative piece, >> https://www.implementingquantlib.com/2024/05/inflation-curves.html >> on Inflation indexes and curves which has been of great help. >> >> What I am struggling with, is that when I price a CPI bond, I would >> expect the value of the bond priced off the real curve to equal the price >> of the CPI bond priced off the nominal curve with coupons increased by the >> forecasted inflation rate as defined by implied inflation being the >> difference between the nominal and real zero curves. >> >> I have investigated this here by adapting the Python code from >> https://www.implementingquantlib.com/2024/05/inflation-curves.html, by >> defining a Nominal and Real curve, with implied inflation being the >> geometric diff of the two curves. >> >> The problem is that I was expecting ql.CPI.laggedFixing(hicp, some_date, >> observation_lag, ql.CPI.Linear))/ ValueBase to be very close to 1.0/ >> implied_infl_curve.discount(some_date)) however this does not seem to be >> the case: >> >> >> node nom real imp_inf base_val inf diff >> May 11th, 2024 1.0000000 1.0000000 1.0000000 124.6732258 1.0000000 >> - >> May 12th, 2025 1.0620111 1.0298161 1.0312628 124.6732258 1.0308708 >> -0.0003802 >> May 11th, 2026 1.1274969 1.0607752 1.0628989 124.6732258 1.0620177 >> -0.0008291 >> May 11th, 2027 1.1972174 1.0930260 1.0953238 124.6732258 1.0939309 >> -0.0012716 >> May 11th, 2028 1.2714581 1.1266872 1.1284926 124.6732258 1.1264751 >> -0.0017878 >> May 11th, 2029 1.3500807 1.1619297 1.1619297 124.6732258 1.1594619 >> -0.0021240 >> May 12th, 2031 1.5224620 1.2390781 1.2287054 124.6732258 1.2251594 >> -0.0028860 >> May 11th, 2034 1.8227180 1.3739282 1.3266471 124.6732258 1.3215592 >> -0.0038352 >> May 12th, 2036 2.0557845 1.4762652 1.3925577 124.6732258 1.3863294 >> -0.0044726 >> May 11th, 2039 2.4608164 1.6392202 1.5012116 124.6732258 1.4932337 >> -0.0053143 >> May 11th, 2044 3.3228469 1.9504444 1.7036358 124.6732258 1.6918066 >> -0.0069435 >> May 11th, 2049 4.4861115 2.3106996 1.9414516 124.6732258 1.9248788 >> -0.0085363 >> May 11th, 2054 6.0566127 2.7320222 2.2168973 124.6732258 2.1941767 >> -0.0102488 >> May 12th, 2064 11.0431267 3.7591653 2.9376540 124.6732258 2.8960907 -0.0141484 >> >> May 11th, 2074 20.1251968 5.0281959 4.0024687 124.6732258 3.9279265 -0.0186241 >> >> >> To replicate please see the Python below: >> >> import QuantLib as ql >> import pandas as pd >> today = ql.Date(11, ql.May, 2024) >> ql.Settings.instance().evaluationDate = today >> >> >> index = ql.EUHICP() >> >> inflation_fixings = [ >> ((2022, ql.January), 110.70), >> ((2022, ql.February), 111.74), >> ((2022, ql.March), 114.46), >> ((2022, ql.April), 115.11), >> ((2022, ql.May), 116.07), >> ((2022, ql.June), 117.01), >> ((2022, ql.July), 117.14), >> ((2022, ql.August), 117.85), >> ((2022, ql.September), 119.26), >> ((2022, ql.October), 121.03), >> ((2022, ql.November), 120.95), >> ((2022, ql.December), 120.52), >> ((2023, ql.January), 120.27), >> ((2023, ql.February), 121.24), >> ((2023, ql.March), 122.34), >> ((2023, ql.April), 123.12), >> ((2023, ql.May), 123.15), >> ((2023, ql.June), 123.47), >> ((2023, ql.July), 123.36), >> ((2023, ql.August), 124.03), >> ((2023, ql.September), 124.43), >> ((2023, ql.October), 124.54), >> ((2023, ql.November), 123.85), >> ((2023, ql.December), 124.05), >> ((2024, ql.January), 123.60), >> ((2024, ql.February), 124.37), >> ((2024, ql.March), 125.31), >> ((2024, ql.April), 126.05), >> ] >> >> for (year, month), fixing in inflation_fixings: >> index.addFixing(ql.Date(1, month, year), fixing) >> >> index.fixing(ql.Date(15, ql.March, 2024)) >> >> >> observation_lag = ql.Period(3, ql.Months) >> >> ql.CPI.laggedFixing( >> index, ql.Date(15, ql.May, 2024), observation_lag, ql.CPI.Linear >> ) >> >> real_quotes = [ >> (ql.Period(1, ql.Years), 2.93), >> (ql.Period(2, ql.Years), 2.95), >> (ql.Period(3, ql.Years), 2.965), >> (ql.Period(4, ql.Years), 2.98), >> (ql.Period(5, ql.Years), 3.0), >> (ql.Period(7, ql.Years), 3.06), >> (ql.Period(10, ql.Years), 3.175), >> (ql.Period(12, ql.Years), 3.243), >> (ql.Period(15, ql.Years), 3.293), >> (ql.Period(20, ql.Years), 3.338), >> (ql.Period(25, ql.Years), 3.348), >> (ql.Period(30, ql.Years), 3.348), >> (ql.Period(40, ql.Years), 3.308), >> (ql.Period(50, ql.Years), 3.228), >> ] >> >> calendar = ql.TARGET() >> observation_lag = ql.Period(3, ql.Months) >> day_counter = ql.Actual365Fixed() >> interpolation = ql.CPI.Linear >> >> nominal_curve = ql.YieldTermStructureHandle( >> ql.FlatForward(today, 0.06, ql.Actual365Fixed()) # Continuous, Annual >> ) >> >> >> rates,dates = [],[] >> for tenor, quote in real_quotes: >> maturity = calendar.advance(today, tenor) >> rates.append(quote/100.0) >> dates.append(maturity) >> >> real_curve = ql.ZeroCurve([today] + dates,[0.0] + rates,day_counter) # >> Continuous, Annual >> implied_infl_curve = ql.DiscountCurve([today] + dates,[1.0]+[ >> nominal_curve.discount(d)/real_curve.discount(d) for d in dates],ql. >> Actual365Fixed()) >> >> helpers = [] >> >> for tenor, quote in real_quotes: >> maturity = calendar.advance(today, tenor) >> helpers.append( >> ql.ZeroCouponInflationSwapHelper( >> ql.makeQuoteHandle(implied_infl_curve.zeroRate(maturity,ql. >> Actual365Fixed(),ql.Continuous).rate()), # Continuous, Annual >> observation_lag, >> maturity, >> calendar, >> ql.Following, >> day_counter, >> index, >> interpolation, >> nominal_curve, >> ) >> ) >> >> ql.Date(1,1,2024) >> fixing_frequency = ql.Monthly >> >> inflation_curve = ql.PiecewiseZeroInflation( >> today,index.lastFixingDate(), fixing_frequency, ql.Actual365Fixed(), >> helpers >> ) >> hicp = ql.EUHICP(ql.ZeroInflationTermStructureHandle(inflation_curve)) >> hicp.fixing(ql.Date(2, ql.February, 2074)) >> hicp.fixing(ql.Date(11, ql.May, 2024)) >> >> pd.DataFrame(inflation_curve.nodes(), columns=["node", "rate"]).style. >> format( >> {"rate": "{:.4%}"} >> ) >> >> df = pd.DataFrame(real_curve.nodes(), columns=["node", "yreal"]) >> df['nom'] = df.node.map(lambda x: 1.0/nominal_curve.discount(x)) >> df['real'] = df.node.map(lambda x: 1.0/real_curve.discount(x)) >> df['imp_inf'] = df.node.map(lambda x: 1.0/implied_infl_curve.discount(x)) >> df['base_val'] = df.node.map(lambda x: ql.CPI.laggedFixing(index, df.loc[ >> 0,'node'], observation_lag, ql.CPI.Linear)) >> df['inf'] = df.node.map(lambda x: ql.CPI.laggedFixing(hicp, x, >> observation_lag, ql.CPI.Linear)) >> df['inf'] = df.inf/df.base_val >> df['diff'] = df.inf/df.imp_inf-1 >> df >> >> Am I on the right track or am I missing something? Any feedback would be >> much appreciated. >> >> |
From: Charles A. <ch...@al...> - 2024-08-27 10:47:06
|
@Luigi Ballabio <lui...@gm...> posted this very informative piece, https://www.implementingquantlib.com/2024/05/inflation-curves.html on Inflation indexes and curves which has been of great help. What I am struggling with, is that when I price a CPI bond, I would expect the value of the bond priced off the real curve to equal the price of the CPI bond priced off the nominal curve with coupons increased by the forecasted inflation rate as defined by implied inflation being the difference between the nominal and real zero curves. I have investigated this here by adapting the Python code from https://www.implementingquantlib.com/2024/05/inflation-curves.html, by defining a Nominal and Real curve, with implied inflation being the geometric diff of the two curves. The problem is that I was expecting ql.CPI.laggedFixing(hicp, some_date, observation_lag, ql.CPI.Linear))/ ValueBase to be very close to 1.0/ implied_infl_curve.discount(some_date)) however this does not seem to be the case: node nom real imp_inf base_val inf diff May 11th, 2024 1.0000000 1.0000000 1.0000000 124.6732258 1.0000000 - May 12th, 2025 1.0620111 1.0298161 1.0312628 124.6732258 1.0308708 -0.0003802 May 11th, 2026 1.1274969 1.0607752 1.0628989 124.6732258 1.0620177 -0.0008291 May 11th, 2027 1.1972174 1.0930260 1.0953238 124.6732258 1.0939309 -0.0012716 May 11th, 2028 1.2714581 1.1266872 1.1284926 124.6732258 1.1264751 -0.0017878 May 11th, 2029 1.3500807 1.1619297 1.1619297 124.6732258 1.1594619 -0.0021240 May 12th, 2031 1.5224620 1.2390781 1.2287054 124.6732258 1.2251594 -0.0028860 May 11th, 2034 1.8227180 1.3739282 1.3266471 124.6732258 1.3215592 -0.0038352 May 12th, 2036 2.0557845 1.4762652 1.3925577 124.6732258 1.3863294 -0.0044726 May 11th, 2039 2.4608164 1.6392202 1.5012116 124.6732258 1.4932337 -0.0053143 May 11th, 2044 3.3228469 1.9504444 1.7036358 124.6732258 1.6918066 -0.0069435 May 11th, 2049 4.4861115 2.3106996 1.9414516 124.6732258 1.9248788 -0.0085363 May 11th, 2054 6.0566127 2.7320222 2.2168973 124.6732258 2.1941767 -0.0102488 May 12th, 2064 11.0431267 3.7591653 2.9376540 124.6732258 2.8960907 -0.0141484 May 11th, 2074 20.1251968 5.0281959 4.0024687 124.6732258 3.9279265 -0.0186241 To replicate please see the Python below: import QuantLib as ql import pandas as pd today = ql.Date(11, ql.May, 2024) ql.Settings.instance().evaluationDate = today index = ql.EUHICP() inflation_fixings = [ ((2022, ql.January), 110.70), ((2022, ql.February), 111.74), ((2022, ql.March), 114.46), ((2022, ql.April), 115.11), ((2022, ql.May), 116.07), ((2022, ql.June), 117.01), ((2022, ql.July), 117.14), ((2022, ql.August), 117.85), ((2022, ql.September), 119.26), ((2022, ql.October), 121.03), ((2022, ql.November), 120.95), ((2022, ql.December), 120.52), ((2023, ql.January), 120.27), ((2023, ql.February), 121.24), ((2023, ql.March), 122.34), ((2023, ql.April), 123.12), ((2023, ql.May), 123.15), ((2023, ql.June), 123.47), ((2023, ql.July), 123.36), ((2023, ql.August), 124.03), ((2023, ql.September), 124.43), ((2023, ql.October), 124.54), ((2023, ql.November), 123.85), ((2023, ql.December), 124.05), ((2024, ql.January), 123.60), ((2024, ql.February), 124.37), ((2024, ql.March), 125.31), ((2024, ql.April), 126.05), ] for (year, month), fixing in inflation_fixings: index.addFixing(ql.Date(1, month, year), fixing) index.fixing(ql.Date(15, ql.March, 2024)) observation_lag = ql.Period(3, ql.Months) ql.CPI.laggedFixing( index, ql.Date(15, ql.May, 2024), observation_lag, ql.CPI.Linear ) real_quotes = [ (ql.Period(1, ql.Years), 2.93), (ql.Period(2, ql.Years), 2.95), (ql.Period(3, ql.Years), 2.965), (ql.Period(4, ql.Years), 2.98), (ql.Period(5, ql.Years), 3.0), (ql.Period(7, ql.Years), 3.06), (ql.Period(10, ql.Years), 3.175), (ql.Period(12, ql.Years), 3.243), (ql.Period(15, ql.Years), 3.293), (ql.Period(20, ql.Years), 3.338), (ql.Period(25, ql.Years), 3.348), (ql.Period(30, ql.Years), 3.348), (ql.Period(40, ql.Years), 3.308), (ql.Period(50, ql.Years), 3.228), ] calendar = ql.TARGET() observation_lag = ql.Period(3, ql.Months) day_counter = ql.Actual365Fixed() interpolation = ql.CPI.Linear nominal_curve = ql.YieldTermStructureHandle( ql.FlatForward(today, 0.06, ql.Actual365Fixed()) # Continuous, Annual ) rates,dates = [],[] for tenor, quote in real_quotes: maturity = calendar.advance(today, tenor) rates.append(quote/100.0) dates.append(maturity) real_curve = ql.ZeroCurve([today] + dates,[0.0] + rates,day_counter) # Continuous, Annual implied_infl_curve = ql.DiscountCurve([today] + dates,[1.0]+[nominal_curve. discount(d)/real_curve.discount(d) for d in dates],ql.Actual365Fixed()) helpers = [] for tenor, quote in real_quotes: maturity = calendar.advance(today, tenor) helpers.append( ql.ZeroCouponInflationSwapHelper( ql.makeQuoteHandle(implied_infl_curve.zeroRate(maturity,ql. Actual365Fixed(),ql.Continuous).rate()), # Continuous, Annual observation_lag, maturity, calendar, ql.Following, day_counter, index, interpolation, nominal_curve, ) ) ql.Date(1,1,2024) fixing_frequency = ql.Monthly inflation_curve = ql.PiecewiseZeroInflation( today,index.lastFixingDate(), fixing_frequency, ql.Actual365Fixed(), helpers ) hicp = ql.EUHICP(ql.ZeroInflationTermStructureHandle(inflation_curve)) hicp.fixing(ql.Date(2, ql.February, 2074)) hicp.fixing(ql.Date(11, ql.May, 2024)) pd.DataFrame(inflation_curve.nodes(), columns=["node", "rate"]).style.format ( {"rate": "{:.4%}"} ) df = pd.DataFrame(real_curve.nodes(), columns=["node", "yreal"]) df['nom'] = df.node.map(lambda x: 1.0/nominal_curve.discount(x)) df['real'] = df.node.map(lambda x: 1.0/real_curve.discount(x)) df['imp_inf'] = df.node.map(lambda x: 1.0/implied_infl_curve.discount(x)) df['base_val'] = df.node.map(lambda x: ql.CPI.laggedFixing(index, df.loc[0, 'node'], observation_lag, ql.CPI.Linear)) df['inf'] = df.node.map(lambda x: ql.CPI.laggedFixing(hicp, x, observation_lag, ql.CPI.Linear)) df['inf'] = df.inf/df.base_val df['diff'] = df.inf/df.imp_inf-1 df Am I on the right track or am I missing something? Any feedback would be much appreciated. |
From: Charles A. <ch...@al...> - 2024-08-27 10:32:43
|
I have found the source of the difference. The section below needs a compounded annual rate and not a continuous rate. ql.ZeroCouponInflationSwapHelper( ql.makeQuoteHandle(implied_infl_curve.zeroRate(maturity,ql. Actual365Fixed(),ql.Compounded).rate()), # Continuous, Annual observation_lag, maturity, calendar, ql.Following, day_counter, index, interpolation, nominal_curve, ) On Tue, Aug 27, 2024 at 10:11 AM Charles Allderman <ch...@al...> wrote: > @Luigi Ballabio <lui...@gm...> posted this very > informative piece, > https://www.implementingquantlib.com/2024/05/inflation-curves.html > on Inflation indexes and curves which has been of great help. > > What I am struggling with, is that when I price a CPI bond, I would expect > the value of the bond priced off the real curve to equal the price of the > CPI bond priced off the nominal curve with coupons increased by the > forecasted inflation rate as defined by implied inflation being the > difference between the nominal and real zero curves. > > I have investigated this here by adapting the Python code from > https://www.implementingquantlib.com/2024/05/inflation-curves.html, by > defining a Nominal and Real curve, with implied inflation being the > geometric diff of the two curves. > > The problem is that I was expecting ql.CPI.laggedFixing(hicp, some_date, > observation_lag, ql.CPI.Linear))/ ValueBase to be very close to 1.0/ > implied_infl_curve.discount(some_date)) however this does not seem to be > the case: > > > node nom real imp_inf base_val inf diff > May 11th, 2024 1.0000000 1.0000000 1.0000000 124.6732258 1.0000000 > - > May 12th, 2025 1.0620111 1.0298161 1.0312628 124.6732258 1.0308708 -0.0003802 > > May 11th, 2026 1.1274969 1.0607752 1.0628989 124.6732258 1.0620177 -0.0008291 > > May 11th, 2027 1.1972174 1.0930260 1.0953238 124.6732258 1.0939309 -0.0012716 > > May 11th, 2028 1.2714581 1.1266872 1.1284926 124.6732258 1.1264751 -0.0017878 > > May 11th, 2029 1.3500807 1.1619297 1.1619297 124.6732258 1.1594619 -0.0021240 > > May 12th, 2031 1.5224620 1.2390781 1.2287054 124.6732258 1.2251594 -0.0028860 > > May 11th, 2034 1.8227180 1.3739282 1.3266471 124.6732258 1.3215592 -0.0038352 > > May 12th, 2036 2.0557845 1.4762652 1.3925577 124.6732258 1.3863294 -0.0044726 > > May 11th, 2039 2.4608164 1.6392202 1.5012116 124.6732258 1.4932337 -0.0053143 > > May 11th, 2044 3.3228469 1.9504444 1.7036358 124.6732258 1.6918066 -0.0069435 > > May 11th, 2049 4.4861115 2.3106996 1.9414516 124.6732258 1.9248788 -0.0085363 > > May 11th, 2054 6.0566127 2.7320222 2.2168973 124.6732258 2.1941767 -0.0102488 > > May 12th, 2064 11.0431267 3.7591653 2.9376540 124.6732258 2.8960907 -0.0141484 > > May 11th, 2074 20.1251968 5.0281959 4.0024687 124.6732258 3.9279265 -0.0186241 > > > To replicate please see the Python below: > > import QuantLib as ql > import pandas as pd > today = ql.Date(11, ql.May, 2024) > ql.Settings.instance().evaluationDate = today > > > index = ql.EUHICP() > > inflation_fixings = [ > ((2022, ql.January), 110.70), > ((2022, ql.February), 111.74), > ((2022, ql.March), 114.46), > ((2022, ql.April), 115.11), > ((2022, ql.May), 116.07), > ((2022, ql.June), 117.01), > ((2022, ql.July), 117.14), > ((2022, ql.August), 117.85), > ((2022, ql.September), 119.26), > ((2022, ql.October), 121.03), > ((2022, ql.November), 120.95), > ((2022, ql.December), 120.52), > ((2023, ql.January), 120.27), > ((2023, ql.February), 121.24), > ((2023, ql.March), 122.34), > ((2023, ql.April), 123.12), > ((2023, ql.May), 123.15), > ((2023, ql.June), 123.47), > ((2023, ql.July), 123.36), > ((2023, ql.August), 124.03), > ((2023, ql.September), 124.43), > ((2023, ql.October), 124.54), > ((2023, ql.November), 123.85), > ((2023, ql.December), 124.05), > ((2024, ql.January), 123.60), > ((2024, ql.February), 124.37), > ((2024, ql.March), 125.31), > ((2024, ql.April), 126.05), > ] > > for (year, month), fixing in inflation_fixings: > index.addFixing(ql.Date(1, month, year), fixing) > > index.fixing(ql.Date(15, ql.March, 2024)) > > > observation_lag = ql.Period(3, ql.Months) > > ql.CPI.laggedFixing( > index, ql.Date(15, ql.May, 2024), observation_lag, ql.CPI.Linear > ) > > real_quotes = [ > (ql.Period(1, ql.Years), 2.93), > (ql.Period(2, ql.Years), 2.95), > (ql.Period(3, ql.Years), 2.965), > (ql.Period(4, ql.Years), 2.98), > (ql.Period(5, ql.Years), 3.0), > (ql.Period(7, ql.Years), 3.06), > (ql.Period(10, ql.Years), 3.175), > (ql.Period(12, ql.Years), 3.243), > (ql.Period(15, ql.Years), 3.293), > (ql.Period(20, ql.Years), 3.338), > (ql.Period(25, ql.Years), 3.348), > (ql.Period(30, ql.Years), 3.348), > (ql.Period(40, ql.Years), 3.308), > (ql.Period(50, ql.Years), 3.228), > ] > > calendar = ql.TARGET() > observation_lag = ql.Period(3, ql.Months) > day_counter = ql.Actual365Fixed() > interpolation = ql.CPI.Linear > > nominal_curve = ql.YieldTermStructureHandle( > ql.FlatForward(today, 0.06, ql.Actual365Fixed()) # Continuous, Annual > ) > > > rates,dates = [],[] > for tenor, quote in real_quotes: > maturity = calendar.advance(today, tenor) > rates.append(quote/100.0) > dates.append(maturity) > > real_curve = ql.ZeroCurve([today] + dates,[0.0] + rates,day_counter) # > Continuous, Annual > implied_infl_curve = ql.DiscountCurve([today] + dates,[1.0]+[nominal_curve > .discount(d)/real_curve.discount(d) for d in dates],ql.Actual365Fixed()) > > helpers = [] > > for tenor, quote in real_quotes: > maturity = calendar.advance(today, tenor) > helpers.append( > ql.ZeroCouponInflationSwapHelper( > ql.makeQuoteHandle(implied_infl_curve.zeroRate(maturity,ql. > Actual365Fixed(),ql.Continuous).rate()), # Continuous, Annual > observation_lag, > maturity, > calendar, > ql.Following, > day_counter, > index, > interpolation, > nominal_curve, > ) > ) > > ql.Date(1,1,2024) > fixing_frequency = ql.Monthly > > inflation_curve = ql.PiecewiseZeroInflation( > today,index.lastFixingDate(), fixing_frequency, ql.Actual365Fixed(), > helpers > ) > hicp = ql.EUHICP(ql.ZeroInflationTermStructureHandle(inflation_curve)) > hicp.fixing(ql.Date(2, ql.February, 2074)) > hicp.fixing(ql.Date(11, ql.May, 2024)) > > pd.DataFrame(inflation_curve.nodes(), columns=["node", "rate"]).style. > format( > {"rate": "{:.4%}"} > ) > > df = pd.DataFrame(real_curve.nodes(), columns=["node", "yreal"]) > df['nom'] = df.node.map(lambda x: 1.0/nominal_curve.discount(x)) > df['real'] = df.node.map(lambda x: 1.0/real_curve.discount(x)) > df['imp_inf'] = df.node.map(lambda x: 1.0/implied_infl_curve.discount(x)) > df['base_val'] = df.node.map(lambda x: ql.CPI.laggedFixing(index, df.loc[0 > ,'node'], observation_lag, ql.CPI.Linear)) > df['inf'] = df.node.map(lambda x: ql.CPI.laggedFixing(hicp, x, > observation_lag, ql.CPI.Linear)) > df['inf'] = df.inf/df.base_val > df['diff'] = df.inf/df.imp_inf-1 > df > > Am I on the right track or am I missing something? Any feedback would be > much appreciated. > > |
From: Luigi B. <lui...@gm...> - 2024-08-27 07:12:10
|
Hi, as Arkadiy says, they will have the same fixing, but there are other problems as well. One is that, unfortunately, Period(7, Days) is not the same as one week; it's 7 business days instead. You need Period(1, Weeks). We'll have to try and disambiguate it sometime, but it's everywhere in the library so we'll have to be careful. Another is that NonstandardSwap creates floating-rate coupons with a single initial fixing, regardless of the tenor of the passed index; so coupons will take the 1-week fixing at the beginning of their tenor and accrue it for the whole three months without compounding. To get the behavior you want, there's no built-in instrument but you can build the two legs manually and pass them to the Swap class. You'll have to use FixedLeg for the fixed coupons and SubPeriodsLeg for the floating leg; the latter builds a sequence of SubPeriodsCoupon instances, which have the compounding behavior you want. I'll try to publish an example when I get a chance to work on it, but in the meantime I hope this helps to point you in the right direction. Luigi On Tue, Aug 27, 2024 at 5:46 AM Arkadiy Naumov <ark...@gm...> wrote: > Hi Jack, > > It looks like your test is undermined by your using the flat 5% curve, > forcing your resets, no matter the frequency, to generate exactly the same > interest over the 3M period. It’s just that the fixing for the daily resets > will be slightly smaller than that for weekly resets, and that in turn will > be smaller than the fixing for the quarterly resets (to account for the > compounding). I would try creating curve with a few tenors, and re-running > the test with that new curve. > > Sent from my iPad > > On Aug 26, 2024, at 10:09 PM, Spectrum <jac...@gm...> wrote: > > > > In the QuantLib python document, there is an example for creating a custom > OvernightIndex: > > name = 'CNYRepo7D' > fixingDays = 1 > currency = ql.CNYCurrency() > calendar = ql.China() > dayCounter = ql.Actual365Fixed() > overnight_index = ql.OvernightIndex(name, fixingDays, currency, calendar, dayCounter) > > > In this example, a CNYRepo7D index is created as an OvernightIndex. But, > the CNYRepo7D has a coupon reset frequency of 7 days, not daily. So the > coupon should compound every week, not everyday. Is this example correct? > > I then tried to use ql.IborIndex to model CNYRepo7D, where I created an > IborIndex with a ql.Period(7, ql.Days). I also tried an IborIndex with a > Period of 3M. But the result seems to be identical. I created a swap with a > flat curve of 5% and printed out the floating leg cash flow. All 3 indexes > (Overnight, 7D Ibor, 3M Ibor) give me the same cash flow for the dummy swap. > > What is the correct way to model a swap where its reset frequency is > different from the payment frequency? > > import QuantLib as ql > > today = ql.Date(24,8,2024) > > # create a flat curve of 5% > rate = 0.05 > dayCounter = ql.Actual365Fixed() > interest_rate = ql.QuoteHandle(ql.SimpleQuote(rate)) > flat_curve = ql.FlatForward(today, ql.QuoteHandle(ql.SimpleQuote(rate)), dayCounter) > curve_handle = ql.YieldTermStructureHandle(flat_curve) > > currency = ql.CNYCurrency() > calendar = ql.China() > > > def print_floating_cashflow_given_index(index): > # Add the fixing > index.addFixing(ql.Date(23, 8, 2024), 0.05) > # Create a 1Y swap with Quarterly Payment Frequency > maturity_date = calendar.advance(today, 1, ql.Years, ql.Unadjusted) > schedule = ql.Schedule(today, maturity_date, ql.Period(3, ql.Months), calendar, ql.ModifiedFollowing, > ql.ModifiedFollowing, ql.DateGeneration.Forward, False) > schedule_len = len(schedule) - 1 > coupon_swap = ql.NonstandardSwap(ql.VanillaSwap.Receiver, > [1] * schedule_len, > [1] * schedule_len, > schedule, > [0.05] * schedule_len, > dayCounter, > schedule, > index, > [1.] * schedule_len, > [0] * schedule_len, > dayCounter, > False, > True) > for cf in coupon_swap.floatingLeg(): > print(cf.date(), cf.amount()) > > # create Overnight Index > fixingDays = 1 > overnight_index = ql.OvernightIndex('CNYRepo7D', > fixingDays, > currency, > calendar, > dayCounter, > curve_handle) > print('Overnight Index Floating CashFlow') > print_floating_cashflow_given_index(overnight_index) > > # create Ibor Weekly Index > ibor_weekly_index = ql.IborIndex( > 'CNY_Weekly', > ql.Period(7, ql.Days), > 1, > currency, > calendar, > ql.ModifiedFollowing, > False, > dayCounter, > curve_handle > ) > print('Weekly Ibor Index Floating CashFlow') > print_floating_cashflow_given_index(ibor_weekly_index) > > # create Ibor Quarterly Index > ibor_quarterly_index = ql.IborIndex( > 'CNY_Quarterly', > ql.Period(3, ql.Months), > 1, > currency, > calendar, > ql.ModifiedFollowing, > False, > dayCounter, > curve_handle > ) > print('Quarterly Ibor Index Floating CashFlow') > print_floating_cashflow_given_index(ibor_quarterly_index) > > > Output > > Overnight Index Floating CashFlow > November 25th, 2024 0.012465753424657534 > February 24th, 2025 0.012543774790186646 > May 26th, 2025 0.012543774790186868 > August 25th, 2025 0.012543774790186868 > August 25th, 2025 1.0 > Weekly Ibor Index Floating CashFlow > November 25th, 2024 0.012465753424657534 > February 24th, 2025 0.012543774790186646 > May 26th, 2025 0.012543774790186868 > August 25th, 2025 0.012543774790186868 > August 25th, 2025 1.0 > Quarterly Ibor Index Floating CashFlow > November 25th, 2024 0.012465753424657534 > February 24th, 2025 0.012543774790186646 > May 26th, 2025 0.012543774790186868 > August 25th, 2025 0.012543774790186868 > August 25th, 2025 1.0 > > > Thanks > > Jack > > > _______________________________________________ > 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 > |
From: Arkadiy N. <ark...@gm...> - 2024-08-27 03:42:44
|
Hi Jack, It looks like your test is undermined by your using the flat 5% curve, forcing your resets, no matter the frequency, to generate exactly the same interest over the 3M period. It’s just that the fixing for the daily resets will be slightly smaller than that for weekly resets, and that in turn will be smaller than the fixing for the quarterly resets (to account for the compounding). I would try creating curve with a few tenors, and re-running the test with that new curve. Sent from my iPad > On Aug 26, 2024, at 10:09 PM, Spectrum <jac...@gm...> wrote: > > > In the QuantLib python document, there is an example for creating a custom OvernightIndex: > > name = 'CNYRepo7D' > fixingDays = 1 > currency = ql.CNYCurrency() > calendar = ql.China() > dayCounter = ql.Actual365Fixed() > overnight_index = ql.OvernightIndex(name, fixingDays, currency, calendar, dayCounter) > > In this example, a CNYRepo7D index is created as an OvernightIndex. But, the CNYRepo7D has a coupon reset frequency of 7 days, not daily. So the coupon should compound every week, not everyday. Is this example correct? > > I then tried to use ql.IborIndex to model CNYRepo7D, where I created an IborIndex with a ql.Period(7, ql.Days). I also tried an IborIndex with a Period of 3M. But the result seems to be identical. I created a swap with a flat curve of 5% and printed out the floating leg cash flow. All 3 indexes (Overnight, 7D Ibor, 3M Ibor) give me the same cash flow for the dummy swap. > > What is the correct way to model a swap where its reset frequency is different from the payment frequency? > > import QuantLib as ql > > today = ql.Date(24,8,2024) > > # create a flat curve of 5% > rate = 0.05 > dayCounter = ql.Actual365Fixed() > interest_rate = ql.QuoteHandle(ql.SimpleQuote(rate)) > flat_curve = ql.FlatForward(today, ql.QuoteHandle(ql.SimpleQuote(rate)), dayCounter) > curve_handle = ql.YieldTermStructureHandle(flat_curve) > > currency = ql.CNYCurrency() > calendar = ql.China() > > > def print_floating_cashflow_given_index(index): > # Add the fixing > index.addFixing(ql.Date(23, 8, 2024), 0.05) > # Create a 1Y swap with Quarterly Payment Frequency > maturity_date = calendar.advance(today, 1, ql.Years, ql.Unadjusted) > schedule = ql.Schedule(today, maturity_date, ql.Period(3, ql.Months), calendar, ql.ModifiedFollowing, > ql.ModifiedFollowing, ql.DateGeneration.Forward, False) > schedule_len = len(schedule) - 1 > coupon_swap = ql.NonstandardSwap(ql.VanillaSwap.Receiver, > [1] * schedule_len, > [1] * schedule_len, > schedule, > [0.05] * schedule_len, > dayCounter, > schedule, > index, > [1.] * schedule_len, > [0] * schedule_len, > dayCounter, > False, > True) > for cf in coupon_swap.floatingLeg(): > print(cf.date(), cf.amount()) > > # create Overnight Index > fixingDays = 1 > overnight_index = ql.OvernightIndex('CNYRepo7D', > fixingDays, > currency, > calendar, > dayCounter, > curve_handle) > print('Overnight Index Floating CashFlow') > print_floating_cashflow_given_index(overnight_index) > > # create Ibor Weekly Index > ibor_weekly_index = ql.IborIndex( > 'CNY_Weekly', > ql.Period(7, ql.Days), > 1, > currency, > calendar, > ql.ModifiedFollowing, > False, > dayCounter, > curve_handle > ) > print('Weekly Ibor Index Floating CashFlow') > print_floating_cashflow_given_index(ibor_weekly_index) > > # create Ibor Quarterly Index > ibor_quarterly_index = ql.IborIndex( > 'CNY_Quarterly', > ql.Period(3, ql.Months), > 1, > currency, > calendar, > ql.ModifiedFollowing, > False, > dayCounter, > curve_handle > ) > print('Quarterly Ibor Index Floating CashFlow') > print_floating_cashflow_given_index(ibor_quarterly_index) > > Output > > Overnight Index Floating CashFlow > November 25th, 2024 0.012465753424657534 > February 24th, 2025 0.012543774790186646 > May 26th, 2025 0.012543774790186868 > August 25th, 2025 0.012543774790186868 > August 25th, 2025 1.0 > Weekly Ibor Index Floating CashFlow > November 25th, 2024 0.012465753424657534 > February 24th, 2025 0.012543774790186646 > May 26th, 2025 0.012543774790186868 > August 25th, 2025 0.012543774790186868 > August 25th, 2025 1.0 > Quarterly Ibor Index Floating CashFlow > November 25th, 2024 0.012465753424657534 > February 24th, 2025 0.012543774790186646 > May 26th, 2025 0.012543774790186868 > August 25th, 2025 0.012543774790186868 > August 25th, 2025 1.0 > > Thanks > Jack > > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users |
From: Spectrum <jac...@gm...> - 2024-08-27 02:06:23
|
In the QuantLib python document, there is an example for creating a custom OvernightIndex: name = 'CNYRepo7D' fixingDays = 1 currency = ql.CNYCurrency() calendar = ql.China() dayCounter = ql.Actual365Fixed() overnight_index = ql.OvernightIndex(name, fixingDays, currency, calendar, dayCounter) In this example, a CNYRepo7D index is created as an OvernightIndex. But, the CNYRepo7D has a coupon reset frequency of 7 days, not daily. So the coupon should compound every week, not everyday. Is this example correct? I then tried to use ql.IborIndex to model CNYRepo7D, where I created an IborIndex with a ql.Period(7, ql.Days). I also tried an IborIndex with a Period of 3M. But the result seems to be identical. I created a swap with a flat curve of 5% and printed out the floating leg cash flow. All 3 indexes (Overnight, 7D Ibor, 3M Ibor) give me the same cash flow for the dummy swap. What is the correct way to model a swap where its reset frequency is different from the payment frequency? import QuantLib as ql today = ql.Date(24,8,2024) # create a flat curve of 5% rate = 0.05 dayCounter = ql.Actual365Fixed() interest_rate = ql.QuoteHandle(ql.SimpleQuote(rate)) flat_curve = ql.FlatForward(today, ql.QuoteHandle(ql.SimpleQuote(rate)), dayCounter) curve_handle = ql.YieldTermStructureHandle(flat_curve) currency = ql.CNYCurrency() calendar = ql.China() def print_floating_cashflow_given_index(index): # Add the fixing index.addFixing(ql.Date(23, 8, 2024), 0.05) # Create a 1Y swap with Quarterly Payment Frequency maturity_date = calendar.advance(today, 1, ql.Years, ql.Unadjusted) schedule = ql.Schedule(today, maturity_date, ql.Period(3, ql.Months), calendar, ql.ModifiedFollowing, ql.ModifiedFollowing, ql.DateGeneration.Forward, False) schedule_len = len(schedule) - 1 coupon_swap = ql.NonstandardSwap(ql.VanillaSwap.Receiver, [1] * schedule_len, [1] * schedule_len, schedule, [0.05] * schedule_len, dayCounter, schedule, index, [1.] * schedule_len, [0] * schedule_len, dayCounter, False, True) for cf in coupon_swap.floatingLeg(): print(cf.date(), cf.amount()) # create Overnight Index fixingDays = 1 overnight_index = ql.OvernightIndex('CNYRepo7D', fixingDays, currency, calendar, dayCounter, curve_handle) print('Overnight Index Floating CashFlow') print_floating_cashflow_given_index(overnight_index) # create Ibor Weekly Index ibor_weekly_index = ql.IborIndex( 'CNY_Weekly', ql.Period(7, ql.Days), 1, currency, calendar, ql.ModifiedFollowing, False, dayCounter, curve_handle ) print('Weekly Ibor Index Floating CashFlow') print_floating_cashflow_given_index(ibor_weekly_index) # create Ibor Quarterly Index ibor_quarterly_index = ql.IborIndex( 'CNY_Quarterly', ql.Period(3, ql.Months), 1, currency, calendar, ql.ModifiedFollowing, False, dayCounter, curve_handle ) print('Quarterly Ibor Index Floating CashFlow') print_floating_cashflow_given_index(ibor_quarterly_index) Output Overnight Index Floating CashFlow November 25th, 2024 0.012465753424657534 February 24th, 2025 0.012543774790186646 May 26th, 2025 0.012543774790186868 August 25th, 2025 0.012543774790186868 August 25th, 2025 1.0 Weekly Ibor Index Floating CashFlow November 25th, 2024 0.012465753424657534 February 24th, 2025 0.012543774790186646 May 26th, 2025 0.012543774790186868 August 25th, 2025 0.012543774790186868 August 25th, 2025 1.0 Quarterly Ibor Index Floating CashFlow November 25th, 2024 0.012465753424657534 February 24th, 2025 0.012543774790186646 May 26th, 2025 0.012543774790186868 August 25th, 2025 0.012543774790186868 August 25th, 2025 1.0 Thanks Jack |
From: Quant <qua...@gm...> - 2024-08-21 07:19:01
|
Thanks Luigi, that was very helpful. Regards, Nk On Tue, 20 Aug 2024 at 18:51, Luigi Ballabio <lui...@gm...> wrote: > Hello, > given the signature of the constructor of > UltimateForwardTermStructure, you need something like > > ultimate_curve = ql.UltimateForwardTermStructure( > ql.YieldTermStructureHandle(curve), > ql.QuoteHandle(ql.SimpleQuote(lastLiquidForwardRate)), > ql.QuoteHandle(ql.SimpleQuote(ultimateForwardRate)), > firstSmoothingPoint, > alpha > ) > > where: > - curve is your existing curve; > - lastLiquidForwardRate is the value of the forward rate where you > want the extrapolation to begin (I'd probably extract it from the existing > curve); > - ultimateForwardRate is the value of the target forward rate (your > 6%); > - firstSmoothingPoint is where you want to start the extrapolation > (probably the end of your curve, but it might be earlier) expressed as a > period, so something like 24 years in your case; > - and you can choose alpha so your curve converges at the speed you > want. > > Hope this helps, > Luigi > > > > On Sun, Aug 18, 2024 at 12:44 AM Quant <qua...@gm...> wrote: > >> Hi QuantLib Users, >> >> I have bootstrapped a risk-free curve using government bonds which go up >> to around 24 years to maturity. Instead of extrapolating the curve using >> the curve.enableExtrapolation() which takes a flat forward curve, I >> would like to use ql.UltimateForwardTermStructure(). I would like the >> Ultimate Forward Curve to converge to 6% in 150 years, how do I update my >> code below to use ql.UltimateForwardTermStructure(): >> >> import pandas as pd >> import matplotlib.pyplot as plt >> import QuantLib as ql >> >> today = ql.Date(30, ql.November, 2023) >> ql.Settings.instance().evaluationDate = today >> >> calendar = ql.TARGET() >> day_count = ql.Actual365Fixed() >> >> # Settlement Days: >> zero_coupon_settlement_days = 0 >> coupon_bond_settlement_days = 3 >> >> # Face Value >> faceAmount = 100 >> >> data = [ >> ('30-11-2023', '29-02-2024', 0, 97.96413, zero_coupon_settlement_days), >> ('21-12-1997', '21-12-2026', 10.5, 104.5131, coupon_bond_settlement_days), >> ('31-07-2013', '31-01-2030', 8.0, 91.09656, coupon_bond_settlement_days), >> ('31-03-2014', '31-03-2032', 8.25, 86.00555, coupon_bond_settlement_days), >> ('31-07-2015', '31-01-2040', 9.0, 77.90538, coupon_bond_settlement_days), >> ('31-01-2014', '31-01-2044', 8.75, 74.15159, coupon_bond_settlement_days), >> ('28-02-2012', '28-02-2048', 8.75, 73.75747, coupon_bond_settlement_days)] >> >> helpers = [] >> >> for issue_date, maturity, coupon, price, settlement_days in data: >> price = ql.QuoteHandle(ql.SimpleQuote(price)) >> issue_date = ql.Date(issue_date, '%d-%m-%Y') >> maturity = ql.Date(maturity, '%d-%m-%Y') >> schedule = ql.Schedule(issue_date, maturity, ql.Period(ql.Semiannual), calendar, ql.DateGeneration.Backward, >> ql.Following, ql.DateGeneration.Backward, False) >> helper = ql.FixedRateBondHelper(price, settlement_days, faceAmount, schedule, [coupon / 100], day_count, >> False) >> helpers.append(helper) >> >> curve = ql.PiecewiseLinearZero(today, helpers, day_count) >> >> # Enable Extrapolation: >> curve.enableExtrapolation() >> >> # Creating Curve Data for Plotting: >> # Creates lists of curve dates, zero rates, and forward rates for plotting. >> # It calculates both zero rates and forward rates for each year up to 25 years from the current date. >> curve_dates = [today + ql.Period(i, ql.Days) >> for i in range(24 * 365)] >> curve_zero_rates = [curve.zeroRate(date, day_count, ql.Compounded, ql.Annual).rate() >> for date in curve_dates] >> curve_forward_rates = [curve.forwardRate(date, date + ql.Period(1, ql.Years), day_count, ql.Compounded).rate() >> for date in curve_dates] >> >> # Converting ql.Date to Numerical Values: (years from today) >> # Converts the curve dates (ql.Date objects) to numerical values representing years from the current >> # date. This is done to prepare the data for plotting on the x-axis. >> numeric_dates = [(date - today) / 365 for date in curve_dates] >> >> # Plotting: >> plt.figure(figsize=(8, 6)) >> plt.plot(numeric_dates, curve_zero_rates, marker='', linestyle='-', color='b', label='Zero Rates') >> plt.plot(numeric_dates, curve_forward_rates, marker='', linestyle='-', color='r', label='Forward Rates') >> plt.title('Zero and Forward Rates') >> plt.xlabel('Years from Today') >> plt.ylabel('Rate') >> plt.legend() >> plt.grid(True) >> plt.xticks(rotation=0) >> plt.tight_layout() >> >> plt.show() >> >> >> Thanks & regards, >> Nk >> > _______________________________________________ >> QuantLib-users mailing list >> Qua...@li... >> https://lists.sourceforge.net/lists/listinfo/quantlib-users >> > |
From: Aleksis A. R. <ale...@go...> - 2024-08-21 03:59:35
|
Usual convention for computing FX option dates (greater than 1m expiry) is to extract the expiry date via rolling back the settlement lag from the VALUE DATE, where VALUE DATE = SPOT DATE + expiry period, and SPOT DATE = TODAY + settlement lag. The ATM forward for said option should then match the FX forward to that expiry date. Let’s assume settlement lag = 2 (so SPOT DATE = TODAY + 2). If one builds an FX curve in Quanlib using: fxSwapHelpers = [ql.FxSwapRateHelper(ql.QuoteHandle(q), ql.QuoteHandle(FX), m, 2, calendar, business_convention_base, end_of_month, base_is_collateral, collateral_curve) for q, m in zip(fxswap_quotes, dffxswapsmaturity)] then the FX forward F for spot S to some VALUE DATE T is calculated as: F=S*(df_f(T)/df_f(2))/(df_d(T)/df_d(2)) ————————— (1) where df_f(T) = foreign discount factor to T df_f(2) = foreign discount factor to the settlement lag df_d(T) = domestic discount factor to T df_d(2) = domestic discount factor to the settlement lag and for sake of simplicity let's assume the collateral curve and foreign curve are the same (say USD OIS). The above formula then reproduces the FX fwds that are used to build the original curve. If forward interest rates to account for the settlement lag are not used i.e. if we just use the standard formula: F=S*df_f(T)/df_d(T) —————————————————(2) then we do not reproduce the “correct" FX forwards used to construct the original curve. Working with F as given by (1) we go on to construct an FX vol surface (employing the BlackVarianceSurface class) such that the ATMF coincides with F, as it should. Details of how we do this can be provided via DM if needed. Now the issue seems to arise when this FX curve (along with the aforementioned foreign curve) and the FX vol surface are used to build a GarmanKolhagen process and valuing a european vanilla FX option using this process. As the GK process does not allow for incorporation of a settlement lag, the depo rates this process is extracting from both the foreign and domestic curves are not forward interest rates, but rather spot rates from TODAY to T. This in turn leads to a violation of put-call parity for ATMF options because the ATMF rate used in the FX vol surface and the ATMF as calculated internally by GK are not the same. In case someone has tried the above approach, I would appreciate their opinion on both the veracity of our approach to FX option valuation in Quantlib and (if the approach is sound) a possible solution to the above issue. Many thanks, Aleksis |
From: Luigi B. <lui...@gm...> - 2024-08-20 16:51:31
|
Hello, given the signature of the constructor of UltimateForwardTermStructure, you need something like ultimate_curve = ql.UltimateForwardTermStructure( ql.YieldTermStructureHandle(curve), ql.QuoteHandle(ql.SimpleQuote(lastLiquidForwardRate)), ql.QuoteHandle(ql.SimpleQuote(ultimateForwardRate)), firstSmoothingPoint, alpha ) where: - curve is your existing curve; - lastLiquidForwardRate is the value of the forward rate where you want the extrapolation to begin (I'd probably extract it from the existing curve); - ultimateForwardRate is the value of the target forward rate (your 6%); - firstSmoothingPoint is where you want to start the extrapolation (probably the end of your curve, but it might be earlier) expressed as a period, so something like 24 years in your case; - and you can choose alpha so your curve converges at the speed you want. Hope this helps, Luigi On Sun, Aug 18, 2024 at 12:44 AM Quant <qua...@gm...> wrote: > Hi QuantLib Users, > > I have bootstrapped a risk-free curve using government bonds which go up > to around 24 years to maturity. Instead of extrapolating the curve using > the curve.enableExtrapolation() which takes a flat forward curve, I would > like to use ql.UltimateForwardTermStructure(). I would like the Ultimate > Forward Curve to converge to 6% in 150 years, how do I update my code below > to use ql.UltimateForwardTermStructure(): > > import pandas as pd > import matplotlib.pyplot as plt > import QuantLib as ql > > today = ql.Date(30, ql.November, 2023) > ql.Settings.instance().evaluationDate = today > > calendar = ql.TARGET() > day_count = ql.Actual365Fixed() > > # Settlement Days: > zero_coupon_settlement_days = 0 > coupon_bond_settlement_days = 3 > > # Face Value > faceAmount = 100 > > data = [ > ('30-11-2023', '29-02-2024', 0, 97.96413, zero_coupon_settlement_days), > ('21-12-1997', '21-12-2026', 10.5, 104.5131, coupon_bond_settlement_days), > ('31-07-2013', '31-01-2030', 8.0, 91.09656, coupon_bond_settlement_days), > ('31-03-2014', '31-03-2032', 8.25, 86.00555, coupon_bond_settlement_days), > ('31-07-2015', '31-01-2040', 9.0, 77.90538, coupon_bond_settlement_days), > ('31-01-2014', '31-01-2044', 8.75, 74.15159, coupon_bond_settlement_days), > ('28-02-2012', '28-02-2048', 8.75, 73.75747, coupon_bond_settlement_days)] > > helpers = [] > > for issue_date, maturity, coupon, price, settlement_days in data: > price = ql.QuoteHandle(ql.SimpleQuote(price)) > issue_date = ql.Date(issue_date, '%d-%m-%Y') > maturity = ql.Date(maturity, '%d-%m-%Y') > schedule = ql.Schedule(issue_date, maturity, ql.Period(ql.Semiannual), calendar, ql.DateGeneration.Backward, > ql.Following, ql.DateGeneration.Backward, False) > helper = ql.FixedRateBondHelper(price, settlement_days, faceAmount, schedule, [coupon / 100], day_count, > False) > helpers.append(helper) > > curve = ql.PiecewiseLinearZero(today, helpers, day_count) > > # Enable Extrapolation: > curve.enableExtrapolation() > > # Creating Curve Data for Plotting: > # Creates lists of curve dates, zero rates, and forward rates for plotting. > # It calculates both zero rates and forward rates for each year up to 25 years from the current date. > curve_dates = [today + ql.Period(i, ql.Days) > for i in range(24 * 365)] > curve_zero_rates = [curve.zeroRate(date, day_count, ql.Compounded, ql.Annual).rate() > for date in curve_dates] > curve_forward_rates = [curve.forwardRate(date, date + ql.Period(1, ql.Years), day_count, ql.Compounded).rate() > for date in curve_dates] > > # Converting ql.Date to Numerical Values: (years from today) > # Converts the curve dates (ql.Date objects) to numerical values representing years from the current > # date. This is done to prepare the data for plotting on the x-axis. > numeric_dates = [(date - today) / 365 for date in curve_dates] > > # Plotting: > plt.figure(figsize=(8, 6)) > plt.plot(numeric_dates, curve_zero_rates, marker='', linestyle='-', color='b', label='Zero Rates') > plt.plot(numeric_dates, curve_forward_rates, marker='', linestyle='-', color='r', label='Forward Rates') > plt.title('Zero and Forward Rates') > plt.xlabel('Years from Today') > plt.ylabel('Rate') > plt.legend() > plt.grid(True) > plt.xticks(rotation=0) > plt.tight_layout() > > plt.show() > > > Thanks & regards, > Nk > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users > |
From: Quant <qua...@gm...> - 2024-08-17 22:41:48
|
Hi QuantLib Users, I have bootstrapped a risk-free curve using government bonds which go up to around 24 years to maturity. Instead of extrapolating the curve using the curve.enableExtrapolation() which takes a flat forward curve, I would like to use ql.UltimateForwardTermStructure(). I would like the Ultimate Forward Curve to converge to 6% in 150 years, how do I update my code below to use ql.UltimateForwardTermStructure(): import pandas as pd import matplotlib.pyplot as plt import QuantLib as ql today = ql.Date(30, ql.November, 2023) ql.Settings.instance().evaluationDate = today calendar = ql.TARGET() day_count = ql.Actual365Fixed() # Settlement Days: zero_coupon_settlement_days = 0 coupon_bond_settlement_days = 3 # Face Value faceAmount = 100 data = [ ('30-11-2023', '29-02-2024', 0, 97.96413, zero_coupon_settlement_days), ('21-12-1997', '21-12-2026', 10.5, 104.5131, coupon_bond_settlement_days), ('31-07-2013', '31-01-2030', 8.0, 91.09656, coupon_bond_settlement_days), ('31-03-2014', '31-03-2032', 8.25, 86.00555, coupon_bond_settlement_days), ('31-07-2015', '31-01-2040', 9.0, 77.90538, coupon_bond_settlement_days), ('31-01-2014', '31-01-2044', 8.75, 74.15159, coupon_bond_settlement_days), ('28-02-2012', '28-02-2048', 8.75, 73.75747, coupon_bond_settlement_days)] helpers = [] for issue_date, maturity, coupon, price, settlement_days in data: price = ql.QuoteHandle(ql.SimpleQuote(price)) issue_date = ql.Date(issue_date, '%d-%m-%Y') maturity = ql.Date(maturity, '%d-%m-%Y') schedule = ql.Schedule(issue_date, maturity, ql.Period(ql.Semiannual), calendar, ql.DateGeneration.Backward, ql.Following, ql.DateGeneration.Backward, False) helper = ql.FixedRateBondHelper(price, settlement_days, faceAmount, schedule, [coupon / 100], day_count, False) helpers.append(helper) curve = ql.PiecewiseLinearZero(today, helpers, day_count) # Enable Extrapolation: curve.enableExtrapolation() # Creating Curve Data for Plotting: # Creates lists of curve dates, zero rates, and forward rates for plotting. # It calculates both zero rates and forward rates for each year up to 25 years from the current date. curve_dates = [today + ql.Period(i, ql.Days) for i in range(24 * 365)] curve_zero_rates = [curve.zeroRate(date, day_count, ql.Compounded, ql.Annual).rate() for date in curve_dates] curve_forward_rates = [curve.forwardRate(date, date + ql.Period(1, ql.Years), day_count, ql.Compounded).rate() for date in curve_dates] # Converting ql.Date to Numerical Values: (years from today) # Converts the curve dates (ql.Date objects) to numerical values representing years from the current # date. This is done to prepare the data for plotting on the x-axis. numeric_dates = [(date - today) / 365 for date in curve_dates] # Plotting: plt.figure(figsize=(8, 6)) plt.plot(numeric_dates, curve_zero_rates, marker='', linestyle='-', color='b', label='Zero Rates') plt.plot(numeric_dates, curve_forward_rates, marker='', linestyle='-', color='r', label='Forward Rates') plt.title('Zero and Forward Rates') plt.xlabel('Years from Today') plt.ylabel('Rate') plt.legend() plt.grid(True) plt.xticks(rotation=0) plt.tight_layout() plt.show() Thanks & regards, Nk |
From: Quant <qua...@gm...> - 2024-08-17 22:34:05
|
Thanks for the feedback Luigi On Tue, Jul 23, 2024 at 12:53 PM Luigi Ballabio <lui...@gm...> wrote: > Hello—no, it's not in QuantLib yet. I described a workaround in > https://www.implementingquantlib.com/2021/10/libor-fallback-calculation.html > which is a bit out of date, as it mentions a couple of outstanding issues > that were since solved; the accrual calculation has been correct for quite > a while, and as of the latest release (1.35) the overnight coupon can also > manage lookback days, lockout days and observation shifts. > > Hope this helps, > Luigi > > > > On Sun, Jul 21, 2024 at 5:41 PM Quant <qua...@gm...> wrote: > >> Hi QuantLib Users, >> >> I just want to check if the Libor-fallback pricer below was actually >> implemented in any version of QuantLib: >> >> https://github.com/lballabio/QuantLib/issues/1075 >> >> I am asking because I can not find it in the latest version 1.34. @Peter >> Caspers <pca...@gm...> it seems you were running with this >> some few years ago. >> >> Thanks & regards, >> NK >> _______________________________________________ >> QuantLib-users mailing list >> Qua...@li... >> https://lists.sourceforge.net/lists/listinfo/quantlib-users >> > |
From: <for...@ya...> - 2024-08-13 04:34:18
|
* { font-size: 13px; font-family: 'MS Pゴシック', sans-serif;}p, ul, ol, blockquote { margin: 0;}a { color: #0064c8; text-decoration: none;}a:hover { color: #0057af; text-decoration: underline;}a:active { color: #004c98;} Hi, I apologize for my question below. I solved it by adding "swapOBJ.setPricingEngine(ql.DiscountingSwapEngine(dCrvHDL))". Please forget about it. Kenji ----- Forwarded Message ----- From: "me" <for...@ya...> To: "Qua...@li..." <Qua...@li...> Date: 2024/08/12 月 23:32 Subject: Swap NPV cannot be zero under two curve. Hi, there I am calculating the swap NPV under two curves with the QuantLib's code attached, which is my toy model, but the swap NPV does not become zero. Could someone please point out what is wrong with my code? Thanks in advance, Kenji PS) If you run the attached, you will find "1x2 fwdIX: 0.1968" which I agreed. But I cannot agree "Swap NPV:-39,077.00", which should be zero. I guess that MakeVanillaSwap constructor is wrong. Are there any other constructor for multi-curve? |
From: <for...@ya...> - 2024-08-12 14:35:46
|
* { font-size: 13px; font-family: 'MS Pゴシック', sans-serif;}p, ul, ol, blockquote { margin: 0;}a { color: #0064c8; text-decoration: none;}a:hover { color: #0057af; text-decoration: underline;}a:active { color: #004c98;} Hi, there I am calculating the swap NPV under two curves with the QuantLib's code attached, which is my toy model, but the swap NPV does not become zero. Could someone please point out what is wrong with my code? Thanks in advance, Kenji PS) If you run the attached, you will find "1x2 fwdIX: 0.1968" which I agreed. But I cannot agree "Swap NPV:-39,077.00", which should be zero. I guess that MakeVanillaSwap constructor is wrong. Are there any other constructor for multi-curve? |
From: Philippe H. <pha...@ma...> - 2024-07-25 14:17:41
|
G2++ is probably ok to decorrelate term rates. it is HW2F that I was referring to as far as not being very suitable given short rate model. Problem is how to build a curve and get CMS rates from a Python interface to the QL G2++ process. I do not see any available working interface to do that, as the existing Python API is not correct versus the C++ signature as mentioned below. If you're happy with HW2F then you probably have most of what is required although I never used it, so guessing. Best regards Philippe Hatstadt 203-252-0408 https://www.linkedin.com/in/philippe-hatstadt/ On Jul 25, 2024, at 6:37 AM, Valerio Santaniello <val...@gm...> wrote: Hi Philippe, thanks a lot for your explanations. I'm quite aware of the limitations of the G2++ model when used to price CMS related instruments but we use it for "risk management" purposes (if this is an excuse) rather than for P&L purposes. Therefore, the choice of the model has been made essentially for simplicity reasons. Having said that, I'll start delving into the implementations of the model ported to Python and see if I can find some workaround. P.S.: I just noticed that I wrongly quoted Peter Casper in my first email, so I added it in the recipients of this email. I hope this doesn't bother you Peter and does not go against the mailing list's rules. Best, Valerio Il giorno mer 24 lug 2024 alle ore 15:47 Philippe Hatstadt < pha...@ma... > ha scritto: Sorry, this is the thread I am referring to. https://sourceforge.net/p/quantlib/mailman/message/58733701/ Essentially, there is a working Python calibration routine for G2++. However, certain process C++ classes were not 100% migrated to Python and they currently do not work, as there is a mismatch in required parameters (curve handle missing for instance). So it's not clear how to generate paths of CMS rates from the calibrated engine, as the processes cannot be called. Using a 2-factor HW is not something I would spend time on if the goal is to price CMS spread options, or any contingent payoff that depends on short versus longer tenors, as HW2F is still a short rate model, and it is not capable of substantially decorrelating say CMS2Y versus CMS10Y. The latter is essential to build GNMA prepayment and OAS models, so HW2F would clearly underprice the (negative) convexity. Your product is a CMS steepener, so I think it may suffer form the same issues. I guess what I'm saying is that I am unsure that there is any Python way of doing this with QL for claims that depend on dual CMS tenors. Luigi had asked me if I could help finish the G2++ processes to work in Python, but I don't really have the bandwidth. it would be nice if someone did it at some point. Best regards Philippe Hatstadt 203-252-0408 https://www.linkedin.com/in/philippe-hatstadt/ On Jul 24, 2024, at 8:51 AM, Valerio Santaniello < val...@gm... > wrote: Hi Philippe, which class are you referring to? I read in this thread that @PeterCasper had a working code to price CMS Spread Options with HW2F model, which would be very helpful to start thinking about a workaround. Best, Valerio Il giorno mer 24 lug 2024 alle ore 11:47 Philippe Hatstadt < phi...@ex... > ha scritto: As far as I know, the G2++ engine only has a C++ calibration implementation. Lack of a Python interface for it was a show stopper for me but if that doesn’t stop you then you might be able to price CMS steepeners at least via MC form the engine although I am unsure if that exists in Python either. Regards Philippe Hatstadt +1-203-252-0408 > On Jul 24, 2024, at 4:34 AM, Valerio Santaniello < val...@gm... > wrote: > > > Hi, > > I am trying to price CMS Steepeners Bonds with a G2++ model in QuantLib Python. I looked at the pricers available, but it seems that the only option would be to build a CMSSpreadLeg and use the lognormalCMSSpreadPricer, which does not appear to implement the G2++ model. Am I right or is there something I am missing? > > Best, > Valerio > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users -- 31 East 32nd Street, 3rd Floor | New York, NY | 10016 < https://www.exosfinancial.com/ > < 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. Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline <untitled attachment> |
From: Valerio S. <val...@gm...> - 2024-07-25 10:38:05
|
Hi Philippe, thanks a lot for your explanations. I'm quite aware of the limitations of the G2++ model when used to price CMS related instruments but we use it for "risk management" purposes (if this is an excuse) rather than for P&L purposes. Therefore, the choice of the model has been made essentially for simplicity reasons. Having said that, I'll start delving into the implementations of the model ported to Python and see if I can find some workaround. P.S.: I just noticed that I wrongly quoted Peter Casper in my first email, so I added it in the recipients of this email. I hope this doesn't bother you Peter and does not go against the mailing list's rules. Best, Valerio Il giorno mer 24 lug 2024 alle ore 15:47 Philippe Hatstadt < pha...@ma...> ha scritto: > Sorry, this is the thread I am referring to. > https://sourceforge.net/p/quantlib/mailman/message/58733701/ > > Essentially, there is a working Python calibration routine for G2++. > However, certain process C++ classes were not 100% migrated to Python and > they currently do not work, as there is a mismatch in required parameters > (curve handle missing for instance). > So it's not clear how to generate paths of CMS rates from the calibrated > engine, as the processes cannot be called. > Using a 2-factor HW is not something I would spend time on if the goal is > to price CMS spread options, or any contingent payoff that depends on short > versus longer tenors, as HW2F is still a short rate model, and it is not > capable of substantially decorrelating say CMS2Y versus CMS10Y. The latter > is essential to build GNMA prepayment and OAS models, so HW2F would clearly > underprice the (negative) convexity. > Your product is a CMS steepener, so I think it may suffer form the same > issues. I guess what I'm saying is that I am unsure that there is any > Python way of doing this with QL for claims that depend on dual CMS tenors. > Luigi had asked me if I could help finish the G2++ processes to work in > Python, but I don't really have the bandwidth. it would be nice if someone > did it at some point. > > Best regards Philippe Hatstadt 203-252-0408 > https://www.linkedin.com/in/philippe-hatstadt/ > > On Jul 24, 2024, at 8:51 AM, Valerio Santaniello < > val...@gm...> wrote: > > > Hi Philippe, > > which class are you referring to? I read in this > <https://sourceforge.net/p/quantlib/mailman/quantlib-users/thread/OF5FBC4935.9C0A60CB-ONC1257729.00341421-C1257729.00357A0E%40wgz-bank.de/#msg25312187> > thread that @PeterCasper had a working code to price CMS Spread Options > with HW2F model, which would be very helpful to start thinking about a > workaround. > > Best, > Valerio > > Il giorno mer 24 lug 2024 alle ore 11:47 Philippe Hatstadt < > phi...@ex...> ha scritto: > >> As far as I know, the G2++ engine only has a C++ calibration >> implementation. Lack of a Python interface for it was a show stopper for me >> but if that doesn’t stop you then you might be able to price CMS steepeners >> at least via MC form the engine although I am unsure if that exists in >> Python either. >> >> Regards >> >> Philippe Hatstadt >> +1-203-252-0408 >> >> >> > On Jul 24, 2024, at 4:34 AM, Valerio Santaniello < >> val...@gm...> wrote: >> > >> > >> > Hi, >> > >> > I am trying to price CMS Steepeners Bonds with a G2++ model in QuantLib >> Python. I looked at the pricers available, but it seems that the only >> option would be to build a CMSSpreadLeg and use the >> lognormalCMSSpreadPricer, which does not appear to implement the G2++ >> model. Am I right or is there something I am missing? >> > >> > Best, >> > Valerio >> > _______________________________________________ >> > QuantLib-users mailing list >> > Qua...@li... >> > https://lists.sourceforge.net/lists/listinfo/quantlib-users >> >> -- >> >> >> 31 East 32nd Street, 3rd Floor | New York, NY | 10016 >> >> >> <https://www.exosfinancial.com/> >> <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. >> > Content-Type: text/plain; charset="us-ascii" > MIME-Version: 1.0 > Content-Transfer-Encoding: 7bit > Content-Disposition: inline > <untitled attachment> > > > |
From: Philippe H. <pha...@ma...> - 2024-07-24 13:47:57
|
Sorry, this is the thread I am referring to. https://sourceforge.net/p/quantlib/mailman/message/58733701/ Essentially, there is a working Python calibration routine for G2++. However, certain process C++ classes were not 100% migrated to Python and they currently do not work, as there is a mismatch in required parameters (curve handle missing for instance). So it's not clear how to generate paths of CMS rates from the calibrated engine, as the processes cannot be called. Using a 2-factor HW is not something I would spend time on if the goal is to price CMS spread options, or any contingent payoff that depends on short versus longer tenors, as HW2F is still a short rate model, and it is not capable of substantially decorrelating say CMS2Y versus CMS10Y. The latter is essential to build GNMA prepayment and OAS models, so HW2F would clearly underprice the (negative) convexity. Your product is a CMS steepener, so I think it may suffer form the same issues. I guess what I'm saying is that I am unsure that there is any Python way of doing this with QL for claims that depend on dual CMS tenors. Luigi had asked me if I could help finish the G2++ processes to work in Python, but I don't really have the bandwidth. it would be nice if someone did it at some point. Best regards Philippe Hatstadt 203-252-0408 https://www.linkedin.com/in/philippe-hatstadt/ On Jul 24, 2024, at 8:51 AM, Valerio Santaniello <val...@gm...> wrote: Hi Philippe, which class are you referring to? I read in this thread that @PeterCasper had a working code to price CMS Spread Options with HW2F model, which would be very helpful to start thinking about a workaround. Best, Valerio Il giorno mer 24 lug 2024 alle ore 11:47 Philippe Hatstadt < phi...@ex... > ha scritto: As far as I know, the G2++ engine only has a C++ calibration implementation. Lack of a Python interface for it was a show stopper for me but if that doesn’t stop you then you might be able to price CMS steepeners at least via MC form the engine although I am unsure if that exists in Python either. Regards Philippe Hatstadt +1-203-252-0408 > On Jul 24, 2024, at 4:34 AM, Valerio Santaniello < val...@gm... > wrote: > > > Hi, > > I am trying to price CMS Steepeners Bonds with a G2++ model in QuantLib Python. I looked at the pricers available, but it seems that the only option would be to build a CMSSpreadLeg and use the lognormalCMSSpreadPricer, which does not appear to implement the G2++ model. Am I right or is there something I am missing? > > Best, > Valerio > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users -- 31 East 32nd Street, 3rd Floor | New York, NY | 10016 < https://www.exosfinancial.com/ > < 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. Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline <untitled attachment> |
From: Valerio S. <val...@gm...> - 2024-07-24 12:50:26
|
Hi Philippe, which class are you referring to? I read in this <https://sourceforge.net/p/quantlib/mailman/quantlib-users/thread/OF5FBC4935.9C0A60CB-ONC1257729.00341421-C1257729.00357A0E%40wgz-bank.de/#msg25312187> thread that @PeterCasper had a working code to price CMS Spread Options with HW2F model, which would be very helpful to start thinking about a workaround. Best, Valerio Il giorno mer 24 lug 2024 alle ore 11:47 Philippe Hatstadt < phi...@ex...> ha scritto: > As far as I know, the G2++ engine only has a C++ calibration > implementation. Lack of a Python interface for it was a show stopper for me > but if that doesn’t stop you then you might be able to price CMS steepeners > at least via MC form the engine although I am unsure if that exists in > Python either. > > Regards > > Philippe Hatstadt > +1-203-252-0408 > > > > On Jul 24, 2024, at 4:34 AM, Valerio Santaniello < > val...@gm...> wrote: > > > > > > Hi, > > > > I am trying to price CMS Steepeners Bonds with a G2++ model in QuantLib > Python. I looked at the pricers available, but it seems that the only > option would be to build a CMSSpreadLeg and use the > lognormalCMSSpreadPricer, which does not appear to implement the G2++ > model. Am I right or is there something I am missing? > > > > Best, > > Valerio > > _______________________________________________ > > QuantLib-users mailing list > > Qua...@li... > > https://lists.sourceforge.net/lists/listinfo/quantlib-users > > -- > > > 31 East 32nd Street, 3rd Floor | New York, NY | 10016 > > > <https://www.exosfinancial.com/> > <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. > |
From: Philippe H. <phi...@ex...> - 2024-07-24 11:33:37
|
As far as I know, the G2++ engine only has a C++ calibration implementation. Lack of a Python interface for it was a show stopper for me but if that doesn’t stop you then you might be able to price CMS steepeners at least via MC form the engine although I am unsure if that exists in Python either. Regards Philippe Hatstadt +1-203-252-0408 > On Jul 24, 2024, at 4:34 AM, Valerio Santaniello <val...@gm...> wrote: > > > Hi, > > I am trying to price CMS Steepeners Bonds with a G2++ model in QuantLib Python. I looked at the pricers available, but it seems that the only option would be to build a CMSSpreadLeg and use the lognormalCMSSpreadPricer, which does not appear to implement the G2++ model. Am I right or is there something I am missing? > > Best, > Valerio > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users -- 31 East 32nd Street, 3rd Floor | New York, NY | 10016 <https://www.exosfinancial.com/> <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. |
From: Valerio S. <val...@gm...> - 2024-07-24 08:32:59
|
Hi, I am trying to price CMS Steepeners Bonds with a G2++ model in QuantLib Python. I looked at the pricers available, but it seems that the only option would be to build a CMSSpreadLeg and use the lognormalCMSSpreadPricer, which does not appear to implement the G2++ model. Am I right or is there something I am missing? Best, Valerio |
From: Luigi B. <lui...@gm...> - 2024-07-23 10:53:35
|
Hello—no, it's not in QuantLib yet. I described a workaround in https://www.implementingquantlib.com/2021/10/libor-fallback-calculation.html which is a bit out of date, as it mentions a couple of outstanding issues that were since solved; the accrual calculation has been correct for quite a while, and as of the latest release (1.35) the overnight coupon can also manage lookback days, lockout days and observation shifts. Hope this helps, Luigi On Sun, Jul 21, 2024 at 5:41 PM Quant <qua...@gm...> wrote: > Hi QuantLib Users, > > I just want to check if the Libor-fallback pricer below was actually > implemented in any version of QuantLib: > > https://github.com/lballabio/QuantLib/issues/1075 > > I am asking because I can not find it in the latest version 1.34. @Peter > Caspers <pca...@gm...> it seems you were running with this some > few years ago. > > Thanks & regards, > NK > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users > |
From: Luigi B. <lui...@gm...> - 2024-07-23 07:38:39
|
QuantLib 1.35 is available for download at < https://www.quantlib.org/download.shtml>; precompiled binaries are also available from PyPI and NuGet for Python and C# respectively. The list of changes for this release is at < https://www.quantlib.org/reference/history.html>. If you have any problems with this release, please report them here on the QuantLib mailing list (<qua...@li...>), or open a GitHub issue at <https://github.com/lballabio/quantlib/issues>. |
From: Quant <qua...@gm...> - 2024-07-21 15:38:42
|
Hi QuantLib Users, I just want to check if the Libor-fallback pricer below was actually implemented in any version of QuantLib: https://github.com/lballabio/QuantLib/issues/1075 I am asking because I can not find it in the latest version 1.34. @Peter Caspers <pca...@gm...> it seems you were running with this some few years ago. Thanks & regards, NK |