Quantitative Finance Stack Exchange is a question and answer site for finance professionals and academics. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer

In teaching myself about bonds, I am writing some software, one piece of which will calculate the maturity of a bond given the yield curve as a function and a requested duration. The tricky part is that duration depends on interest rates, and the interest rate depends (through the yield curve) on maturity, which depends on duration. That part is working fine for reasonable durations and interest rates, albeit somewhat slowly, simply by iterating back and forth between calculating maturity and calculating interest rates, until a solution is settled upon.

However, another function is supposed to generate a portfolio of such bonds by calling the former function, given an average duration and a std. dev. of the duration of the bonds in the portfolio. Now the paradigm breaks down, since the generator will occasionally request durations greater than the maximum duration of the bond itself. The easiest fix for both functions is to calculate an approximate maximum duration and avoid duration requests that are beyond that limit.

My understanding of maximum duration is somewhat limited, except to say that the duration-maturity relationship is inverted-U shaped and generally not amenable to closed-form solutions. I have only been able to locate one paper on the subject, which is for below-par bonds only. Gross approximations are fine; I just need to be in the ballpark for this application. But closed-form solutions are essential since this check will be run on every bond created (and if I simulate I may create thousands or more over time).

share|improve this question
Are these actual bonds for which you are calculating durations? How do you not know the maturity exactly? Maturity and coupon are the basic inputs to any bond pricing algorithm, from which you calculate yield-to-maturity then duration. It may be helpful if you elaborate on the specific intended problem/application for this algorithm. – Tal Fishman Aug 9 '11 at 3:06
These aren't actual bonds. This is portfolio generation, which is why working backwards is required. The idea is that you given that you already have a collection of (n-1) bonds in a portfolio with duration d and a target portfolio duration D, what is the maturity of the $n^{th}$ bond you should purchase to move the new d to D. – Ari B. Friedman Aug 9 '11 at 8:16
up vote 5 down vote accepted

After struggling through the Pianca paper due to its poor proofing ($F$ is never defined but appears to be face value, and $n$ is implied to be the number of periods remaining but is instead maturity), I seem to have it worked out.

Using the lambertW function in gsl, I have it replicated in R:

# Estimate duration using various closed-form formulae
# Equations 5,6, and 11 in Pianca "Maximum duration of below-par bonds: A closed-form formula"
# Assumptions: flat yield curve, constant coupon, reimbursement value = face value
# r = C/F, or the coupon rate (F is face value, C is dollar value of coupons)
# i = applicable interest rate
# n = maturity date,
# type = "pianca", "macaulay", or "hawawini"
# At par, (i==r)
findDur_ClosedForm <- function(r,i,n,type="pianca") {
  type <- tolower(type)
  ani <- NA # For hawawini: Need pv of an n-period annuity at rate i
    pianca = 1 + (1/i) + ( n*(i-r) - (1+i) )/( r*( (1+i)^n - 1 ) + i ) ,
    macaulay = 1 + 1/i - ( (1+i)/r + n*(1+1/r-(1+i)/r ) ) / ( (1+i)^n - 1 - 1/r + (1+i)/r ) ,
    hawawini = ( (1+i)*ani*r + n*(i-r)(1+i)^(-n) ) / ( r+(i-r)(1+i)^-n )

# Find maximum duration using closed-form formulae
# ... pass-alongs to findDur_ClosedForm
findMaxDur <- function(r,i,...) {
  # If above or at par, max duration is 1+1/i
  # Otherwise use Pianca formula
  asymptote <- 1+1/i
  if( i<=r ) { # At or above par
  } else { # Below par
    a <- i-r
    b <- log(1+i)
    n <- ( b*(1+i) + a*( 1 + lambert_W0( a*exp( -(a+b*(1+i))/a )/r ) ) ) / (a*b)
    return( findDur_ClosedForm(r=r,i=i,n=n) )

Ns <- seq(1,300,1)
Ds <- sapply( Ns, findDur_ClosedForm,r=.001,i=.05 )


# Numerical optimization from closed form
> max(Ds)
[1] 51.01994
# Maximum according to Pianca's paper
> findMaxDur(r=.001,i=.05)
[1] 51.01998

I have also confirmed through reading through the papers carefully and comparing to exact results that the closed form solutions are all estimates not exact.

share|improve this answer

If you're able to work with the results from the paper cited (Pianca, Maximum Duration of Below Par Bonds: A Closed-Form Formula), congratulations! You have the hard part done!

Maximum durations for par and premium bonds are trivial. Here is a figure directly from the cited paper:

enter image description here

Some points about the figure:

  • the market interest rate used is $i=10\%$
  • $1 + 1/i$ is the duration of a perpetual bond
  • except for the zero-coupon bond, as maturity increases, the durations of all bonds asymptotically approach that of the perpetual bond
  • the par and premium bonds ($r=10\%$ and $r=20\%$ both monotonically increase toward the duration of the perpetual bond as maturity increases

Thus, the maximum duration for par and above-par bonds is simply $1+1/i$, where $i$ is the market interest rate.

share|improve this answer
Thanks for this. I'm still sorting through all this, but in re-reading both the Pianca paper and the Hawawini paper I am starting to realize that my previous lack of progress on this issue results from my assumption that the closed-form formulae for duration were approximations. By contrast, Pianca seems to use them as though they are exact. I'll have to work through the derivations and figure out whether they are, in fact, exact. If so, I can likely avoid the whole iterative algorithm and just go directly from maturity to duration. – Ari B. Friedman Aug 9 '11 at 8:32

Your Answer


