-2
$\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
$\endgroup$
1
  • 1
    $\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$ 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.

$\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
$\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)
$\endgroup$
2
  • $\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$ Dec 3 '19 at 18:57
0
$\begingroup$

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.

$\endgroup$

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.