QuantLib Ibor Forecasts: Compounding and Fixing Conventions
Summary
The document explains why a QuantLib Ibor forecast from a flat curve set to five percent does not return a five percent fixing. The curve uses continuous compounding by default, while the forecast fixing is a simply compounded rate over the index’s accrual period. Converting between these conventions produces a slightly different quoted rate. The sample output also varies slightly across dates because the relevant accrual periods differ.
The accepted answer suggests a flat curve with quarterly compounding as an approximation for quarterly fixings, while noting that it is not exact and other fixing tenors may require different compounding frequencies. Another answer outlines the forecast calculation from discount factors at the period’s start and end, explaining why a constant continuously compounded rate can still imply a different simple rate. The discussion distinguishes forecasting from manually adding historical fixings, which does not set future forecasts.
Key ideas
- A flat curve’s quoted rate depends on its compounding convention.
- QuantLib converts the continuously compounded curve rate into a simply compounded Ibor fixing over the accrual period.
- Different accrual dates can produce small differences in forecast fixings.
- Quarterly compounding can approximate quarterly fixings, but the result is not exact.
- Adding a historical fixing does not set a future forecast.
Tags
Full text
# Ibor Index with Flat Curve 5% not retrieving exact 5% fixings
# Ibor Index with Flat Curve 5% not retrieving exact 5% fixings
I have defined an Ibor Index with the python version of Quantlib using a Flat Forward Curve of 5%.
When I get an estimate for a date in 3 months from now, I would expect to get `0.0500000`, as I defined in the flat curve. However I get `0.050320809398634044` instead. I am perplexed to why this is...
```
import QuantLib as ql
calendar = ql.UnitedStates(ql.UnitedStates.FederalReserve)
usd_curve = ql.FlatForward(2, calendar,
0.05, ql.Actual360())
effectiveDate = ql.Settings.instance().evaluationDate
index = ql.IborIndex("LiborUSD", ql.Period("3m"),
2, ql.USDCurrency(), calendar,
ql.ModifiedFollowing, False,
ql.Actual360(),
ql.YieldTermStructureHandle(usd_curve))
for i in [3,6,9,12,15]:
print(index.fixing(
calendar.advance(effectiveDate, i, ql.Months, ql.ModifiedFollowing)
))
```
```
0.050320809398634044
0.050320809398634044
0.05031030503130324
0.05032080939863317
0.050320809398634044
```
## Answer by Luigi Ballabio (score 4, accepted)
https://quant.stackexchange.com/a/79261
You're creating a flat curve with a rate of 5% continously compounded, whereas the LIBOR fixing is a simply-compounded rate. You're getting the simple rate equivalent to a 5% continuously compounded rate over the relevant period; that is, the LIBOR rate $L$ so that $(1+Lt) = e^{rt}$, with $r$ being your 5% input and $t$ the 3-months period underlying the fixing.
I'm afraid there's no direct way to set the LIBOR fixing; the `addFixing` method suggested in the other answer works for past fixings, not for forecasting. You can get a result close to what you want by creating a flat, quarterly compounding curve:
```
usd_curve = ql.FlatForward(2, calendar, 0.05, ql.Actual360(), ql.Compounded, ql.Quarterly)
```
because the formulas happen to work out (if you want a 6-months fixing, you'll need `ql.Semiannual` and so on). It's not exact, but you'll be just a small fraction of basis point away from the 5% you want:
```
0.05000691632583292
0.050006916325834656
0.04999654231487185
0.05000691632583379
0.05000691632583292
```
## Answer by Xiarpedia (score 2)
https://quant.stackexchange.com/a/79259
When calling `index.fixing` you are actually calling the c++ method `IborIndex::forecastFixing` and given the date is in the future QuantLib will do the following calculation: $$(\frac{e^{-r_1 * t_1}}{e^{-r_2*t_2}} - 1)/(\frac{t_2 - t_1}{360}),$$
based on your inputs, where continuous compounding is set by default. Here $t_1$ will be given by
```
Date fixingDate = fixingCalendar().advance(valueDate,
-static_cast<Integer>(fixingDays_), Days);
```
and $t_2$ by
```
fixingCalendar().advance(fixingDate, fixingDays_, Days);
```
Thus the curve itself will be constant, i.e., $r_1 = r_2$ but the dates are different causing the effect you see in your calculations. If you'd like to set a fixing I'd suggest having a look at the method `setFixing`.
- FlatForward
- IborIndex
- InterestRateIndexShown 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.