From: Luigi B. <lui...@gm...> - 2018-03-29 07:34:19
|
Glad to hear it. Thanks! Luigi On Thu, Mar 29, 2018 at 2:04 AM Jose Pedro Melo <jm...@li...> wrote: > Finally, after many iterations, i found were was the problem. I changed > this part of the code: > > handle = ql.YieldTermStructureHandle() > helpers += > [ql.OISRateHelper(settlement_days_icp,ql.Period(months,ql.Months), > ql.QuoteHandle(ql.SimpleQuote(rate/100)),ICP,handle,False,0,ql.Following,ql.Monthly) > for rate, months in zip(swap_month,months)] > > helpers += > [ql.OISRateHelper(settlement_days_icp,ql.Period(years,ql.Years), > ql.QuoteHandle(ql.SimpleQuote(rate/100)),ICP,handle,False,0,ql.Following,ql.Semiannual) > for rate, years in zip(swap_years,years)] > > Seems like the OISRateHelper payment frequency was different than our ICP > swaps. This modification yields the close results to BBG bootsrapping: > > 0 0.000000 0.000000 > 1 0.008333 2.500000 > 2 0.261111 2.486395 > 3 0.513889 2.483810 > 4 0.769444 2.501550 > 5 1.025000 2.560555 > 6 1.527778 2.691903 > 7 2.038889 2.884934 > 8 3.061111 3.315383 > 9 4.072222 3.674813 > 10 5.083333 3.976807 > 11 6.097222 4.306079 > 12 7.113889 4.607043 > 13 8.127778 4.903621 > 14 9.147222 5.175711 > 15 10.158333 5.471312 > 16 15.233333 6.497894 > 17 20.308333 7.977794 > > Thanks to all for your time. I'll leave the complete code here for the > people interested: > > import QuantLib as ql > import pandas as pd > def create_calendar_chile(start_year,n_years): > Chile = ql.WeekendsOnly() > days = [1,14,15,1,21,26,2,16,15,18,19,9,27,1,19,8,17,25,31] > months = [1,4,4,5,5,6,8,9,9,10,10,11,12,12,12,12] > name = ['Año Nuevo','Viernes Santo','Sabado Santo','Dia del > Trabajo','Dia de las Glorias Navales','San Pedro y San Pablo','Elecciones > Primarias','Dia de la Virgen del Carmen','Asuncion de la > Virgen','Independencia Nacional','Glorias del Ejercito','Encuentro de dos > mundos','Día de las Iglesias Evangélicas y Protestantes','Día de todos los > Santos','Elecciones Presidenciales y Parlamentarias','Inmaculada > Concepción','Segunda vuelta Presidenciales','Navidad','Feriado Bancario'] > for i in range(n_years+1): > for x,y in zip(days,months): > date = ql.Date(x,y,start_year+i) > Chile.addHoliday(date) > return Chile > def get_curve(date,swap,currency = 'CLP'): > calendar = create_calendar_chile(2001,50) > dayCounter_Act360 = ql.Actual360() > settlement_days_icp = 2 > # OIS quotes up to 20 years > ICP = ql.OvernightIndex("ICP", settlement_days_icp, ql.CLPCurrency(), > calendar, dayCounter_Act360) > fixingDays = 0 > if currency == 'CLP': > # setup DepositRateHelper for 0-1 days > TPM = swap[0] > months = [3,6,9,12,18] > swap_month = swap[1:6] > years =[2,3,4,5,6,7,8,9,10,15,20] > swap_years = swap[6:] > helpers > =[ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(TPM/100)),ql.Period(1,ql.Days), > fixingDays,calendar, ql.Following, False,ql.Actual360())] > else: > months = [3,6,9,12] > swap_month = swap[0:3] > years =[2,3,4,5,6,7,8,9,10,15,20] > swap_years = swap[4:] > helpers = [] > > # setup OISRateHelper from 3 months to 20 years > #helpers > +=[ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(rate/100)),ql.Period(months,ql.Months),settlement_days_icp,calendar,ql.Following,False,ql.Actual360()) > for rate, months in zip(swap_month,months)] > handle = ql.YieldTermStructureHandle() > helpers += > [ql.OISRateHelper(settlement_days_icp,ql.Period(months,ql.Months), > ql.QuoteHandle(ql.SimpleQuote(rate/100)),ICP,handle,False,0,ql.Following,ql.Monthly) > for rate, months in zip(swap_month,months)] > helpers += > [ql.OISRateHelper(settlement_days_icp,ql.Period(years,ql.Years), > ql.QuoteHandle(ql.SimpleQuote(rate/100)),ICP,handle,False,0,ql.Following,ql.Semiannual) > for rate, years in zip(swap_years,years)] > icp_curve = ql.PiecewiseLogCubicDiscount(date, helpers, ql.Actual360()) > icp_curve.enableExtrapolation() > return icp_curve > def print_zero(date,yieldcurve): > day_count = ql.Actual360() > spots = [] > tenors = [] > for d in yieldcurve.dates(): > yrs = day_count.yearFraction(date, d) > print(yrs,d) > compounding = ql.Simple > freq = ql.Annual > zero_rate = yieldcurve.zeroRate(yrs, compounding, freq) > print(zero_rate) > > tenors.append(yrs) > eq_rate = > zero_rate.equivalentRate(day_count,compounding,freq,date,d).rate() > zero_rate.equivalentRate(day_count,compounding,freq,date,d).rate() > spots.append(100*eq_rate) > datatable = {'Years': tenors,'Zero': spots} > datatable = pd.DataFrame.from_dict(datatable) > print(datatable) > #Eval. Date > date_ql = ql.Date(12,1,2018) > ql.Settings.instance().evaluationDate = date_ql > swap_clp = [2.5, 2.48, 2.47, 2.48, 2.53, 2.64, 2.82, 3.17, 3.43, 3.62, > 3.81,3.96, 4.09, 4.19, 4.29, 4.45, 4.62] > yieldcurve_clp = get_curve(date_ql,swap_clp) > print_zero(date_ql,yieldcurve_clp) > > > ------------------------------ > *De:* Raul Muñoz <rm...@gm...> > *Enviado:* martes, 20 de marzo de 2018 03:22 a. m. > *Para:* Luigi Ballabio > *CC:* Jose Pedro Melo; qua...@li... > *Asunto:* Re: [Quantlib-users] Bootstraping difference between python > QuantLib and Bloomberg. > > Hi: > > You need to try: SWDF DFLT, with this comand you can see the defaults that > bbg is using (attached). Another thing that I didn't see in your code is > the spot lag. In chile the spot lag is t+2 (as usual) so that the > bootstrapp should match to all par values to t+2. And finally I suggest you > to match discount factors instead of rates. > > Best Regards, > > RAMR > > > > 2018-03-19 14:09 GMT-03:00 Luigi Ballabio <lui...@gm...>: > > I think there's still something we don't know about the way the Bloomberg > curve is built. For instance, in the first couple of rows of the Bloomberg > data you reported: > > 10-01-2018 11-01-2018 1 1,000069 ZERO 2,500 > 12-01-2018 12-04-2018 90 0,993838 ZERO 2,480 > > The first one has a positive rate, yet the discount factor is larger than > 1. I think this suggests that the curve has its reference date on the > 12th; but in your code you have to set it to the 10th in order to include > the first overnight rate, because our curve doesn't go before the > reference. > > Does anybody have any insights on this? > > Luigi > > > > On Sun, Feb 25, 2018 at 5:35 AM Jose Pedro Melo <jm...@li...> wrote: > > Unfortunately i haven't advance much. Why do i get different results when > i bootstrap the curve with the swap and OIS rate helpers? > > 2018-02-13 7:29 GMT-03:00 Luigi Ballabio <lui...@gm...>: > > Apologies for dropping the ball. Did you make any progress? > > Luigi > > > On Thu, Jan 25, 2018 at 6:41 PM Jose Pedro Melo <jm...@li...> wrote: > > Thanks for the fast response, > > I'm not sure which interpolation method Bbg uses, but i tried changing it > from cubic to linear in quantlib -PiecewiseLinearZero and > PiecewiseCubicZero- to check if that would help, without much success. In > the following table i changed both the interpolation method and the start > date: > > Start Date End Date DF Days Year Fraction Interpolation Output > 12/01/2018 12/01/2038 0.386246 7305 20.2916667 Cubic 7.830933 > 12/01/2018 12/01/2038 0.386246 7305 20.2916667 Linear 7.831006 > > I changed the settlement days to 0 in order to get the same starting > dates. For reference, i tried a basic bootstrapping spreadsheet i had and > i'm getting closer result to bloomberg's output. > > > El 24 ene. 2018 12:54 p. m., Luigi Ballabio <lui...@gm...> > escribió: > > To check that, you can try passing the spot date instead of today's date > to the curve. That should cause the start date to go to January 12. > > Apart from that, do you know what kind of interpolation Bloomberg uses? > That might have an effect too. > > > On Wed, Jan 24, 2018 at 4:48 PM Jose Pedro Melo <jm...@li...> wrote: > > I did the following comparison: > > Source Start Date End Date Days Disc. Factor Year Fraction > (1/df-1)*360/days Original Output > Quantlib 10/01/2018 12/01/2038 7307 0.386192 20.2972222 7.831% 7.831 > Bloomberg 12/01/2018 12/01/2038 7305 0.382045 20.2916667 7.971% 7.971 > > There is a small difference in the amount of days used to calculate the > rates. I don't know if these difference on start dates could have a > relevant impact in the bootsrapping algorithm. > > > 2018-01-24 12:13 GMT-03:00 Luigi Ballabio <lui...@gm...>: > > Did you try using the same formula, or comparing the discount factors > directly? (I'd try to understand if the difference is in the underlying > curve or in the equivalentRate calculation.) > > > > On Wed, Jan 24, 2018 at 4:06 PM Jose Pedro Melo <jm...@li...> wrote: > > Thanks for the response Luigi, > > The 'semiannual' tag appears only to show the swap original frequency. I > got the rates using the excel formula =BCurveInt(A1;"zc.mid";B1;"Frequency=Zero"), > where A1 is the curve bbg ID and B1 is the date for which you are getting > the rate. The formula behind the rates is (1/DF-1)*360/Days. > > > El 24 ene. 2018 11:45 a. m., "Luigi Ballabio" <lui...@gm...> > escribió: > > What is Bloomberg quoting, precisely? The "Semiannual" they're displaying > seems to go against the simple-compounding rate you're extracting... > > > On Mon, Jan 15, 2018 at 9:28 AM josepedro123 <jm...@li...> wrote: > > I'm trying to get the Zero rates implied by the swap CLP curve (ICP). The > following code works but it doesn't produce similar levels compared to > Bloomberg's Zero curve. Here is a snippet of the code: > > import QuantLib as ql > import pandas as pd > > def create_calendar_chile(start_year,n_years): > Chile = ql.WeekendsOnly() > days = [1,14,15,1,21,26,2,16,15,18,19,9,27,1,19,8,17,25,31] > months = [1,4,4,5,5,6,8,9,9,10,10,11,12,12,12,12] > name = ['Año Nuevo','Viernes Santo','Sabado Santo','Dia del > Trabajo','Dia de las Glorias Navales','San Pedro y San Pablo','Elecciones > Primarias','Dia de la Virgen del Carmen','Asuncion de la > Virgen','Independencia Nacional','Glorias del Ejercito','Encuentro de dos > mundos','Día de las Iglesias Evangélicas y Protestantes','Día de todos los > Santos','Elecciones Presidenciales y Parlamentarias','Inmaculada > Concepción','Segunda vuelta Presidenciales','Navidad','Feriado Bancario'] > for i in range(n_years+1): > for x,y in zip(days,months): > date = ql.Date(x,y,start_year+i) > Chile.addHoliday(date) > return Chile > def get_curve(date,swap,currency = 'CLP'): > calendar = create_calendar_chile(2001,50) > dayCounter_Act360 = ql.Actual360() > settlement_days_icp = 2 > # OIS quotes up to 20 years > ICP = ql.OvernightIndex("ICP", settlement_days_icp, ql.CLPCurrency(), > calendar, dayCounter_Act360) > fixingDays = 0 > > if currency == 'CLP': > # setup DepositRateHelper for 0-1 days > TPM = swap[0] > months = [3,6,9,12,18] > swap_month = swap[1:6] > years =[2,3,4,5,6,7,8,9,10,15,20] > swap_years = swap[6:] > helpers = > [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(TPM/100)), > ql.Period(1,ql.Days), fixingDays, > calendar, ql.Following, False, > ql.Actual360())] > else: > months = [3,6,9,12] > swap_month = swap[0:3] > years =[2,3,4,5,6,7,8,9,10,15,20] > swap_years = swap[4:] > helpers = [] > > > # setup OISRateHelper from 3 months to 20 years > helpers += > [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(rate/100)), > ql.Period(months,ql.Months), > settlement_days_icp, > calendar, > ql.Following, > False, > ql.Actual360()) > for rate, months in zip(swap_month,months)] > > #helpers += [ql.OISRateHelper(settlement_days_icp, > ql.Period(months,ql.Months), > # > ql.QuoteHandle(ql.SimpleQuote(rate/100)),ICP) > # for rate, months in > zip(swap_month,months)] > > helpers += [ql.OISRateHelper(settlement_days_icp, > ql.Period(years,ql.Years), > > ql.QuoteHandle(ql.SimpleQuote(rate/100)),ICP) > for rate, years in > zip(swap_years,years)] > > icp_curve = ql.PiecewiseCubicZero(date, helpers, ql.Actual360()) > icp_curve.enableExtrapolation() > return icp_curve > def print_zero(date,yieldcurve): > day_count = ql.Actual360() > spots = [] > tenors = [] > for d in yieldcurve.dates(): > yrs = day_count.yearFraction(date, d) > print(yrs,d) > compounding = ql.Simple > freq = ql.Annual > zero_rate = yieldcurve.zeroRate(yrs, compounding, freq) > tenors.append(yrs) > eq_rate = > zero_rate.equivalentRate(day_count,compounding,freq,date,d).rate() > zero_rate.equivalentRate(day_count,compounding,freq,date,d).rate() > spots.append(100*eq_rate) > > datatable = {'Years': tenors,'Zero': spots} > datatable = pd.DataFrame.from_dict(datatable) > print(datatable) > > #Eval. Date > date_ql = ql.Date(10,1,2018) > ql.Settings.instance().evaluationDate = date_ql > swap_clp = [2.5, 2.48, 2.47, 2.48, 2.53, 2.64, 2.82, 3.17, 3.43, 3.62, > 3.81, > 3.96, 4.09, 4.19, 4.29, 4.45, 4.62] > yieldcurve_clp = get_curve(date_ql,swap_clp) > print_zero(date_ql,yieldcurve_clp) > Results: > Years Zero > 0 0.000000 0.000000 > 1 0.002778 2.500000 > 2 0.255556 2.480773 > 3 0.508333 2.470668 > 4 0.763889 2.480488 > 5 1.025000 2.530187 > 6 1.522222 2.639855 > 7 2.036111 2.864088 > 8 3.050000 3.287675 > 9 4.063889 3.640960 > 10 5.077778 3.937202 > 11 6.091667 4.259577 > 12 7.111111 4.553990 > 13 8.122222 4.843389 > 14 9.136111 5.108135 > 15 10.150000 5.396163 > 16 15.225000 6.400718 > 17 20.297222 7.830561 > BBG: > Start End Days DF Frequency Zero > 10-01-2018 11-01-2018 1 1,000069 ZERO 2,500 > 12-01-2018 12-04-2018 90 0,993838 ZERO 2,480 > 12-01-2018 12-07-2018 181 0,987734 ZERO 2,470 > 12-01-2018 12-10-2018 273 0,981540 ZERO 2,480 > 12-01-2018 14-01-2019 367 0,974857 ZERO 2,530 > 12-01-2018 12-07-2019 546 0,961501 ZERO 2,640 > 12-01-2018 13-01-2020 731 0,944621 SEMIANNUAL 2,887 > 12-01-2018 12-01-2021 1096 0,908255 SEMIANNUAL 3,318 > 12-01-2018 12-01-2022 1461 0,870133 SEMIANNUAL 3,678 > 12-01-2018 12-01-2023 1826 0,832049 SEMIANNUAL 3,980 > 12-01-2018 12-01-2024 2191 0,792244 SEMIANNUAL 4,309 > 12-01-2018 13-01-2025 2558 0,753263 SEMIANNUAL 4,610 > 12-01-2018 12-01-2026 2922 0,715195 SEMIANNUAL 4,906 > 12-01-2018 12-01-2027 3287 0,679005 SEMIANNUAL 5,178 > 12-01-2018 12-01-2028 3652 0,642988 SEMIANNUAL 5,473 > 12-01-2018 12-01-2033 5479 0,502562 SEMIANNUAL 6,504 > 12-01-2018 12-01-2038 7305 0,382045 SEMIANNUAL 7,971 > > There is a +10 bp difference in the long term part. I tried using the swap > rate helpers and tweacking the days to get the same year fractions but it > doens't seem to be the problem. I wonder how is the oisratehelper > configurated (payment conventions, rates). Any ideas of where could be my > mistake? > Thanks, > > > > -- > Sent from: http://quantlib.10058.n7.nabble.com/quantlib-users-f3.html > > > ------------------------------------------------------------------------------ > Check out the vibrant tech community on one of the world's most > engaging tech sites, Slashdot.org! http://sdm.link/slashdot > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users > > > > > > > ------------------------------------------------------------------------------ > Check out the vibrant tech community on one of the world's most > engaging tech sites, Slashdot.org! http://sdm.link/slashdot > _______________________________________________ > QuantLib-users mailing list > Qua...@li... > https://lists.sourceforge.net/lists/listinfo/quantlib-users > > > |