-3
$\begingroup$

are there any existing python modules that can calculate Modified and/or Macauley Duration of a bond.

$\endgroup$
2
$\begingroup$

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
| improve this answer | |
$\endgroup$
  • $\begingroup$ You have an error in your calculation your range function should start in 1 but because you are iterating in an array this will cause index out of range, when you say cfs[i]*i should be * (i+1) because the first i is 0 and you are loosing then the first number the same in your power method $\endgroup$ – Alejandro Serret Oct 13 '17 at 22:47
1
$\begingroup$

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.

| improve this answer | |
$\endgroup$
1
$\begingroup$
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
| improve this answer | |
$\endgroup$
1
$\begingroup$

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)
| improve this answer | |
$\endgroup$
  • $\begingroup$ Very nice. But your input definitions seem somewhat non-standard, for example coupon rate is usually expressed "per year", not "per period". $\endgroup$ – Alex C Dec 3 '19 at 18:36
  • 1
    $\begingroup$ I agree, but I wanted to stay consistent with "Investment Science" by Luenberger. He flips the usage of "yield to maturity" using "lambda", and using "yield per period" using "y" as in the formula. You have to adjust mbudda's formula by dividing by semi-annual ((i+1)/2) or dividing his final result by 2 to get the same duration calculations as the explicit formulas. In this manner I thought it would be best to have the individual supply with their payment structure upfront. $\endgroup$ – the775 Dec 3 '19 at 18:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.