# Bootstrapping Swap Curve

I am trying to get the zero rates from the swap curve for chilean pesos (vs Camara). I tried this code (from a previuos question similar to mine from other person) and I am very close to get the result. But somehow I always get a zero rate 1 to 2 basis points below the real zero rate. This is happening even on other indexes.

The result I get

The result I expect

Info about the index in case you don't know it

The code

fecha = "2020-09-30"

tasa_clp1 = (0.50,0.475,0.475,0.49,0.62,0.78,0.99,1.28,1.53,1.79,1.9,2.16,2.295,2.52,2.62)#list(tasa_clp.iloc[:,0])
#tasa_clf1 = list(tasa_clf.iloc[:,0])

def create_calendar_chile(start_year,n_years):
Chile = ql.WeekendsOnly()
days = [1]
months = [1]
name = ['Año Nuevo']
for i in range(n_years+1):
for x,y in zip(days,months):
date = ql.Date(x,y,start_year+i)
return Chile

def get_curve(date,swap,currency = 'CLP'):
calendar = create_calendar_chile(2020,50)
dayCounter_Act360 = ql.Actual360(includeLastDay=True)
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,12]
swap_month = swap[1:4]
years =[2,3,4,5,6,7,8,9,10,15,20]
swap_years = swap[4:]
helpers = [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(TPM/100)),
ql.Period(1,ql.Days), fixingDays,
calendar, ql.ModifiedFollowing, False, ql.Actual360(includeLastDay=False))]
else:
months = [3,6,12]
swap_month = swap[1:4]
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.ModifiedFollowing,
False,
ql.Actual360(includeLastDay=True))
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.PiecewiseLinearZero(date, helpers, ql.Actual360(includeLastDay=True))
icp_curve.enableExtrapolation()
return icp_curve
def print_zero(date,yieldcurve):
day_count = ql.Actual360(includeLastDay=True)
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.Compounded
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(int(fecha[8:]),int(fecha[5:7]),int(fecha[:4]))
ql.Settings.instance().evaluationDate = date_ql
swap_clp = tasa_clp1#[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, currency = 'CLP')
print_zero(date_ql,yieldcurve_clp)


• Why do you use a holiday calendar with weekends only? If I look at the fixing info (CLICP Index), it seems to observe the usual CL holiday calendar (e.g. from CDR on Bloomberg). Just curious - I doubt this affects the difference in zero rates you observe. – user42108 Oct 14 '20 at 16:39
• Because there is no calendar for Chile. So you have to create one, for simplicity I only added the new year as holiday, does not change really At least that's what I understand about the library until now – Ewald Stark Oct 16 '20 at 22:50
• Thanks, Ewald.- I need to create one myself for both Chile and Thailand (also missing in QLNet). – user42108 Oct 17 '20 at 15:40