Bootstrapping a Chilean Peso Overnight Swap Curve
Summary
The document presents a QuantLib setup for constructing a Chilean peso overnight indexed swap curve against the Camara reference. It supplies deposit quotes at short maturities and overnight swap quotes across longer maturities, then uses rate helpers and a piecewise-linear zero curve to infer discount factors and zero rates. The curve is configured with a Chilean calendar, an Actual/360 day count, settlement lags, and extrapolation beyond the last input date.
The author reports that calculated zero rates are one to two basis points below expected market values, including on other indexes, but the excerpt provides no diagnosis or confirmed correction. The code therefore serves as an implementation example and a troubleshooting question, not evidence that the convention choices are correct. Calendar holidays, quote units, helper conventions, evaluation date, and zero-rate compounding conversions all warrant checking against the relevant market specifications before relying on the output.
Key ideas
- The example bootstraps a zero curve from short deposits and longer overnight swap quotes.
- QuantLib rate helpers encode settlement, calendar, day-count, and business-day conventions.
- A piecewise-linear zero curve can be used to inspect discount factors and zero rates.
- Reported rates differ slightly from the author's expected values, but the cause is unresolved.
- Market conventions and compounding assumptions must match the instruments being modeled.
Tags
Full text
# Bootstrapping Swap Curve
# 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)
Chile.addHoliday(date)
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)
```Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.