Pricing - Zero Coupon Bonds#

In this page we cover the technical aspect of the pricing for zero coupon bonds.

The main public API to revaluate the price of a bond price can be imported from fift_analytics as:

In [1]: from fift_analytics.gilts.zero_coupon import get_zero_coupon_gilt_price

get_zero_coupon_gilt_price#

Input Parameters:

  • Face Value \(( F )\): The maturity value of the bond.

  • Annual Yield \(( r )\): The annual yield to maturity as a decimal (e.g., 0.04 for 4%).

  • Maturity Date: The date when the bond matures.

  • Settlement Date: The date when the bond is settled (defaults to today if not provided).

Calculate Time to Maturity:

Calculate the number of days between the settlement date and the maturity date. Convert this to years using the Actual/Actual (ISMA) day count convention.

\[Time to Maturity = \frac{\text{Days to Maturity}}{\text{Year Length}}\]

Where:

\[\text{Days to Maturity} = \text{Maturity Date} - \text{Settlement Date} \text{Year Length} = 365 \text{ or } 366 \text{ (depending on leap year)}\]

Compute Price Using Continuous Compounding:

Use the continuous compounding formula to calculate the bond price.

\[P = F \cdot e^{-r \cdot t}\]

Where:

\(( P )\) is the present price of the bond. \(( F )\) is the face value of the bond. \(( r )\) is the annual yield to maturity. \(( t )\) is the time to maturity in years.

In [2]: import math

In [3]: face_value = 100

In [4]: annual_yield = 0.03

In [5]: time_to_maturity = 0.5

In [6]: present_value = face_value * math.exp(-annual_yield * time_to_maturity)

In [7]: print(round(present_value, 2))
98.51

Handle Edge Cases#

If the time to maturity is very small (approaching zero), return the face value directly.

In [8]: import math

In [9]: face_value = 100

In [10]: annual_yield = 0.03

In [11]: time_to_maturity = 3 / 365

In [12]: present_value = face_value * math.exp(-annual_yield * time_to_maturity)

In [13]: print(round(present_value, 2))
99.98

Example Calculation#

Let's go through an example:

  • Face Value: £1,000

  • Annual Yield: 4% (0.04)

  • Maturity Date: 2025-02-19

  • Settlement Date: 2025-02-16

Calculate Time to Maturity:

Days to Maturity:

In [14]: from datetime import datetime

In [15]: datetime(2025, 2, 20) - datetime(2025, 2, 17)
Out[15]: datetime.timedelta(days=3)

If we assume it's not a leap year, the year Length is 365,

Time to Maturity:

\[\frac{3}{365} \approx 0.0082 \text{ years}\]
In [16]: (datetime(2025, 2, 20) - datetime(2025, 2, 17)).days / 365
Out[16]: 0.00821917808219178

Compute Price:

Using the continuous compounding formula:

\[P = 1000 \cdot e^{-0.04 \cdot 0.0082} \approx 1000 \cdot e^{-0.000328} \approx 1000 \cdot 0.999672 \approx 999.67\]
In [17]: time_to_maturity = (datetime(2025, 2, 20) - datetime(2025, 2, 17)).days / 365

In [18]: print(f"The time to maturity is {time_to_maturity}")
The time to maturity is 0.00821917808219178

In [19]: exp_factor = -0.04 * time_to_maturity

In [20]: print(exp_factor)
-0.0003287671232876712

In [21]: exp_value = math.exp(exp_factor)

In [22]: print(exp_value)
0.9996712869147009

In [23]: face_value = 1000

In [24]: reval_price = round(face_value * exp_value, 2)

In [25]: print(f"The theoretical price of the zero-coupon gilt is £{reval_price}")
The theoretical price of the zero-coupon gilt is £999.67