2
$\begingroup$

After reviewing and fixing my last code (Swap Bootstrapping with quantlib), i managed to get the zero rates for the ICP swap curve (CLP). Now the thing is that there is a considerable difference between the rates shown in the Bloomberg swap bootstrapping an QL's results. Here is the updated 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 = []
    dates = []
    tenors = []
    df = []
    for d in yieldcurve.dates():
        yrs = day_count.yearFraction(date, d)
        df.append(yieldcurve.discount(d))
        dates.append(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 = {'Dates':dates,'Years': tenors,'DF':df,'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:

          DF               Dates      Years      Zero
0   1.000000  January 10th, 2018   0.000000  0.000000
1   0.999931  January 11th, 2018   0.002778  2.500000
2   0.993700    April 12th, 2018   0.255556  2.480773
3   0.987597     July 12th, 2018   0.508333  2.470668
4   0.981404  October 12th, 2018   0.763889  2.480488
5   0.974721  January 14th, 2019   1.025000  2.530187
6   0.961368     July 12th, 2019   1.522222  2.639855
7   0.944897  January 13th, 2020   2.036111  2.864088
8   0.908864  January 12th, 2021   3.050000  3.287675
9   0.871107  January 12th, 2022   4.063889  3.640960
10  0.833387  January 12th, 2023   5.077778  3.937202
11  0.793979  January 12th, 2024   6.091667  4.259577
12  0.755379  January 13th, 2025   7.111111  4.553990
13  0.717674  January 12th, 2026   8.122222  4.843389
14  0.681810  January 12th, 2027   9.136111  5.108135
15  0.646116  January 12th, 2028  10.150000  5.396163
16  0.506455  January 12th, 2033  15.225000  6.400718
17  0.386192  January 12th, 2038  20.297222  7.830561

BBG:

Start   End Days    Start Disc.Factor   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, deposit and ois rate helpers, but minimal changes occurred. Also hoped that changing the year fractions would have an impact but it didn't change significaly. Is there anything i could be missing?

Thanks,

$\endgroup$
  • 1
    $\begingroup$ Have you noticed that the BBG rates are quoted as Semi-annual from 2y onwards? $\endgroup$ – Phil H Jan 16 '18 at 14:01
  • $\begingroup$ Thats the swap payment frequency, but the rate is annual, if you transform the discount factors into rates you would get the same level. $\endgroup$ – Jose Pedro Melo Jan 16 '18 at 14:11
  • 1
    $\begingroup$ Something does not compute with your bloomberg output: a 20 year discount factor of 0.382045 would correspond to a zero rate of around 4.8%, not 7.9% $\endgroup$ – Antoine Conze Jan 16 '18 at 15:06
  • 1
    $\begingroup$ simple annualized rates on an act/360 basis would be R = (1/DF)^(360/days)-1 and the 20 years rate would not be 7.9% but would be 4.9%, also more in line with current markets. $\endgroup$ – Antoine Conze Jan 17 '18 at 7:49
  • 1
    $\begingroup$ deposit type rate type calculation is usually used only for maturities <= 1 year, but anyway what you want to compare are discount factors, or rates that you compute consistently in both outputs: for instance in your QL output QL probably computes a zero rate from t=0 to t=Maturity, whereas in BB you are applying a number of days that goes from t=spot date to t=Maturity. $\endgroup$ – Antoine Conze Jan 17 '18 at 13:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.