Calculating Macaulay and Modified Bond Duration in Python
Summary
The document collects approaches for computing Macaulay and modified duration from a bond’s cash flows. One method discounts each payment using its period-specific rate, weights the payment time by its present value, and divides by the bond price; modified duration is then obtained by adjusting Macaulay duration for yield and payment frequency. Other replies give explicit formulas for regular coupon bonds, including a special case when coupon rate and yield match, and a continuous-compounding example that calculates present value and duration from dated payments.
The examples illustrate that duration can be calculated from cash flows or through a closed-form expression, and that irregular payment dates may require a more flexible cash-flow representation. The examples are not a unified library or a full treatment of conventions: compounding, yield units, payment timing, and day-count assumptions must match the bond being valued. One reply points to a commercial analytics product, which is a recommendation rather than evidence about calculation accuracy.
Key ideas
- Macaulay duration weights each cash-flow time by its discounted value relative to bond price.
- Modified duration adjusts Macaulay duration for yield and the coupon payment convention.
- Explicit formulas can simplify calculations for regular coupon bonds and include a special case when coupon rate equals yield.
- Irregular payment dates require cash-flow timing details that simple regular-period formulas may not represent.
- Compounding and rate conventions must be consistent with the bond valuation setup.
Tags
Full text
# Modified or Macauley Duration in python
# Modified or Macauley Duration in python
are there any existing python modules that can calculate Modified and/or Macauley Duration of a bond.
## Answer by mbudda (score 2)
https://quant.stackexchange.com/a/21611
I calculate duration in Python using numpy, it's nice and simple:
```
def durations(cfs, rates, price, ytm, no_coupons, payments_per_year=2):
import numpy as np
mac_dur = np.sum([cfs[i]*((i+1)/payments_per_year)/np.power(1+rates[i],i+1) for i in range(len(cfs))])/price
mod_dur = mac_dur/(1+ytm/no_coupons)
return mac_dur, mod_dur
```
## Answer by kevin_theinfinityfund (score 2)
https://quant.stackexchange.com/a/50074
Example: Consider a 7% bond with 3 years to maturity. Assume bond is selling at 8% yield.
Most concise function for explicit formulas:
```
def durations_explicit(c, y, m, n):
macaulay_duration = ((1+y) / (m*y)) - ( (1 + y + n*(c-y)) / ((m*c* ((1+y)**n - 1)) + m*y) )
modified_duration = macaulay_duration / (1 + y)
return macaulay_duration, modified_duration
durations_explicit(c=.035, y=.04, m=2, n=6)
(2.75371702450442, 2.6478048312542497)
```
For a more complete answer with docstrings and accounting for the case when coupon rate per period equals yield per period
```
def durations_explicit(c, y, m, n):
"""Parameters:
c = coupon rate per period
y = yield per period
m = periods per year
n = periods remaining"""
if c==y: # Shorter explicit formula if coupon rate per period = yield per period
macaulay_duration = ((1+y)/(m*y))*(1 - (1 / (1+y)**n))
modified_duration = macaulay_duration / (1 + y)
print(f"Macaulay Duration: {macaulay_duration}")
print(f"Modified Duration: {modified_duration}")
return macaulay_duration, modified_duration
else:
macaulay_duration = ((1+y) / (m*y)) - ( (1 + y + n*(c-y)) / ((m*c* ((1+y)**n - 1)) + m*y) )
modified_duration = macaulay_duration / (1 + y)
print(f"Macaulay Duration: {macaulay_duration}")
print(f"Modified Duration: {modified_duration}")
return macaulay_duration, modified_duration
durations_explicit(c=.035, y=.04, m=2, n=6)
Macaulay Duration: 2.75371702450442
Modified Duration: 2.6478048312542497
(2.75371702450442, 2.6478048312542497)
```
## Answer by Phil H (score 1)
https://quant.stackexchange.com/a/15607
Go talk to Fincad. Here is their page on integrating with scripting languages:
http://www.fincad.com/news-events/assets/pdfs/mar07/using-fincad-developer-scripting-languages.pdf
Their analytics libraries include bond analytics, and they have a spreadsheet product so you can test methods and results before implementing them.
Disclaimer: I work for a company who is a customer of Fincad's analytics.
## Answer by Tural Valiyev (score 1)
https://quant.stackexchange.com/a/43275
```
You can use my script:def Duration (timetomaturity,nominalvalue,yieldrate,couponrate): import math as m yld=yieldrate/100 cpnr=couponrate/100 t=list(range(1,timetomaturity+1)) cfi=nominalvalue*cpnr cfN=nominalvalue*cpnr+nominalvalue cfl=[cfi]*(len(t)-1)+[cfN] B=0 # B is the bond's present value for k in range(0,timetomaturity): B=B+cfl[k]*(m.exp(-yld*t[k])) D=0 # D is the duration for i in range(0,timetomaturity): D+=(t[i]*cfl[i]*m.exp(-yld*t[i]))/B return round(D,2),round(B,2)#Duration(5,100,1,1)#By Tural Valiyev
```
## Answer by Pythonista anonymous (score 0)
https://quant.stackexchange.com/a/61028
You can look at the answer I gave here: https://quant.stackexchange.com/a/61025/40827 which is based on potentially irregular cashflows. Ie you pass the exact dates or periods and amounts, you don't specify, say, a bond paying 5% every semester for the next 3 years.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.