Interest Rate Modeling
Interest Rate Modeling
Daniele Marazzina
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.
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
• 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
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
we obtain
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
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
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
• 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)
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)
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.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:
0.5
0.4
0.3
0.2
0.1
0
0 0.5 1 1.5 2 2.5 3 3.5 4
G(i, j) = φj (T T (i)),
we obtain
D := G β, (10)
where β = (β1 , · · · , βs )T .
g(τ ) := −log(d(τ ))
As it holds
we have
6
reasoning as above, it holds
Rτ
d(τ ) = e− 0
f (t) dt
. (13)
then we have
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
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
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.
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.
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
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
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);
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
Notice that, in order to solve the constrain minimization (9), we impose f=10^15 if (8) is not satisfied.
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
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.
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
φ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 .
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);
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) ).
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 .
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 .
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).
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
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
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
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
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;
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
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
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
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
−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
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.
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
• 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
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
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.
and
09/21/07
SP = 09/21/07 09/22/08 .
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 .
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 ,
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:
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;
5. GAULEG computes the nodes and weights of the Gauss-Legendre quadrature formula.
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
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
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)
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.
[X,FVAL]= FMINSEARCH(...) returns the value of the objective function, described in FUN, at X.
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.
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.
[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