Skip to content

Net present value and duration of a set of bonds

Course exercises 47–48 · Part I

Problem

Write a function that returns the net present value and the duration of several assets at once, given their cash flows on a common schedule and a non-flat rate curve (exercise 47). Apply it to four assets over five years (exercise 48).

Method

With cash flows in the rows of \(C\), payment dates \(t\) and evaluation date \(t_0\):

\[ v = (1 + \tilde{i})^{-(t - t_0)}, \qquad NPV = C\, v^\top, \qquad D = \frac{C\,\big((t - t_0) \circ v\big)^\top}{NPV} \]

Code

clear all, clc

% Point 1
    t_0 = 0;                    % by default
    t = 1:5;                    % schedule

    C = [7 7 7 7 107;           % flows matrix
         6 6 6 106 0;
         0 0 100 0 0;
         0 0 0 0 100];

    i_tilde = [.05, .046, .044, .049, .052]; % non-flat yield structure

    [NPV,D] = F_es47(t,t_0,C,i_tilde)
function [NPV, D] = F_es47(t, t_0, C, i_tilde)

% inputs:   t       := vector of the schedule
%           t_0     := (scalar) starting point of the investment
%           C       := mxn matrix of cash flows
%           i_tilde := non-flat interest rate curve
% outputs:  NPV     := Net Present Value
%           D       := Duration
% Refer to row vectors!

v = (1 + i_tilde).^(-(t - t_0));    % discount factor vector (t = payment date, t_0 = evaluation date)
NPV = C * v';                       % column vector: one net present value per asset (row of C)
D = (C * ((t - t_0) .* v)') ./ NPV;
end
import numpy as np
from F_es47 import F_es47               # uses the function in F_es47.py (same folder), like F_es47.m

# %% Point 1
t_0 = 0                                 # by default
t = np.arange(1, 6)                     # schedule: MATLAB 1:5

C = np.array([[7, 7, 7,   7, 107],      # flows matrix
              [6, 6, 6, 106,   0],
              [0, 0, 100, 0,   0],
              [0, 0, 0,   0, 100]])

i_tilde = np.array([.05, .046, .044, .049, .052])   # non-flat yield structure

NPV, D = F_es47(t, t_0, C, i_tilde)
print("NPV =", NPV)
print("D =", D)
import numpy as np


def F_es47(t, t_0, C, i_tilde):
    # inputs:   t       := vector of the schedule
    #           t_0     := (scalar) starting point of the investment
    #           C       := mxn matrix of cash flows (one row per asset)
    #           i_tilde := non-flat interest rate curve
    # outputs:  NPV     := Net Present Value
    #           D       := Duration

    v = (1 + i_tilde) ** (-(t - t_0))   # discount factor vector
    NPV = C @ v                         # one net present value per asset (row of C)
    D = (C @ ((t - t_0) * v)) / NPV

    return NPV, D                       # MATLAB: function [NPV, D] = ...

Results

Rate curve: 5.0%, 4.6%, 4.4%, 4.9%, 5.2% for years 1 to 5.

Asset Cash flows NPV Duration
7% bond, 5 years 7, 7, 7, 7, 107 108.04 4.41
6% bond, 4 years 6, 6, 6, 106 104.01 3.68
Zero-coupon, 3 years 100 at year 3 87.88 3.00
Zero-coupon, 5 years 100 at year 5 77.61 5.00

Takeaways

  • One matrix product values all the assets together: each row of \(C\) is an asset.
  • The zero-coupon bonds confirm the formula: their duration equals their maturity.
  • Higher coupons shorten duration, because more of the value arrives early.