0% found this document useful (0 votes)
17 views39 pages

Interest Rate Modeling

This document discusses interest rate modeling using MATLAB. It presents implementations of the Nelson-Siegel method and polynomial spline methods to estimate the term structure of interest rates from bond and money market data. The implementations allow fitting yield curves to coupon bond prices, Libor rates, and swap rates. The models' performances are evaluated based on computational costs and accuracy of the fitted curves.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views39 pages

Interest Rate Modeling

This document discusses interest rate modeling using MATLAB. It presents implementations of the Nelson-Siegel method and polynomial spline methods to estimate the term structure of interest rates from bond and money market data. The implementations allow fitting yield curves to coupon bond prices, Libor rates, and swap rates. The models' performances are evaluated based on computational costs and accuracy of the fitted curves.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 39

Interest Rate Modeling: A M ATLAB Implementation

Daniele Marazzina

SEMeQ Department, Università del Piemonte Orientale


Via Perrone 18, 28100 Novara, Italy
e-mail: daniele.marazzina@eco.unipmn.it

Avanade Italy
Corso Venezia 46, 20121 Milano, Italy
e-mail: danielema@avanade.com

Abstract

The aim of this work is to present a M ATLAB implementation of different methods for estimating the
term structure of interest rate. More precisely, we implement the exponential functional form of Nelson-
Siegel and polynomial spline methods (with or without penalty term), considering both coupon bonds,
like Italian Btp, and Libor and Swap interest rates. Furthermore, we compare the models’performances,
considering both computational costs and approximation results.

1 Introduction
An important tool in the development and testing of financial theory is the term structure of interest rate
as it provides a characterization of interest rates as a function of maturity. The yield curve, or term structure
of interest rate, is the set of interest rates for different investment periods or maturities. Yield curve can
display a wide variety of shapes. Typically, a yield curve will slope upwards, with longer term rates being
higher, although there are plenty of examples of inverted term structures where long rates are less then short
rates.
In the bond markets the yield curve is found from bond data, while in the money market the yield curve is
derived from the prices of a variety of different types of instrument. Cash rates provide information about
the short term rates, from one week to about 18 months. These are investments or borrowings where the
entire sum of interest plus principal is due at the end of the period, with no interim payments. After about
two-year point, Swaps become the dominant instrument: from there it is possible to derive the yield curve
until 15-year point. After that, bond can be used. See [5] for further details.
Information about the yield curve becomes steadily more sparse as the maturity increases. A good interest
rate curve is the most basic requirement for pricing interest rate derivatives: if the curve is bad, the prices
it returns will be bad (see [1]). The objective in empirical fitting of the term structure is to find a curve that
fits the data sufficiently well and it is a sufficiently smooth function: the second requirement is at least as
important as the first, even if it is less quantifiable (see, for example, [12]).
In this paper we consider the methodology of fitting the discount function d (or related function, as,
for example, the instantaneous forward rate function) by the exponential model of Nelson-Siegel (see [9]
and [11]) and polynomial spline methods (see [6] and [7]) with or without penalty term (see [2] and [4]).
Moreover, we consider a M ATLAB [13] code written for both Italian Btp data and Libor and Swap data in
order to obtain the curves.

The outline of the paper is the following: in Section 2 we describe how we can extract the necessary
data from coupon bonds and Libor and Swap rates; in Section 3 we introduce the data-fitting techniques:
more precisely, we describe the Nelson-Siegel model and some methods based on cubic spline. In Sec-
tion 4 we explain how our M ATLAB code works using the theoretical results introduced in the previous

1
sections. Finally, Section 5 deals with the models’performances, considering both computational cost and
approximation results.

2 The Discount Function


The term structure of interest rate can be identified with any of a number of related concepts. In this
section we consider the discount function d(t), which describes the present value of 1 Euro repayable in t
years. The aim of the algorithm described in this paper is to extract the term structure from a set of coupon
bonds (such as the Italian Btp considered), whose prices are largely determined by the present value of their
stated payments (see [2]), or a set of Libor and Swap rates. More precisely, in this section we show a way
to obtain the values of the discount function at the payments’dates for both kind of data. For further details,
see the examples reported in Appendix A.

2.1 Coupon Bonds


Following [2] and [8], let P (i) be the price of a coupon bond i at a fixed date t (value date) and A(i, j)
be its j th payment made at time BP (i, j); moreover, let mi be the number of remaining payments for the
bond i and n be the number of bonds. Then, if we set for i = 1, · · · , n and j = 1, · · · , mi

T (i, j) := α0 [t, BP (i, j)],

where α0 [t1 , t2 ] is the distance between the two dates t1 and t2 , computed according to the actual/365
day-count convention (i.e., the day-count convention for bonds), we have
mi
X
P (i) = A(i, j)d(T (i, j)) ∀ i = 1, · · · , n. (1)
j=1

Since the coupon bond i is characterized by a periodic coupon Ci and a facial value Fi , we set
(
A(i, j) = Ci if j < mi
A(i, j) = Ci + Fi if j = mi ,

for i = 1, · · · , n. For simplicity, in this paper we consider coupons paid every six months (semi-annual
coupons) and we define Ci = C bi /2, where Cbi is the annual payment for the bond i, i = 1, · · · , n.
If we now define T T as the vector containing all the elements of T , sorted in ascending order, and we
define the matrix AA such that AA(i, j) is the payment of the bond i at time T T (j) (thus it could be equal
to 0 if T T (j) is not a time to payment for the considered bond), then (1) becomes

AA D = P , (2)

where D(i) = d(T T (i)), i = 0, · · · , m, and m is the number of elements of T T (i.e., the number of the
global payment times).
Considering the bond i, i = 1, · · · , n, its price P (i) (i.e., the price that purchaser pays when buying the
bond) is equal to the quoted price (clean price) plus the accrued interest AI (i.e., the interest accumulated
between the most recent interest payment and the present time). In order to compute AI, let t−1 be the date
of the previous coupon payment, t be the value date and t1 be the date of the next coupon payment, then
the accrued interest is
bi α0 [t−1 , t]
C α0 [t−1 , t]
AI = = Ci .
2 α0 [t−1 , t1 ] α0 [t−1 , t1 ]

2
2.2 Libor and Swap Rates
First of all we consider Libor (London Interbank Offered Rate) rates, which are daily reference rates
based on the interest rates at which banks offer to lend funds to other banks.
Let n1 be the number of Libors considered, LM be the vector containing the times to maturity of the n1
Libors and LR(i) be the interest rate of the Libor with time to maturity LM (i), i = 1, · · · , n1 : this means
that 1 Euro bought at time t (i.e., the value date) gives

1 + LR(i) α1 [t, LP (i)]

Euros at time LP (i), where:

• LP (i) is the payment date, i.e., LP (i) = t + LM (i) if it is a business day, otherwise LP (i) is the
first business day after t + LM (i);

• α1 [t1 , t2 ] is the distance between the two dates t1 and t2 , computed according to the actual/360
day-count convention, (i.e., the day-count convention for Libors).

Thus, if we set

T1 (i) := α1 [t, LP (i)],

we have
1 1
d(T1 (i)) = = ,
1 + LR(i) α1 [t, LP (i)] 1 + LR(i) T1 (i)

and so, reasoning as in the previous subsection, if we define for each Libor rate i

A1 (i) = 1 + LR(i) T1 (i),


P1 (i) = 1,

we obtain

A1 (i) d(T1 (i)) = P1 (i) ∀ i = 1, · · · , n1 . (3)

Now we consider Swaps, which are agreement to exchange one set of cash flow for another. The most
commonly traded Swap requires one side to pay a fixed rate and the other to pay a floating rate. In order to
derive the discount function from Swap rates, we suppose that they have cash flow at one-year intervals.
Let t be the value date, SR(i) be the interest rate of the Swap with expiration at i years and SP (i, j), with
0 < j ≤ i, be its j th payment date; we define

T2 (i, j) := α2 [t, SP (i, j)],

where α2 [t1 , t2 ] is the distance between the two dates t1 and t2 , computed according to the 30/360 day-
count convention (i.e., the day-count convention for Swaps considering the Euro market).
Thus, following [5], we have
Pi−1
1 − SR(i) j=1 [T2 (i, j) − T2 (i, j − 1)] d(T2 (i, j))
d(T2 (i)) = , i = 1, · · · , n2 , (4)
1 + SR(i) [T2 (i) − T2 (i, i − 1)]

3
where n2 is the maximum expiration time of the Swap considered and we have set T2 (i, 0) = 0 and
T2 (i) := T2 (i, i), i.e., its time to maturity.
If we define for i = 1, · · · , n2

A2 (i, j) = SR(i) [T2 (i, j) − T2 (i, j − 1)] if j < i,


A2 (i, i) = 1 + SR(i) [T2 (i) − T2 (i, i − 1)],
P2 (i) = 1,

then (4) is equivalent to


i
X
A2 (i, j) d(T2 (i, j)) = P2 (i) ∀ i = 1, · · · , n2 . (5)
j=1

It is easy to see that in order to use equations (4) and (5) it is necessary to know each Swap rates with expi-
ration from 1 to n2 years. If it is not possible, we obtain the missing Swap rates using linear interpolation,
i.e., if we suppose that the values of SR(i − 1) and SR(i + 1) are known, while SR(i) is unknown, we
set
SR(i − 1) + SR(i + 1)
SR(i) = .
2
See the M ATLAB routine MISSING _S WAP in Section 4.1 for further details and [1] for other interpolation
techniques.

Reasoning as above, if we now define n as the total number of financial instruments considered (i.e.,
n = n1 + n2 ), T T as the vector containing all the times to payment of both the Libor and the Swap rates
(i.e., all the elements T1 (l), l = 1, · · · , n1 and T2 (i, j), i = 1, · · · , n2 , j = 1, · · · , i, sorted in ascending
order), we can define

• AA(i, j) = A1 (i) if i ≤ n1 and T T (j) = T1 (i),

• AA(i, j) = A2 (i − n1 , p) if i > n1 and T T (j) = T2 (i − n1 , p),

• P (i) = P1 (i) if i ≤ n1 ,

• P (i) = P2 (i − n1 ) if i > n1 ,

for i = 0, · · · , n, j = 1, · · · , m, where m is the size of T T , i.e., the number of payment dates, and
p = 1, · · · , n2 .
Thus equations (3) and (5) become

AA D = P , (6)

where D(i) = d(T T (i)), i = 0, · · · , n.


Notice that equation (2) (i.e., the coupon bonds case) and equation (6) (i.e., the Libor and Swap rates
case) are of the same type. Thus we will consider their resolution through a fitting procedure without any
distinction between the kind of data considered.

3 The Fitting Procedure


The aim of this section is to introduce the data-fitting techniques: we start with the Nelson-Siegel model,
introduced in [9], then we present six models related with the cubic spline method.

4
3.1 Nelson-Siegel Model
The Nelson-Siegel model uses a single exponential functional form over the entire maturity range (see
[8]). The discount function associated with (1), (3) and (4) is given as
−t/β
)+α3 te−t/β
d(t) = e−α1 t−β(α2 +α3 )(1−e (7)

with the constraints

α1 > 0, α1 + α2 > 0, β > 0. (8)

Therefore, considering equations (2) and (6), we impose that


−T T (i)/β
)+α3 T T (i)e−T T (i)/β
D(i) := d(T T (i)) = e−α1 T T (i)−β(α2 +α3 )(1−e .

It is easy to understand that we are not sure that it is possible to find values of α1 , α2 , α3 and β which
satisfies

AA D = P ;

thus the estimation of the discount function requires searching the unknown parameters

Θ := {α1 , α2 , α3 , β}

which minimize the sum of the squared errors, i.e., we consider the system

AA D = P + E,

where E is the errors’vector (which depends on Θ) and we have to solve the following least square mini-
mization problem:

min E T E. (9)
Θ

3.2 Cubic Spline Method


The term spline is used to refer to a wide class of functions that are used in applications requiring data
interpolation and/or smoothing (see, for example, [10] for further details). Cubic splines are piecewise
polynomial, joined at so-called knot points, characterized by the fact that their first and second derivatives
are continuous functions.
A B-spline (or bell spline) is a spline function that has minimal support with respect to a given degree
and domain partition; each spline function can be represented as a linear combination of B-splines of the
same degree and over the same partition. In Figure 1 we show an example of B-spline basis function (see
Appendix B and [2] for further details).
Following [2], we have implemented the term structure fitting techniques below.

3.2.1 B-spline

Let {φi }si=1 be the set of the B-spline basis functions; first of all we consider the case in which we
parametrize d as a cubic spline, i.e.,
s
X
d(τ ) = βi φi (τ ).
i=1

5
Figure 1:

B−spline Basis Functions (Knot Points: 0; 2; 4)


1
φ1
0.9
φ2
0.8
φ3
0.7 φ4
φ5
0.6

0.5

0.4

0.3

0.2

0.1

0
0 0.5 1 1.5 2 2.5 3 3.5 4

Therefore, if we define for i = 1, · · · , m and j = 1, · · · , s

G(i, j) = φj (T T (i)),

we obtain

D := G β, (10)

where β = (β1 , · · · , βs )T .

Then we consider the function

g(τ ) := −log(d(τ ))

and we parametrize it as a cubic spline, i.e.,


s
X
g(τ ) = βi φi (τ ),
i=1

As it holds

d(τ ) = −eg(τ ) , (11)

we have

D := −exp(G β), (12)

where exp is the exponential function which operates element-wise on arrays.


Finally we consider the instantaneous forward rate function
d
f (τ ) = − log(d(τ ));

6
reasoning as above, it holds

d(τ ) = e− 0
f (t) dt
. (13)

Thus, if we parametrize f as a cubic spline, i.e.,


s
X
f (τ ) = βi φi (τ ),
i=1

and we define the matrix


Z T T (i)
IG(i, j) = φj (t) dt,
0

then we have

D := −exp(IG β). (14)

Reasoning as for the Nelson-Siegel model, the fitting procedure for the three cases above consists of
solving the minimization problem associated to the following system

AA D = P + E,

i.e., since we have to search β which minimize E T E, we have to solve the least square minimization
problem

min[(P − AA D)T (P − AA D)]. (15)


β

3.2.2 B-spline with Penalty Term

In a spline the number of basis functions s is determined by the number of knot points: too few or too
many parameters can lead to poor estimates. The strategy proposed in [2] is to penalize excess variability
in the estimated discount function, reducing the effective number of parameters since the penalty forces
implicit relationship between the spline basis functions.
If the domain of the spline is [0, T ], we define the penalty term H as the matrix of dimension s × s such
that
Z T
00 00
H(i, j) = φi (t)φj (t) dt.
0

The minimization problem associated with the B-spline with penalty fitting technique is

min[(P − AA D)T (P − AA D) + λβ T Hβ], (16)


β

where λ is the penalty parameter (i.e., a positive real number) and D is defined as in (10), (12) or (14),
depending on the function to be parametrized.
The penalty parameter λ controls the penalty matrix H; naturally, λ moves inversely to the effective number
of parameters: the more λ becomes a large number, the more the penalty matrix H becomes important in
(16). In order to choose the appropriate λ, we consider the value of λ which minimizes the so-called
Generalized Cross Validation (GCV) function
((I − Q)Y )T ((I − Q)Y )
γ(λ) := ,
(s − 2tr(Q))2

7
where
 
Q := X (X T X + λH)−1 X T ,

I is the s × s identity matrix, tr is the trace operator and X and Y are defined in Table 1.

Table 1: Choice of X and Y (X i denotes the ith row of X)


Function to Parametrize W Xi Y
d - (AA G)i P
g AA exp(−G β) −W (i) (AA G)i P −W +Xβ
f AA exp(−IG β) −W (i) (AA IG)i P − W + X β

Intuitively, cross validation starts by looking at a leave-one-out estimator for each data point. If data is
not scarce, then the set of available input-output measurements can be divided into two parts: one part for
training and one part for testing. A better method, which is intended to avoid the possible bias introduced
by relying on any particular division into test and train components, is to partition the original set in several
different ways and to compute an average score over the different partitions. This is called “leave-one-out”
cross-validation. The residual values from actual data point and the fitted data point from the “leave-
one-out” estimation are averaged to construct the cross validation measure. With few parameters in the
estimation the residual will tend to be large, due to a poor overall fit, while with an interpolant the perfect fit
will tend to produce spurious movements and hence large out of sample residuals. Somewhere in between
is the lowest value of the cross validation measure and thus the best estimate. See [2] for further details.
Notice that in Table 1 β is the solution of (16) and thus it depends also on λ: therefore, in the second
and the third case (i.e., when we parametrize g or f ), in order to find the best λ we have to find β solving
the minimization problem (16) at each step of the GCV-minimization procedure.

4 The M ATLAB Code


The aim of this section is to present our code; below we report the main file. For further information on
the M ATLAB routines used in the following code, such as FMINSEARCH or DAYSDIF, see Appendix C.

function main(flag1,flag2)
% INPUT
% flag1: kind of data
% flag1 = 0 -> Btp
% flag1 = 1 -> Swap + Libor
%
% flag2: kind of curve
% flag2 = 0 -> Nelson-Siegel
% flag2 = 1 -> B-spline (function: d)
% flag2 = 2 -> B-spline + Penalty (function: d)
% flag2 = 3 -> B-spline (function: g)
% flag2 = 4 -> B-spline + Penalty (function: g)
% flag2 = 5 -> B-spline (function: f)
% flag2 = 6 -> B-spline + Penalty (function: f)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FIRST STEP: Getting Data %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

8
if flag1==0
[Btp,value_date]=Btp_data;
elseif flag1==1
[Libor,Swap,value_date]=Libor_Swap_data;
Swap=missing_Swap(Swap);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SECOND STEP: Building Matrices and Vectors %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% TT-> vector of global payments (time)
% AA-> matrix of global payments (value)
% MAT->vector of maturity dates
if flag1==0
[P,T,A]=matrix_vector_Btp(value_date,Btp);
elseif flag1==1
[P,T,A]=matrix_vector_LS(value_date,Libor,Swap);
end
[TT,AA,MAT]=matrix_vector(T,A);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% THIRD STEP: Curve Fitting %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Find the vector x of the parameters of the curve
%
% Options for FMINSEARCH
options=optimset(’TolFun’,1e-9,’TolX’,1e-9,’MaxIter’,1e8,’MaxFunEvals’,1e8);
%
if flag2==0 %NELSON-SIEGEL
x_0=[0.04;-0.02;0.001;2]; %initial value
x=fminsearch(’NelsonSiegel’,x_0,options,AA,P,TT);
else %B-SPLINE METHODS
K=length(MAT);
s=max(3,round(sqrt(K))); %number of knot points + 1
KP=knot_points(s,K,MAT);
s=length(KP)+2; %number of B-spline basis function
KPa=[KP(1),KP(1),KP(1),KP,KP(end),KP(end),KP(end)];%Augmented knot points
if flag2==1 %B-SPLINE (function d)
for i=1:length(TT)
for j=1:s
G(i,j)=BsplineBasis(j,4,TT(i),KPa); %B-spline matrix
end
end
x_0=ones(s-1,1); %initial value
x=fminsearch(’Bspline’,x_0,options,AA*G,P);
x=[1;x];
elseif flag2==2 %B-SPLINE + PENALTY (function d)
for i=1:length(TT)
for j=1:s

9
G(i,j)=BsplineBasis(j,4,TT(i),KPa);
end
end
H=penalty(s,KPa); % Penalty Term
% Find the optimal Penalty Parameter
lambda=10^10; %initial value
lambda=fminsearch(’GCV’,lambda,options,AA*G,P,H);
% Find x
x_0=ones(s-1,1); %initial value
x=fminsearch(’Bspline_penalty’,x_0,options,AA*G,P,H,lambda);
x=[1;x];
elseif flag2==3 %B-SPLINE (function g)
for i=1:length(TT)
for j=1:s
G(i,j)=BsplineBasis(j,4,TT(i),KPa);
end
end
x_0=ones(s-1,1);
x=fminsearch(’Bspline_g’,x_0,options,AA,G,P);
x=[0;x];
elseif flag2==4 %B-SPLINE+PENALTY (function g)
for i=1:length(TT)
for j=1:s
G(i,j)=BsplineBasis(j,4,TT(i),KPa);
end
end
H=penalty(s,KPa); % Penalty Term
% Find the optimal Penalty Parameter
x_0=ones(s-1,1); %initial value
lambda=10^3; % initial value
lambda=fminsearch(’GCV_g’,lambda,options,AA,G,P,H,x_0,s,options);
% Find x
x=fminsearch(’Bspline_penalty_g’,x_0,options,AA,G,P,H,lambda);
x=[0;x];
elseif flag2==5 %B-SPLINE (function f)
IG=intBsplineBasis(TT,s,KP,KPa); % integral of the B-spline basis
x_0=ones(s,1); %initial value
x=fminsearch(’Bspline_f’,x_0,options,AA,IG,P);
elseif flag2==6 %B-SPLINE+PENALTY (function f)
IG=intBsplineBasis(TT,s,KP,KPa); % integral of the B-spline basis
H=penalty(s,KPa); % Penalty Term
% Find the optimal Penalty Parameter
x_0=ones(s,1); %initial value
lambda=10^3; %initial value
lambda=fminsearch(’GCV_f’,lambda,options,AA,IG,P,H,x_0,s,options);
% Find x
x=fminsearch(’Bspline_penalty_f’,x_0,options,AA,IG,P,H,lambda);

10
end
end

4.1 First Step: Getting Data


The first step of the M ATLAB program is to get the Btp or the Libor and Swap data. If we consider Btp,
the program calls the B TP _ DATA routine, which provides all the necessary data.

function [Btp,value_date]=Btp_data
% Btp -> Btp struct --> [nominal value, clean value, maturity,
% rate, number of coupons (for year)]
%
value_date=’12/19/2006’;
%
Btp=[
struct(’n_val’,100,’val’,99.94,’mat’,’01/15/2007’,’rate’,2.75,’coupons’,2)
...
struct(’n_val’,100,’val’,96.3,’mat’,’02/01/2037’,’rate’,4.00,’coupons’,2)
];

If instead we consider Libor and Swap, the program calls the L IBOR _S WAP _ DATA routine for the
necessary data and then MISSING _S WAP, which uses linear interpolation for the missing Swap rates (see
Section 2.2).

function [Libor,Swap,value_date]=Libor_Swap_data
%
value_date=’09/21/2006’;
%%%%%%%%%%%%%%%%%%%%%%
% Libor -> duration (in days) - duration (in months) - rate
Libor=[
1, 0, 3.04188;
...
0, 3, 3.37025;
];
%%%%%%%%%%%%%%%%%%%%%%
% Swap -> duration (in years) - rate
Swap=[
1, 3.808;
...
30, 4.214;
];

function Swap1=missing_Swap(Swap)
% Compute missing Swap using linear interpolation
%
n=length(Swap); %number of Swaps
difference=zeros(n,1); %initialize
% difference(i)=n means that between the duration of swap i and i+1
% there are n years-> if n=1 we do nothing, otherwise we create the

11
% missing Swap/Swaps using linear interpolation
for i=1:n-1
difference(i)=Swap(i+1,1)-Swap(i,1);
end
%
count=0;
for i=1:n
count=count+1;
Swap1(count,:)=Swap(i,:);
for j=1:difference(i)-1
count=count+1;
Swap1(count,1)=Swap(i,1)+j;
t=Swap1(count,1);
t1=Swap(i,1);
t2=Swap(i+1,1);
s1=Swap(i,2);
s2=Swap(i+1,2);
Swap1(count,2)=(s1*(t2-t)+s2*(t-t1))/(t2-t1);
end
end

4.2 Second Step: Building Matrices and Vectors


In the second step, following Section 2, we build the matrix AA and the vector P necessary for the
third step: the curve fitting.
If we consider Btp, the main program calls the MATRIX _ VECTOR _B TP routine, which computes matrices
A and T and the vector P (see Section 2.1).

function [P,T,A]=matrix_vector_Btp(Date,Btp)
% Compute: P -> price vector
% T -> matrix of coupons’payments (time)
% T[i,j]=time to the jth payment of the ith Btp
% A -> matrix of coupons’payments (value)
% A[i,j]=jth payment of the ith Btp
% Date is taken as time 0
%
% Initialize Matrices and Vector
n=length(Btp); % number of Btp
P=zeros(n,1);
A=[];
T=[];
for i=1:n
% 1-compute Previous coupon and Next coupons
[Pcoupon,Ncoupons]=PNcoupons(Btp(i),Date);
% 2-compute Accrued Interest
AI=Btp(i).n_val*(Btp(i).rate/100)*(1/(Btp(i).coupons))*...
(daysdif(Pcoupon,Date,3)/daysdif(Pcoupon,Ncoupons(1),3));
% DAYSDIF->Days between dates with day-count basis 3(=actual/365)

12
% 3-compute P
P(i)=Btp(i).val+AI;
% 4-compute A and T
m=length(Ncoupons); % number of next coupons
for j=1:m
T(i,j)=daysdif(Date,Ncoupons(j),3)/365;
A(i,j)=((Btp(i).rate/100)/Btp(i).coupons)*Btp(i).n_val;
end
A(i,m)=A(i,m)+Btp(i).n_val; %pay the nominal value at maturity
end

The above routine calls PN COUPON, which computes the previous coupon date and the dates of the
next coupons.

function [Pcoupon,Ncoupons]=PNcoupons(Btp,Date);
% Compute the Previous coupon and the Next coupons date
%
maturity=Btp.mat;
numcoup=Btp.coupons;%number of coupons paid on each year
monthcoup=12/numcoup; %months between two coupons
%
coupon=datenum(maturity);
%DATENUM converts date string into serial date number
cday=day(maturity);%day of the maturity date
cmonth=month(maturity);%month of the maturity date
cyear=year(maturity);%year of the maturity date
count=0; %number of next coupons
while( daysdif(Date,coupon,3)>0 )
%DAYSDIF->days between dates with day-count basis 3(=actual/365)
count=count+1;
coup(count)=coupon;%next coupons’date
temp=cmonth-monthcoup;
if temp<=0
cyear=cyear-1;
cmonth=12+temp;
else
cmonth=temp;
end
coupon=datenum(cyear,cmonth,cday);
end
Pcoupon=coupon;
while( isbusday(Pcoupon)==0 ) % if it is not a business day
Pcoupon=Pcoupon+1;
end
%
for i=1:count
temp=coup(i);
while( isbusday(temp)==0 ) % if it is not a business day

13
temp=temp+1;
end
Ncoupons(count-i+1)=temp; % ascending order
end

In the same way, if we consider Libor and Swap, we compute matrix A, T and vector P using the
MATRIX _ VECTOR _LS. Notice that A, T and P contain the elements of A1 and A2 , T1 and T2 , P1 and
P2 , respectively (see Section 2.2).

function [P,T,A]=matrix_vector_LS(Date,Libor,Swap)
% Compute: P -> price vector
% T -> matrix of payments (time)
% A -> matrix of payments (value)
% Date is taken as time 0
%
n1=length(Libor); % number of Libors
n2=length(Swap); % number of Swaps
cday=day(Date);
cmonth=month(Date);
cyear=year(Date);
%
%%%%%
% P %
%%%%%
P=ones(n1+n2,1);
%
%%%%%%%%%%%
% A and T %
%%%%%%%%%%%
% Libor
% daycount -> actual/360 (basis 2 in daysdif)
for i=1:n1
% temp is the maturity of the i-th Libor
if Libor(i,1)>0 % if the duration is in days
temp=datenum(cyear,cmonth,cday+Libor(i,1));
else % if the duration is in months
temp=datenum(cyear,cmonth+Libor(i,2),cday);
end
while( isbusday(temp)==0 ) %if it is not a business day
temp=temp+1;
end
T(i,1)=daysdif(Date,temp,2)/360;
A(i,1)=1+(Libor(i,3)/100)*T(i,1);
end
%
% Swap
% daycount -> 30/360 (basis 6 in daysdif)
for i=1:n2

14
for j=1:Swap(i,1)
% temp is the j-th payment date of the i-th Swap
temp=datenum(cyear+j,cmonth,cday);
while( isbusday(temp)==0 ) %if it is not a business day
temp=temp+1;
end
T(n1+i,j)=daysdif(Date,temp,6)/360;
if j==1 %if it is the first payment
t=T(n1+i,j);
else
t=T(n1+i,j)-T(n1+i,j-1);
end
A(n1+i,j)=(Swap(i,2)/100)*t;
end
A(n1+i,Swap(i,1))=A(n1+i,Swap(i,1))+1;
end

At the end, using routine MATRIX _ VECTOR, we compute matrix AA and vector T T (see Section 2)
for both the Btp case or the Libor-Swap case.

function [TT,AA,MAT]=matrix_vector(T,A)
% Compute:
% TT-> vector of global payments (time)
% AA-> matrix of global payments (value)
% MAT->vector of times to maturity
%
%%%%%%
% TT %
%%%%%%
count=1;
for i=1:size(T,2)
for j=1:size(T,1)
a=T(end+1-j,i);
if a==0 %all the remaining element of the column are 0
break % break the j-loop
else
flag=0; % the date a is not present in TT
for k=1:count-1
if TT(k)==a
flag=1; % a is already present in T
break % break the k-loop
end
end
if flag==0 % if the date a is not present in TT...
TT(count)=a; % add a to TT
count=count+1;
end
end

15
end
end
TT=sort(TT); %Sort in ascending order.
%%%%%%
% AA %
%%%%%%
for k=1:length(TT)
for i=1:size(A,1)
for j=1:size(A,2)
if T(i,j)==TT(k) %if the payment date are equal
AA(i,k)=A(i,j);
break;
elseif T(i,j)>TT(k)
break;
end
end
end
end
%%%%%%%
% MAT %
%%%%%%%
for i=1:size(T,1)
for j=1:size(T,2)
if T(i,j)==0
MAT(i)=T(i,j-1);
break;
elseif j==size(T,2)
MAT(i)=T(i,j);
break;
end
end
end
MAT=sort(MAT);

For further details see the examples reported in Appendix A.

4.3 Third Step: Curve Fitting


In this last step we compute the curve’s parameters. Notice that both the Btp case and the Libor and
Swap case are considered without any distinction.

4.3.1 Nelson Siegel Model

From the MAIN routine we have

x_0=[0.04;-0.02;0.001;2]; %initial value


x=fminsearch(’NelsonSiegel’,x_0,options,AA,P,TT);

where the N ELSON S IEGEL routine is the following

16
function [f]=NelsonSiegel(x,A,P,T)
% f is the quantity to minimize
%
if x(1)<=0 % x(1) must be positive...
f=10^15;
elseif x(1)+x(2)<=0 % x(1)+x(2) must be positive...
f=10^15;
elseif x(4)<=0 % x(4) must be positive...
f=10^15;
else % if x(1), x(1)+x(2), x(4) is positive...
for i=1:length(T)
t(i,1)=exp(-x(1)*T(i)-x(4)*(x(2)+x(3))*(1-exp(-T(i)/x(4)))+...
x(3)*T(i)*exp(-T(i)/x(4)));
end
temp=P-A*t;
f=0;
for i=1:length(temp)
f=f+temp(i)^2;
end
end

If we consider Section 3.1, we have

x(1):= α1 , x(2):= α2 , x(3):= α3 , x(4):= β.

Notice that, in order to solve the constrain minimization (9), we impose f=10^15 if (8) is not satisfied.

4.3.2 B-spline methods

For the B-spline methods, in order to define the basis functions, in the MAIN program we have

K=length(MAT);
s=max(3,round(sqrt(K))); %number of knot points + 1
KP=knot_points(s,K,MAT);
s=length(KP)+2; %number of B-spline basis functions
KPa=[KP(1),KP(1),KP(1),KP,KP(end),KP(end),KP(end)]; %Augmented KP

where the KNOT _ POINTS routine is as follows

function T=knot_points(s,k,MAT)
% Compute the knot points following McCulloch (1971)
% These points are used to compute the B-spline basis functions
%
T(1)=0;
for i=2:s-2
h=fix(((i-1)*k/(s-2)));
% fix(X) rounds X to the nearest integers towards zero.
theta=((i-1)*k/(s-2))-h;
T(i)=MAT(h)+theta*(MAT(h+1)-MAT(h));
end
T(s-1)=MAT(end);

17

As in [6] and [8], the number of knot points (and thus the number of basis functions) depends on K. In
Appendix B we report the following routines:

• B SPLINEBASIS returns the value of B-spline basis functions; this routine is used to compute matrix
G,

• D B SPLINEBASIS returns the value of the first derivative of the B-spline basis functions,

• DD B SPLINEBASIS returns the value of the second derivative of the B-spline basis functions,

• INT B SPLINEBASIS returns the integrals of the B-spline basis functions: this routine is used to com-
pute matrix IG.

Following Sections 3.2.1 and 3.2.2, in order to compute the set of parameters β, we have to consider
the minimization problem below.

• B-spline (parametrized function: d)


From the MAIN routine we have

x_0=ones(s-1,1); %initial value


x=fminsearch(’Bspline’,x_0,options,AA*G,P);
x=[1;x];

where

function [f]=Bspline(x,A,b)
% B-spline
% f is the quantity to minimize
%
x=[1;x]; %the first term of the vector must be equal to 1
temp=b-A*x;
f=0;
for i=1:length(temp)
f=f+temp(i)^2;
end

Notice that d(0) = 1, since the present value of 1 Euro repayable in 0 years is actually 1; thus we
have to impose

β1 = 1

since 0 is the first knot point and it holds

φ1 (0) = 1, φi (0) = 0 if i = 2, · · · s,

where we recall that s is the number of basis functions (see Figure 1 and [2]). For this reason, the
minimization procedure involves only the parameters β2 , · · · , βs .

• B-spline with Penalty (parametrized function: d)


From the MAIN routine we have

18
H=penalty(s,KPa); % Penalty Term
% Find the optimal Penalty Parameter
lambda=10^10; %initial value
lambda=fminsearch(’GCV’,lambda,options,AA*G,P,H);
% Find x
x_0=ones(s-1,1); %initial value
x=fminsearch(’Bspline_penalty’,x_0,options,AA*G,P,H,lambda);
x=[1;x];

The penalty term, which is unique for each B-spline with penalty method, is computed by the
P ENALTY routine (see Section 3.2.2).

function H=penalty(s,KPa)
% Compute the Penalty Term
%
K=length(KPa)-6;
H=sparse(s,s);
for k=1:K-1
[x,w]=gauleg(KPa(k+3),KPa(k+4),4);
for t=1:length(x)
f=[];
for i=1:s
f(i)=ddBsplineBasis(i,4,x(t),KPa);
end
for i=1:s
for j=1:s
H(i,j)=H(i,j)+w(t)*f(i)*f(j);
end
end
end
end

For the GAULEG routine, which computes the nodes and weights of the Gauss-Legendre quadrature
formula, see Appendix B.5.
The minimization procedures call the following routines:

function f=GCV(lambda,X,Y,H)
% GENERAL CROSS VALIDATION
%
Q=X*inv(X’*X+lambda*H)*X’;
n=length(Y);
I=eye(n); %identity matrix of size n
T=(I-Q)*Y;
theta=2;
f=((T’)*T)/((n-theta*trace(Q))^2);

and

19
function [f]=usa_Bspline_penalty(x,A,b,H,lambda)
% f is the quantity to minimize
%
x=[1;x];%the first term of the vector must be equal to 1
f=((b-A*x)’)*(b-A*x)+lambda*((x’)*H*x);

As above, the second minimization procedure involves only the parameters β2 , · · · , βs .

• B-spline (parametrized function: g)


From the MAIN routine we have

x_0=ones(s-1,1);
x=fminsearch(’Bspline_g’,x_0,options,AA,G,P);
x=[0;x];

where

function [f]=Bspline_g(x,C,F,b)
% f is the quantity to minimize
%
x=[0;x];
Pi=C*exp(-F*x);
f=((b-Pi)’)*(b-Pi);

Notice that we have imposed β1 = 0 since g(0) = 0 implies d(0) = 1 (see (11) ).

• B-spline with Penalty (parametrized function: g)


From the MAIN routine we have

H=penalty(s,KPa); % Penalty Term


% Find the optimal Penalty Parameter
x_0=ones(s-1,1); %initial value
lambda=10^3; % initial value
lambda=fminsearch(’GCV_g’,lambda,options,AA,G,P,H,x_0,s,options);
% Find x
x=fminsearch(’Bspline_penalty_g’,x_0,options,AA,G,P,H,lambda);
x=[0;x];

where

function e=GCV_g(lambda,AA,G,P,H,b_0,s,options)
% GENERAL CROSS VALIDATION
%
if lambda>0
b=fminsearch(’Bspline_penalty_g’,b_0,options,AA,G,P,H,lambda);
b=[0;b];
W=AA*exp(-G*b);
temp=AA*G;

20
for i=1:length(W)
Xg(i,:)=(-W(i)).*(temp(i,:));
end
Yg=P-W+Xg*b;
e=GCV(lambda,Xg,Yg,H);
else %constrain: lambda>0
e=10^12;
end

and

function [f]=Bspline_penalty_g(x,C,F,b,H,lambda)
% f is the quantity to minimize
%
x=[0;x];
Pi=C*exp(-F*x);
f=(((b-Pi)’)*(b-Pi))+lambda*((x’)*H*x);

Notice that GCV_ G call B- SPLINE _ PENALTY _ G in a minimization procedure. Moreover, as above,
we have imposed β1 = 0 and the minimization procedures involve only parameters β2 , · · · , βs .

• B-spline (parametrized function: f )


From the MAIN routine we have

x_0=zeros(s,1); %initial value


x=fminsearch(’Bspline_f’,x_0,options,AA,IG,P);

where

function [f]=Bspline_f(x,C,F,b)
% f is the quantity to minimize
%
Pi=C*exp(-F*x);
f=((b-Pi)’)*(b-Pi);

Notice that (13) implies d(0) = 1; thus we do not impose any restriction to β1 and the minimization
procedure involves β1 , · · · , βs .

• B-spline with Penalty (parametrized function: f )


This case is similar to the B-spline with Penalty (parametrized function: g) case. We have

H=penalty(s,KPa); % Penalty Term


% Find the optimal Penalty Parameter
x_0=ones(s,1); %initial value
lambda=10^3; %initial value
lambda=fminsearch(’GCV_f’,lambda,options,AA,IG,P,H,x_0,s,options);
% Find x
x=fminsearch(’Bspline_penalty_f’,x_0,options,AA,IG,P,H,lambda);

21
where

function e=GCV_f(lambda,X,IG,P,H,b_0,s,options)
% GENERAL CROSS VALIDATION
%
if lambda>0
b=fminsearch(’Bspline_penalty_f’,b_0,options,X,IG,P,H,lambda);
W=X*exp(-IG*b);
temp=X*IG;
for i=1:length(W)
Xf(i,:)=(-W(i)).*(temp(i,:));
end
Yf=P-W+Xf*b;
e=GCV(lambda,Xf,Yf,H);
else %constrain: lambda>0
e=10^12;
end

and

function [f]=Bspline_penalty_f(x,C,F,b,H,lambda)
% f is the quantity to minimize
%
Pi=C*exp(-F*x);
f=(((b-Pi)’)*(b-Pi))+lambda*((x’)*H*x);

5 Numerical Results
The aim of this section is to present the models’performances, considering both computational cost
and approximation results. Numerical experiments have been carried out on a Personal Computer with a
Pentium IV (2.40 Ghz) processor and 768 MB of RAM, and using M ATLAB 7.0 (R14).

5.1 Btp Case


In this section we deal with the Btp case, which are Italian coupon bonds with semi-annual payments.
In the numerical experiments we have considered the Btp quotation with value date 19th December 2006
(see Table 2).
First of all we consider the computational cost: the “Building Matrices and Vectors” step, which does
not depend on the fitting model considered, takes approximately 8.5 seconds, while in Table 3 we report
the elapsed time of the third step of the MAIN routine (i.e., the “Curve Fitting” steps) for each method
considered. Moreover, in the same table we present the residuals |E| of the minimization problems (9) for
the Nelson Siegel model, (15) for the B-spline methods, and (16) for the B-spline with penalty methods; for
this last class of methods, we also report the best λ computed with the GCV procedure.
From this table, it seems that the best choice from a computational point of view is the B-spline model with
the parametrization of the discount function, while if we consider the residual, the best choice seems to be
the B-spline method (f ), i.e., we parametrize the instantaneous forward rate function f using B-spline basis
functions. Moreover, the B-spline methods with penalty (g) and (f ) have a great computational cost: this

22
Table 2: Btp
Value Clean Price Expiration Annual Rate Value Clean Price Expiration Annual Rate
(%) (%)
100 99.94 01/15/2007 2.75 100 105.91 08/01/2011 5.25
100 100.36 02/01/2007 6.75 100 99.57 09/15/2011 3.75
100 100.17 03/01/2007 4.50 100 105.31 02/01/2012 5.00
100 99.7 06/01/2007 3.00 100 104.81 02/01/2013 4.75
100 101.6 07/01/2007 6.75 100 102.22 08/01/2013 4.25
100 101 10/15/2007 5.00 100 102.31 08/01/2014 4.25
100 101.89 11/01/2007 6.00 100 102.27 02/01/2015 4.25
100 99.77 01/15/2008 3.50 100 98.6 08/01/2015 3.75
100 98.92 02/01/2008 2.75 100 98.19 08/01/2016 3.75
100 101.63 05/01/2008 5.00 100 110.78 08/01/2017 5.25
100 98.18 06/15/2008 2.50 100 101.96 02/01/2019 4.25
100 99.69 09/15/2008 3.50 100 104.24 02/01/2020 4.50
100 98.37 04/15/2009 3.00 100 96.16 08/01/2021 3.75
100 98.44 02/01/2009 3.00 100 158.78 11/01/2023 9.00
100 101.6 05/01/2009 4.50 100 141.42 11/01/2026 7.25
100 99.91 06/15/2009 3.75 100 131.7 11/01/2027 6.50
100 101.25 11/01/2009 4.25 100 115.18 11/01/2029 5.25
100 97.74 01/15/2010 3.00 100 127.09 05/01/2031 6.00
100 96.59 06/15/2010 2.75 100 124.27 02/01/2033 5.75
100 106.03 11/01/2010 5.50 100 112.94 08/01/2034 5.00
100 98.73 03/15/2011 3.50 100 96.3 02/01/2037 4.00

Table 3: Btp Data: Timing and Residual


Method Curve Fitting Residual Best λ
(elapsed time)
Nelson Siegel 0.406 seconds 1.058905 -
Bspline (d) 0.313 seconds 0.599565 -
Bspline+Penalty(d) 0.531 seconds 0.858068 15442.197764
Bspline (g) 0.437 seconds 0.544416 -
Bspline+Penalty (g) 28.922 seconds 0.560438 1273.437583
Bspline (f ) 3.234 seconds 0.471925 -
Bspline+Penalty (f ) 80.062 seconds 1.641775 52148137.527466

is due to the GCV-minimization procedure, which call another minimization procedure at each step (see
Section 3.2.2).
Then we show the plots of the discount function d (Figure 2), of the spot rate function h (Figure 3),
where
log(d(τ ))
h(τ ) := − ,
τ
and of the instantaneous forward rate function f (Figure 4).
These figures suggest the following observations, which are important in order to understand the behavior
of the different data-fitting techniques:

23
Figure 2: Btp Case
Discount Function
1
Nelson−Siegel
0.9 Bspline (d)
Bspline + Penalty (d)
Bspline (g)
0.8
Bspline + Penalty (g)
Bspline (f)
0.7 Bspline + Penalty (f)

0.6

0.5

0.4

0.3

0.2
0 5 10 15 20 25 30

Figure 3: Btp Case

Spot Rate
0.043

0.042

0.041

0.04

0.039 Nelson−Siegel
Bspline (d)
Bspline + Penalty (d)
0.038 Bspline (g)
Bspline + Penalty (g)
0.037 Bspline (f)
Bspline + Penalty (f)

0.036
0 5 10 15 20 25 30

24
Figure 4: Btp Case

Instantaneous Forward Rate


0.046

0.044

0.042

0.04
Nelson−Siegel
Bspline (d)
0.038 Bspline + Penalty (d)
Bspline (g)
Bspline + Penalty (g)
0.036 Bspline (f)
Bspline + Penalty (f)

0.034
0 5 10 15 20 25 30

Figure 5: Btp Case

Comparison
0.6

0.4

0.2

−0.2
Nelson−Siegel
Bspline (d)
−0.4 Bspline + Penalty (d)
Bspline (g)
−0.6 Bspline + Penalty (g)
Bspline (f)
Bspline + Penalty (f)
−0.8
0 5 10 15 20 25 30 35 40

25
• discount function
from Figure 2 it seems that the different methods for curve construction produce very similar plots;

• spot rate function


from Figure 3 it seems that the Nelson Siegel and the B-spline with penalty (f ) models behave quite
different from the other methods after the 15-years point. If we consider the last method, this behavior
is due to the large penalty parameter computed with the GCV procedure (see Table 3);

• instantaneous forward rate function


the plots presented in Figure 4 are quite different; the best choices seem to be the Nelson-Siegel and
the B-spline with penalty (f ) models, since for the other methods the plotted curves decrease too
rapidly after the 20-years point (see [3] for further details).

Finally we compare our models with the initial data. More precisely, let Pe be the vector containing
the prices of the considered Btp at the value date, computed using the discount function obtained with a
data-fitting technique, then in Figure 5 we plot the values

P (i) − Pe(i), i = 1, · · · , 42,

where 42 is the number of Btp considered.

5.2 Libor and Swap Case


In this section we present the same data as above, considering Libor and Swap rates with value date
21th September 2006 (see Tables 4 and 5).

Table 4: Libor
Duration (days) Rate (%) Duration (months) Rate (%)
1 day 3.04188 1 month 3.19325
7 days 3.06275 2 months 3.2935
15 days 3.06563 3 months 3.37025

Table 5: Swap
Duration (year) Rate (%) Duration (year) Rate (%)
1 3.808 8 3.973
2 3.88 9 4.011
3 3.883 10 4.029
4 3.892 15 4.066
5 3.906 20 4.202
6 3.925 25 4.218
7 3.947 30 4.214

As above, in Table 6 we compare the different methods considering both the computational cost and the
residuals |E|, respectively. The results are in agreement with the Btp case. Notice that the elapsed time for
the “Building Matrices and Vectors” step is approximately 3.5 seconds.
Moreover, in Figures 6, 7 and 8 we show the plots of the discount function, of the spot rate function and of
the instantaneous forward rate function, respectively. These figures suggest the following observations:

• discount function
in Figure 6 the plots are really similar, as in the Btp case;

26
Figure 6: Libor and Swap Case
Discount Function
1
Nelson−Siegel
0.9 Bspline (d)
Bspline + Penalty (d)
Bspline (g)
0.8
Bspline + Penalty (g)
Bspline (f)
0.7 Bspline + Penalty (f)

0.6

0.5

0.4

0.3

0.2
0 5 10 15 20 25 30

Figure 7: Libor and Swap Case

Spot Rate
0.043

0.042

0.041

0.04

0.039 Nelson−Siegel
Bspline (d)
Bspline + Penalty (d)
0.038
Bspline (g)
Bspline + Penalty (g)
0.037 Bspline (f)
Bspline + Penalty (f)

0.036
0 5 10 15 20 25 30

27
Figure 8: Libor and Swap Case

Instantaneous Forward Rate


0.048

0.046

0.044

0.042

0.04
Nelson−Siegel
Bspline (d)
0.038 Bspline + Penalty (d)
Bspline (g)
Bspline + Penalty (g)
0.036
Bspline (f)
Bspline + Penalty (f)
0.034
0 5 10 15 20 25 30

Figure 9: Libor and Swap Case


−3 Comparison
x 10

−2

Nelson−Siegel
−4 Bspline (d)
Bspline + Penalty (d)
Bspline (g)
−6 Bspline + Penalty (g)
Bspline (f)
Bspline + Penalty (f)
−8
0 5 10 15 20 25 30 35 40

28
Table 6: Libor and Swap Data: Timing and Residual
Method Curve Fitting Residual Best λ
(elapsed time)
Nelson Siegel 0.125 seconds 0.011997 -
Bspline (d) 0.157 seconds 0.006932 -
Bspline+Penalty(d) 0.360 seconds 0.011889 4.089915
Bspline (g) 0.157 seconds 0.007672 -
Bspline+Penalty (g) 18.828 seconds 0.012356 22.205400
Bspline (f ) 0.920 seconds 0.005384 -
Bspline+Penalty (f ) 44.875 seconds 0.006086 1.419115

• spot rate function


from Figure 7 it seems that the B-spline with penalty (g) method (and not the B-spline with penalty
(f ), as in the Btp case) behaves like the Nelson Siegel model: this is due to the different penalty
parameter value, since in the Btp case the largest parameter is the one of the B-spline with penalty
(f ) method, while in the Libor and Swap case it is the one computed for the B-spline with penalty (g)
model (see Table 6);

• instantaneous forward rate function


Figure 8 suggests that the best plots are the ones derived from the Nelson Siegel and the B-spline with
penalty methods, since the classical B-spline methods produce curves which increase or decrease too
rapidly after the 20-years points.

Finally, as in the previous subsection, in Figure 9 we compare our models with the initial data.

6 Conclusion
In this paper we have shown how to fit smoothing splines or exponential curves (like the Nelson Siegel
model) to the term structure of interest rates. We have described the M ATLAB code and we have presented
numerical results, comparing the different models. From the numerical experiments, it is clear that it is not
possible to find the best model: the choice of which method to use is subjective and need to be decided on
a case by case basis. In fact, if we consider the residual, the best choice is to use smoothing splines which
parametrized the instantaneous forward rate function f : this result is in agreement with [2]. Moreover, if
we are interested in the instantaneous forward rate function, the best choice seems to be the Nelson Siegel
model. Following [2], we have also presented methods with a penalty term: these methods behaves better
than the classical B-spline methods if we consider the instantaneous forward rate function, but they are
characterized by high computational costs due to the GCV procedure in order to compute the best penalty
parameter. Notice that in [2] the authors use a great number of knot points and thus the penalty term is
necessary in order to obtain well-behaved curves, while in this paper we have followed [6] and [8], using
few knot points.

29
A Building Matrices and Vectors: Examples
The aim of this section is to explain Sections 2 and 4.2 with two examples: one for the Btp case and the
other for the Libor and Swap case.

A.1 Btp Case


In this section we consider the Btp quotation with value date 19th December 2006 reported in Table 7.

Table 7: Btp
Facial Value Clean Price Expiration Annual Interest Rate (%)
100 99.94 01/15/2007 2.75
100 99.7 06/01/2007 3.00
100 99.77 01/15/2008 3.50
100 101.63 05/01/2008 5.00
100 98.18 06/15/2008 2.50

We now consider the first bond of Table 7: following Section 2.1, we have

• m1 = 1, i.e, there is only 1 payment date for the first bond;

• F1 = 100, i.e., the facial value;

• C1 = 100 2.75%
2 = 1.375, i.e., the facial value multiplied by the semi-annual interest rate.

Reasoning in the same way for all the elements of Table 7, we have
 
101.375 0 0
 101.5 0 0
 

 
A=  1.75 1.75 101.75 .

 2.5 2.5 102.5 
 
1.25 1.25 101.25
Moreover, we have
 
01/16/07
06/01/07
 
 
 
BP = 
 01/16/07 07/16/07 01/15/08 

05/01/07 11/01/07 05/01/08 
 

06/15/07 12/17/07 06/16/08
and thus
 
28 0 0
164 0 0
 
 
 
T =
 28 209 392 ,

133 317 499
 
 
178 363 545
where we recall that T contains the days between the value date and the payment dates of the Btp BP ,
computed according to the actual/365 day-count convention.
Now we can compute vector T T , i.e., the vector containing all the non-zero elements of T
 
T T = 28 133 164 178 209 317 363 392 499 545 ;

30
and thus we define matrix AA as follows
 
101.375 0 0 0 0 0 0 0 0 0
0 0 101.5 0 0 0 0 0 0 0
 
 
 
AA =   1.75 0 0 0 1.75 0 0 101.75 0 0 .

0 2.5 0 0 0 2.5 0 0 102.5 0
 
 
0 0 0 1.25 0 0 1.25 0 0 101.25

Notice that in the M ATLAB code (see Section 4) both the elements of T and T T are computed in years
and not in days. Moreover, in order to compute the payment dates (and thus BP ), we have to check if each
date is a business day: in our code, we have used the M ATLAB function ISBUSDAY, which is based on the
US calendar (that is why the 15th January 2007 is considered as holiday and thus the payment date of the
first bond is 16th January 2007).
Finally, if we sum the clean prices and the accrued interests, we obtain
 
101.104617486339
 99.848351648352 
 
 
P =  101.252240437158  .

 102.292983425414 
 
98.207472527473

A.2 Libor and Swap


Now we consider the Libor and Swap interest rates with value date 21th September 2006 reported in
Tables 8 and 9, respectively.

Table 8: Libor
Duration Interest Rate (%)
1 day 3.04188
7 days 3.06275
15 days 3.06563

Table 9: Swap
Duration Interest Rate (%)
1 year 3.808
2 years 3.88
3 years 3.883

First of all, we consider the Libor case: from Table 8, we obtain


 
LR = 0.0304188 0.0306275 0.0306563 ,
 
LM = 1 7 15 ;

thus, following Section 2.2, we have


 
LP = 09/22/06 09/28/06 10/06/06 ,
 
T1 = 0.002778 0.019444 0.041667

31
and so
 
A1 = 1.000084 1.000595 1.001278 ;

notice that in this example the elements of LM are computed in days, while the elements of T1 are
computed in years, using the actual/360 day-count convention.

Now we consider the Swap case: from Table 9 we obtain


 
SR = 0.03808 0.0388 0.03883

and
 
09/21/07
SP =  09/21/07 09/22/08 .
 

09/21/07 09/22/08 09/21/09

Recalling that the value date is 09/21/06, using the 30/360 day-count convention, we have
 
1 0 0
T2 =  1 2.002778 0  .
 

1 2.002778 3

We recall that in order to compute the payment dates, we have to check if each date is a business day,
otherwise we have to look for the next business day: this is the reason why T2 (2, 2) = 2.002778.
Finally, following Section 2.2, we calculate matrix A2
 
1.03808 0 0
A2 =  0.0388 1.038908 0 .
 

0.03883 0.038938 1.038722

If we now compute vector T T , i.e., the vector containing all the non-zero elements of T1 and T2
 
T T = 0.002778 0.019444 0.041667 1 2.002778 3 ,

we can define matrix AA as follows


 
1.000084 0 0 0 0 0
0 1.000595 0 0 0 0
 
 
 
 0 0 1.001277 0 0 0 
AA =  ;

 0 0 0 1.03808 0 0 

0 0 0 0.0388 1.038908 0
 
 
0 0 0 0.03883 0.038938 1.038722

Notice that in the MATRIX _ VECTOR _LS routine (see Section 4.2) the elements of A1 and A2 are stored
in a unique matrix A
 
1.000084 0 0
 1.000595 0 0
 

 
 1.001278 0 0 
A=  ;
 1.03808 0 0 

 0.0388 1.038908 0
 

0.03883 0.038938 1.038722

32
in the same way, the elements of T1 and T2 are stored in T as follows
 
0.002778 0 0
 0.019444 0 0 
 
 
 0.041667 0 0 
T =  .
 1 0 0 
1 2.002778 0 
 

1 2.002778 3

B Bspline Routines
In this section, we present the following routines:

1. B SPLINEBASIS computes the value of B-spline basis functions;

2. D B SPLINEBASIS computes the value of the first derivative of the B-spline basis functions;

3. DD B SPLINEBASIS computes the value of the second derivative of the B-spline basis functions;

4. INT B SPLINEBASIS returns the integrals of the B-spline basis functions;

5. GAULEG computes the nodes and weights of the Gauss-Legendre quadrature formula.

B.1 B SPLINE BASIS


function F=BsplineBasis(k,r,x,d)
% B-spline Basis Function
% k -> consider the kth basis function
% r -> r-1 is the degree of the spline
% x -> is the the point in which I evaluate the function
% d -> augmented knot points
%
if (k+r-1<5 & k<5)
if (x<d(5))
F=((d(5)-x)/(d(5)-d(1)))^(r-1);
else
F=0;
end
elseif (k+1>length(d)-4 & k+r>length(d)-4)
if (x>=d(end-4))
F=((x-d(end-4))/(d(end)-d(end-4)))^(r-1);
else
F=0;
end
else
if r==1
if (x>=d(k) & x<d(k+1))
F=1;
else

33
F=0;
end
else
f1=BsplineBasis(k,r-1,x,d);
f2=BsplineBasis(k+1,r-1,x,d);
F=((f1*(x-d(k)))/(d(k+r-1)-d(k)))+...
((f2*(d(k+r)-x))/(d(k+r)-d(k+1)));
end
end

B.2 D B SPLINE BASIS

function F=dBsplineBasis(k,r,x,d)
% First Derivative of B-spline Basis Function
% k -> consider the kth basis function
% r -> r-1 is the degree of the spline
% x -> is the vector of the points in which I evaluate the function
% d -> augmented knot points (necessary to define the basis function)
%
if r<2
F=0;
else
if (k+r-1<5 & k<5)
if (x<d(5))
F=(r-1)*(((d(5)-x)/(d(5)-d(1)))^(r-2))*(-1/(d(5)-d(1)));
else
F=0;
end
elseif (k+1>length(d)-4 & k+r>length(d)-4)
if (x>=d(end-4))
F=(r-1)*(((x-d(end-4))/(d(end)-d(end-4)))^(r-2))*...
(1/(d(end)-d(end-4)));
else
F=0;
end
else
f1=BsplineBasis(k,r-1,x,d);
f2=BsplineBasis(k+1,r-1,x,d);
d1=dBsplineBasis(k,r-1,x,d);
d2=dBsplineBasis(k+1,r-1,x,d);
F=((f1+(x-d(k))*d1)/((d(k+r-1)-d(k))))+...
((-f2+(d(k+r)-x)*d2)/(d(k+r)-d(k+1)));
end
end
end

34
B.3 DD B SPLINE BASIS

function F=ddBsplineBasis(k,r,x,d)
% Second Derivative of B-spline Basis Function
% k -> consider the kth basis function
% r -> r-1 is the degree of the spline
% x -> is the vector of the points in which I evaluate the function
% d -> augmented knot points (necessary to define the basis function)
%
if r<3
F=0;
else
if (k+r-1<5 & k<5)
if (x<d(5))
F=(r-1)*(r-2)*(((d(5)-x)/(d(5)-d(1)))^(r-3))*...
((-1/(d(5)-d(1)))^2);
else
F=0;
end
elseif (k+1>length(d)-4 & k+r>length(d)-4)
if (x>=d(end-4))
F=(r-1)*(r-2)*(((x-d(end-4))/(d(end)-d(end-4)))^(r-3))*...
((1/(d(end)-d(end-4)))^2);
else
F=0;
end
else
d1=dBsplineBasis(k,r-1,x,d);
d2=dBsplineBasis(k+1,r-1,x,d);
dd1=ddBsplineBasis(k,r-1,x,d);
dd2=ddBsplineBasis(k+1,r-1,x,d);
F=((d1+(x-d(k))*dd1+d1)/((d(k+r-1)-d(k))))+...
((-d2+(d(k+r)-x)*dd2-d2)/(d(k+r)-d(k+1)));
end
end
end

B.4 INT B SPLINE BASIS

function IG=intBsplineBasis(T,s,KP,d)
% Integral of the cubic B-spline basis function
% IG[i,j]=int_{0}^{T(i)} B(j) dx
% where B(j) is the jth basis function
% KP -> Knot Points
% d -> Augmented Knot Points
%
IG=zeros(length(T),s);
for i=1:length(T)

35
for ii=1:length(KP)
if T(i)>KP(ii)
if ii<length(KP)
t=min(T(i),KP(ii+1));
else
t=T(i);
end
[x,w]=gauleg(KP(ii),t,4);
for j=1:s
for jj=1:length(x)
temp=BsplineBasis(j,4,x(jj),d);
IG(i,j)=IG(i,j)+temp*w(jj);
end
end
else %the integral between 0 and T(i) has already been computed
break %stop the ii-loop and change the value of i
end
end
end

B.5 GAULEG

function [xx,ww]=gauleg(a,b,n)
% Gauss-Legendre quadrature formula
% Computes the Gauss-Legendre nodes xx and weights ww
% of order n for the interval (a,b)
%
m=(n+1)/2;
xm=0.5*(b+a);
xl=0.5*(b-a);
for i=1:m
z=cos(pi*(i-0.25)/(n+0.5));
while 1 % do untill break
p1=1.0;
p2=0.0;
for j=1:n
p3=p2;
p2=p1;
p1=((2.0*j-1.0)*z*p2-(j-1.0)*p3)/j;
end
pp=n*(z*p1-p2)/(z*z-1.0);
z1=z;
z=z1-p1/pp;
if (abs(z-z1)<eps), break, end
end
xx(i)=xm-xl*z;
xx(n+1-i)=xm+xl*z;

36
ww(i)=2.0*xl/((1.0-z*z)*pp*pp);
ww(n+1-i)=ww(i);
end

C M ATLAB Routines
The following informations are taken from the M ATLAB [13] manual.

C.1 DAYSDIF - Days between dates for any day count basis
DAYSDIF returns the number of days between D1 and D2 using the given day count basis. Enter dates
as serial date numbers or date strings.

D = daysdif(D1, D2)
D = daysdif(D1, D2, Basis)

Inputs:
D1 - [Scalar or Vector] of dates.
D2 - [Scalar or Vector] of dates.

Optional Inputs:
Basis - [Scalar or Vector] of day-count basis.
Valid Basis are:
0 = actual/actual (default)
1 = 30/360
2 = actual/360
3 = actual/365
4 - 30/360 (PSA compliant)
5 - 30/360 (ISDA compliant)
6 - 30/360 (European)
7 - act/365 (Japanese)

C.2 DATENUM - Serial date number


N = DATENUM(S) converts the string or date vector S into a serial date number. Date numbers are
serial days where 1 corresponds to 1-Jan-0000.
Certain formats may not contain enough information to compute a date number. In those cases, missing
values will in general default to 0 for hours, minutes and seconds, will default to January for the month,
and 1 for the day of month. The year will default to the current year. Date strings with 2 character years
are interpreted to be within the 100 years centered around the current year.

N = DATENUM(Y,M,D) and N = DATENUM([Y,M,D]) return the serial date numbers for correspond-
ing elements of the Y,M,D (year,month,day) arrays. Y, M, and D must be arrays of the same size (or any can
be a scalar).

Examples:
n = datenum(’19-May-2000’) returns n = 730625.

37
n = datenum(2001,12,19) returns n = 731204.
n = datenum(2001,12,19,18,0,0) returns n = 731204.75.

C.3 FMINSEARCH - Multidimensional unconstrained nonlinear minimization


X = FMINSEARCH(FUN,X0) starts at X0 and attempts to find a local minimizer X of the function FUN.
FUN accepts input X and returns a scalar function value F evaluated at X. X0 can be a scalar, vector or
matrix.

X = FMINSEARCH(FUN,X0,OPTIONS) minimizes with the default optimization parameters replaced


by values in the structure OPTIONS, created with the OPTIMSET function. FMINSEARCH uses these
options: Display, TolX, TolFun, MaxFunEvals, MaxIter, FunValCheck, and OutputFcn.

[X,FVAL]= FMINSEARCH(...) returns the value of the objective function, described in FUN, at X.

[X,FVAL,EXITFLAG] = FMINSEARCH(...) returns an EXITFLAG that describes the exit condition of


FMINSEARCH. Possible values of EXITFLAG and the corresponding exit conditions are:
1 - FMINSEARCH converged to a solution X.
0 - Maximum number of function evaluations or iterations reached.
-1 - Algorithm terminated by the output function.

FMINSEARCH uses the Nelder-Mead simplex (direct search) method.

C.4 ISBUSDAY - True for dates that are business days


T = ISBUSDAY(D,HOL,WEEKEND)

Inputs:
D - a vector of dates in question.

Optional Inputs:
HOL - a user-defined vector of holidays. The default is a predefined US holidays (in holidays.m).
WEEKEND - a vector of length 7, containing 0 and 1, with the value of 1 to indicate weekend day(s). The
first element of this vector corresponds to Sunday. Thus, when Saturday and Sunday are weekend then
WEEKDAY = [1 0 0 0 0 0 1]. The default is Saturday and Sunday weekend.

Outputs:
T = - 1 if D is business day and 0 if otherwise.

C.5 OPTIMSET - Create/alter OPTIM OPTIONS structure


OPTIONS = OPTIMSET(’PARAM1’,VALUE1,’PARAM2’,VALUE2,...) creates an optimization options
structure OPTIONS in which the named parameters have the specified values. Any unspecified parameters
are set to [] (parameters with value [] indicate to use the default value for that parameter when OPTIONS
is passed to the optimization function).

OPTIMSET PARAMETERS for MATLAB:


Display - Level of display [ off | iter | notify | final ]
MaxFunEvals - Maximum number of function evaluations allowed [ positive integer ]

38
MaxIter - Maximum number of iterations allowed [ positive scalar ]
TolFun - Termination tolerance on the function value [ positive scalar ]
TolX - Termination tolerance on X [ positive scalar ]
FunValCheck - Check for invalid values, such as NaN or complex, from user-supplied functions [ off | on ]
OutputFcn - Name of installable output function [ function ]. This output function is called by the solver
after each iteration.

References
[1] Revisiting “The Art and Science of Curve Building”, FINCAD News, December 2005 Issue.

[2] M. Fisher, D. Nychka, D. Zervos, “Fitting the Term Structure of Interest Rates with Smoothing
Splines”, Board of Governors of the Federal Reserve System (U.S.), Finance and Economics Dis-
cussion Series, Vol. 95-1, 1994.

[3] P. Hagan, G. West, “Interpolation Methods for Curve Construction”, Applied Mathematical Finance,
Vol. 13-2, 2006.

[4] M. Ioannides, “A Comparison of Yield Curve Estimation Techniques Using UK Data”, Journal of
Banking & Finance, Vol. 27, 2003.

[5] J. James, N. Webber, Interest Rate Modelling, John Wiley & Sons, 2000.

[6] J.H. McCulloch, “Measuring the Term Structure of Interest Rate”, Journal of Business, Vol. XLIV,
1971.

[7] J.H. McCulloch, “The Tax-Adjusted Yield Curve”, The Journal of Finance, Vol. XXX-3, 1975.

[8] S.K. Nawalkha, G.M. Soto, N.K. Beliaeva, Interest Rate Risk Modeling: The Fixed Income Valuation
Course, John Wiley & Sons, 2005.

[9] C.R. Nelson, A.F. Siegel, “Parsimonious Modeling of Yield Curves”, Journal of Business, Vol. 60-4,
1987.

[10] A. Quarteroni, R. Sacco, F. Saleri, Numerical Mathematics, Springer, 2000.

[11] A.F. Siegel, C.R. Nelson, “Long-Term Behaviour of Yield Curves”, Journal of Financial and Quanti-
tative Analysis, Vol. 23-1, 1988.

[12] O.A. Vasicek, H.G. Fong, “Term Structure Modeling Using Exponential Splines”, The Journal of
Finance, Vol. XXXVII-2, 1982.

[13] www.mathworks.com

39

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy