Bootstrapping Deposit Discount Factors with Staggered Start Dates
Summary
This note explains why manually calculated zero rates for two deposits may differ from a QuantLib piecewise linear zero curve. The key is that the deposits do not share the curve’s valuation date as their start: the overnight transaction runs over one day, while the three month deposit begins several days after the valuation date because of its fixing and settlement conventions. Its discount factor must therefore incorporate discounting from the valuation date to the deposit start as well as the deposit’s quoted simple interest over its accrual period.
The worked example uses a tomorrow next deposit and a three month STIBOR deposit, with actual/360 deposit accrual and an actual/365 zero curve. It derives the second zero rate by dividing the discount factor at the deposit start by the deposit’s simple interest growth factor, then annualizing the resulting continuous rate over the interval from start to maturity. The resulting rate matches the QuantLib output. The calculation depends on the stated calendars, dates, conventions, and day counts; other curve setups may require different dates or conventions.
Key ideas
- A deposit’s quoted rate accrues between its own start and end dates, which may differ from the curve valuation date.
- The discount factor at the deposit start must be included when deriving a later deposit’s zero rate.
- The example uses actual/360 for deposit accrual and actual/365 for continuous zero-rate annualization.
- Fixing, settlement, calendar, and business-day conventions determine the relevant deposit dates.
Tags
Full text
# How to calculate the discount factors for two deposits in an interest rate curve
# How to calculate the discount factors for two deposits in an interest rate curve
I am trying to calculate the zero rate for a piecewise linear zero curve. I have the following deposit on the short end
- STIBOR 1D, is identified as a tomorrow next deposit: 0.02416
- STIBOR 3 Month: 0.02701
I then use the very nice package QuantLib to find the continuous zero rates:
```
from datetime import datetime, date, timedelta
import pandas as pd
date_today = datetime(2022,12,30)
# Set the date today
ql_date_today = ql.Date(date_today.strftime("%Y-%m-%d"), "%Y-%m-%d") #
ql.Settings.instance().evaluationDate = ql_date_today
helpers = []
depositRates = [0.02416, 0.02701]
depositMaturities = ['1D', '3M']
calendar = ql.Sweden()
fixingDays = 2
endOfMonth = False
convention = ql.ModifiedFollowing
dayCounter = ql.Actual360()
for r,m in zip(depositRates, depositMaturities):
if m == '1D':
fixingDays = 1
convention = ql.Following
elif m == '3M':
convention = ql.Following
fixingDays = 2
helpers.append(ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(r)),
ql.Period(m),
fixingDays,
calendar,
convention,
endOfMonth,
dayCounter))
curve1 = ql.PiecewiseLinearZero(0, ql.TARGET(), helpers, ql.Actual365Fixed())
curve1.enableExtrapolation()
def ql_to_datetime(d):
return datetime(d.year(), d.month(), d.dayOfMonth())
def calc_days(maturity, date_now = date_today):
return (maturity-date_now).days
dates, rates = zip(*curve1.nodes())
dates = list(map(ql_to_datetime, dates))
days = list(map(calc_days, dates))
df = pd.DataFrame(dict({"Date": dates, "Rate": rates, "Days" : days}))
df
```
The result from QuantLib is:
| | Date | Rate | Days |
| 0 | 2022-12-30 00:00:00 | 0.0244947 | 0 |
| 1 | 2023-01-03 00:00:00 | 0.0244947 | 4 |
| 2 | 2023-04-03 00:00:00 | 0.027174 | 94 |
Now I wish to recreate the values that Quantlib produces, given that the curve is bootstrapped with actual 365. For the first deposit I use the simple rate, $DF = \frac{1}{1+RT}$, to calculate the discount factor (I also find it interesting that the daycount convention that gives the matching result to Quantlib is given by 1/360, when my intuition tells me it should be 4/360 given the maturity date):
$$ DF_1 = \frac{1}{1+0.02416 \cdot \frac{1}{360}} \approx 0.999932893 . $$
Then the continuous zero rate becomes:
$$ r_1 = -365/1 \cdot \ln (DF_1) \approx 0.02449473. $$
Moreover, if we continue with the second rate we obtain the following discount factor:
$$ DF_2 = \frac{0.999932893 }{1+0.02701 \cdot \frac{94}{360}} \approx 0.99293014. $$
At last the continuous zero rate for the second deposit is
$$ r_1 = -365/94 \cdot \ln (DF_2) \approx 0,02754960 . $$
Thus, the results that I get by calculating the zero rates manually for the second deposit does not really match QuantLib's result so I know I am doing my calculations wrong. I have tried to dig in the c++ source code in Quantlib with no success. I have also tried to change the maturity dates in the calculations but still I have not found a matching value for the deposits. I would be glad for any help or pointers.
## Answer by Xiarpedia (score 2, accepted)
https://quant.stackexchange.com/a/75100
I found the answer after extensive digging in this forum, particularly what gave me the answer was the following post How does bloomberg calculate the discount rate from EUR estr curve? [closed].
Thus, for the second deposit let $T_s$, $T_e$ denote the start and end of the deposit respectively. Then allow $t$ be the time of the you wish to calculate the discount factor. Given the holidays during 2022-12-30 we set $T_s = 4$ and $T_e = 94$. Further we consider $t = 0$. Then the solution we are after is given by:
$$ r_2 = -\frac{365}{T_e-T_s} \cdot \log ( \frac{DF(t,T_s)}{1+R \cdot (T_e - T_s)/360} ). $$
If we continue with calculating $DF(t, T_s)$ we obtain
$$ DF(t, T_s) = e^{(-r_1 \cdot (T_s -t) / 365)} = e^{(-r_1 \cdot (4 -0) / 365)} \approx 0.9997316. $$
Then the final result is
$$ r_2 = -\frac{365}{94-4} \cdot \log ( \frac{0.9997316}{1+0.02701 \cdot (94 - 4)/360} ) \approx 0.0271740. $$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.