Skip to content
All library documents

Reconciling Manual and QuantLib Forward Rates from Discount Factors

Article Quant Q&A · Author: ql.user2511

Summary

The document compares one-month forward rates computed by QuantLib with rates recomputed from discount factors on a zero curve. Its manual calculation uses the ratio of the discount factor at the forward period’s start to the factor at maturity, converts that ratio into a simple rate, and annualizes it using the stated year fraction. The example specifies a valuation date, zero rates, Actual/360 day counting, and compounded rate conventions.

The question reports small differences between the library output and the manual series, while the supplied answer repeats the calculation code and adds the zero-coupon rates to the plotted comparison. It does not explain the source of the discrepancies or establish that the two calculations should match under the selected compounding convention. The material is useful as a setup for comparing curve-derived forwards, but the central convention mismatch remains unresolved in the answer shown.

Key ideas

  • A forward rate can be derived from the ratio of discount factors at the period start and maturity.
  • The year fraction and compounding convention affect how a discount-factor ratio maps to a quoted forward rate.
  • The example compares a manual calculation with QuantLib output using a zero curve and Actual/360 day count.
  • The supplied answer repeats the computation but does not resolve the reported differences.

Tags

Full text
# SOLVED Manually Recomputing Forward Rates from QuantLib Python


# SOLVED Manually Recomputing Forward Rates from QuantLib Python












I have used QuantLib Python to compute 1-month forward rates from zero rates as at 05 December 2019.

My codes can be found below:

```
import QuantLib as ql

calendar = ql.NullCalendar()
compounding = ql.Compounded
day_convention = ql.Actual360()
valuation_date = ql.Date(5, 12, 2019)
ql.Settings.instance().evaluationDate = valuation_date
dates = [calendar.advance(valuation_date, ql.Period(n, ql.Years)) for n in range(0, 4, 1)]
zero_rates = [0.01, 0.02, 0.03, 0.05]
zero_curve = ql.ZeroCurve(dates, zero_rates, day_convention)
forward_term_structure = ql.YieldTermStructureHandle(zero_curve)
forward_term_structure.enableExtrapolation()
forward_rates_quantlib = []
value_dates = []
maturity_dates = []
discount_factor_value_dates = []
discount_factor_maturity_dates = []
year_frac_value_maturity_dates = []

for date in dates:
    value_date = date
    value_dates.append(value_date)
    maturity_date = date + ql.Period('1M')
    maturity_dates.append(maturity_date)
    forward_rate = forward_term_structure.forwardRate(value_date, maturity_date, day_convention, compounding).rate()
    forward_rates_quantlib.append(forward_rate)
    discount_factor_value_date = zero_curve.discount(value_date)
    discount_factor_value_dates.append(discount_factor_value_date)
    discount_factor_maturity_date = zero_curve.discount(maturity_date)
    discount_factor_maturity_dates.append(discount_factor_maturity_date)
    year_frac_value_maturity_date = day_convention.yearFraction(value_date, maturity_date)
    year_frac_value_maturity_dates.append(year_frac_value_maturity_date)
    
import pandas as pd
manual_calculation = pd.DataFrame()
manual_calculation['Value_Date'] = value_dates
manual_calculation['Discount_Factor_Value_Date'] = discount_factor_value_dates
manual_calculation['Maturity_Date'] = maturity_dates
manual_calculation['Discount_Factor_Maturity_Date'] = discount_factor_maturity_dates
manual_calculation['Year_Frac_Value_Maturity'] = year_frac_value_maturity_dates
manual_calculation['Forward_Rate_QuantLib'] = forward_rates_quantlib

forward_rates_manual = []

for i in range(0, len(manual_calculation), 1):
    df_value = manual_calculation.loc[i, 'Discount_Factor_Value_Date']
    df_mat = manual_calculation.loc[i, 'Discount_Factor_Maturity_Date']
    year_frac = manual_calculation.loc[i, 'Year_Frac_Value_Maturity']
    forward_rates_manual.append(((df_value/df_mat) - 1) * (1/year_frac))
    
manual_calculation['Forward_Rate_Manual'] = forward_rates_manual

import matplotlib.pyplot as plt  
plt.plot(zero_rates, 'o-', label = "Spot")
plt.plot(forward_rates, 'o-', label = "1M Forward (QuantLib)")
plt.plot(forward_rates_manual, 'o-', label = "1M Forward (Manual)")
plt.legend()
```

As can be seen from the list `forward_rates_manual`, I have tried to recompute the 1-month forward rates manually using the following formula:

where

means discount factor from value date to valuation date

means discount factor from maturity date to valuation date, where maturity date is value date plus 1 month, and

means the year fraction between value date and maturity date.

However, when I compare `forward_rates_quantlib` with `forward_rates_manual`, I can see slight differences arising, and I cannot seem to understand where these come from.

Grateful for any clarification, thanks.

## Answer by user68989 (score -1)

https://quant.stackexchange.com/a/76703

```
import QuantLib as ql

calendar = ql.NullCalendar()
compounding = ql.Compounded
day_convention = ql.Actual360()
valuation_date = ql.Date(5, 12, 2019)
ql.Settings.instance().evaluationDate = valuation_date
dates = [calendar.advance(valuation_date, ql.Period(n, ql.Years)) for n in range(0, 4, 1)]
zero_rates = [0.01, 0.02, 0.03, 0.05]
zero_curve = ql.ZeroCurve(dates, zero_rates, day_convention)
forward_term_structure = ql.YieldTermStructureHandle(zero_curve)
forward_term_structure.enableExtrapolation()
forward_rates_quantlib = []
value_dates = []
maturity_dates = []
discount_factor_value_dates = []
discount_factor_maturity_dates = []
year_frac_value_maturity_dates = []

for date in dates:
    value_date = date
    value_dates.append(value_date)
    maturity_date = date + ql.Period('1M')
    maturity_dates.append(maturity_date)
    forward_rate = forward_term_structure.forwardRate(value_date, maturity_date, day_convention, compounding).rate()
    forward_rates_quantlib.append(forward_rate)
    discount_factor_value_date = zero_curve.discount(value_date)
    discount_factor_value_dates.append(discount_factor_value_date)
    discount_factor_maturity_date = zero_curve.discount(maturity_date)
    discount_factor_maturity_dates.append(discount_factor_maturity_date)
    year_frac_value_maturity_date = day_convention.yearFraction(value_date, maturity_date)
    year_frac_value_maturity_dates.append(year_frac_value_maturity_date)

import pandas as pd

manual_calculation = pd.DataFrame()
manual_calculation['Value_Date'] = value_dates
manual_calculation['Discount_Factor_Value_Date'] = discount_factor_value_dates
manual_calculation['Maturity_Date'] = maturity_dates
manual_calculation['Discount_Factor_Maturity_Date'] = discount_factor_maturity_dates
manual_calculation['Year_Frac_Value_Maturity'] = year_frac_value_maturity_dates
manual_calculation['Forward_Rate_QuantLib'] = forward_rates_quantlib
manual_calculation['ZC'] = zero_rates

forward_rates_manual = []

for i in range(0, len(manual_calculation), 1):
    df_value = manual_calculation.loc[i, 'Discount_Factor_Value_Date']
    df_mat = manual_calculation.loc[i, 'Discount_Factor_Maturity_Date']
    year_frac = manual_calculation.loc[i, 'Year_Frac_Value_Maturity']
    forward_rates_manual.append(((df_value / df_mat) - 1) * (1 / year_frac))

manual_calculation['Forward_Rate_Manual'] = forward_rates_manual
manual_calculation= manual_calculation.set_index('Value_Date')
import matplotlib.pyplot as plt

manual_calculation[['ZC','Forward_Rate_Manual','Forward_Rate_QuantLib']].plot()
plt.legend()
plt.show()
```

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.