RATS 11.1
RATS 11.1

BONDSPLINE.RPF estimates a yield curve using a cubic spline approximation to the discount function, as described in McCulloch(1971). This compares with BONDS.RPF, which estimates the yield curve (on the same data set) using a non-linear function.

 

This models the discount function \(P(m)\) as a cubic spline, which is (in this case), a base cubic in \(m\) combined with terms of the form \(\beta _i \left( {\max (m - m_i ,0)} \right)^3 \) for a chosen set of "knots" \(m_i\). This has the property that \(P(m)\) is continuous with continuous 1st and 2nd derivatives as well. The only thing that changes at the knots is the 3rd derivative.

 

The data are described in BONDS.RPF. This can be estimated as a linear regression on a generated set of regressors, where those are created by decomposing the value of the bond into its components.

 

The regressors are divided into the BASEREGS (the 1st, 2nd and 3rd order terms of the base cubic polynomial—the constant, basically by definition, has to be 1 since it's the discount value for m=0) and KNOTREGS, which are the cubes of the excess over the corresponding knots. The knots are chosen to be at maturities 2, 4, 6 and 8 (in half years).

 

dec vect[series] baseregs(3)

*

ompute nknots=4
dec vect knots(nknots)
compute knots=||2.0,4.0,6.0,8.0||
dec vect[series] knotregs(nknots)
clear(zeros) knotregs baseregs
 

The series VALUEADJ will be the value of the bond adjusted for the constant term in \(P(m)\) and for the partial iniitial coupon. It starts off with the full value, but is reduced for the two adjustments. Note that the "entries" here are bonds, not time.

 

set valueadj = value

 

This loops over the bonds to generate the required regressors. We walk backwards through the coupon dates. The final one (first when working backwards) includes both the face value and the final coupon.

 

do i=1,nbonds

   compute mdate=maturity(i)

   *

   compute cdate=mdate

   while (cdate > 0.0) {

      if cdate==mdate

         compute receipt=coupon(i)+100.0

      else

         compute receipt=coupon(i)

      compute valueadj(i)=valueadj(i)-receipt

      do j=1,3

         compute baseregs(j)(i)=baseregs(j)(i)+receipt*cdate^j

      end do j

      do k=1,nknots

         compute knotregs(k)(i)=knotregs(k)(i)+receipt*%plus(cdate-knots(k))^3

      end do k

      compute cdate=cdate-1

   }

   *

   * Adjust for simple interest payable by the purchaser for the initial

   * coupon. cdate will be -(fraction of period).

   *

   compute valueadj(i)=valueadj(i)-coupon(i)*cdate

end do i

 

This defines a FUNCTION which computes, for a given maturity \(m\), the value of the cubic spline \(P(m)\).

 

function cspline m

type real cspline m

*

compute cspline=1.0+%beta(1)*m+%beta(2)*m^2+%beta(3)*m^3

do k=1,nknots

   compute cspline=cspline+%beta(3+k)*%plus(m-knots(k))^3

end do k

end spline

 

and this computes the value of that over test values for the maturity on (0,10] periods (half years), converts to (annualized) yields and graphs.

 

set testm 1 50  = .20*t

set pvalue 1 50 = cspline(testm)

*

* Convert the discount factor into an annualized yield curve

*

set testm 1 50  = testm/2

set yield 1 50  = -100.0*log(pvalue)/testm

scatter(style=line,header="Yield Curve",hlabel="Years",vlabel="Yield")

# testm yield

Full Program

open data bonds.xls

data(format=xls,org=cols) / coupon value maturity

compute nbonds=%allocend()

*

* The data set consists of US Treasury bonds, which have semi-annual

* coupons, but with the coupon stated in annual terms. The maturity

* series also provides annual information. The coupon is divided by two

* and the maturity multiplied by 2 to give values for the actual coupon

* period.

*

set coupon   = coupon / 2

set maturity = maturity * 2

*

* This models P(m)=discount factor for maturity m as a cubic spline.

*

* These are for the unrestricted linear, quadratic and cubic terms. (The

* constant has to be 1).

*

dec vect[series] baseregs(3)

*

* These are for the knots

*

compute nknots=4

dec vect knots(nknots)

compute knots=||2.0,4.0,6.0,8.0||

dec vect[series] knotregs(nknots)

clear(zeros) knotregs baseregs

*

* This is for the value of the bond adjusted for the constant terms in

* P(n) and for the partial initial coupon.

*

set valueadj = value

*

* Loop over the bonds to generate the required set of regressors.

*

do i=1,nbonds

   compute mdate=maturity(i)

   *

   * Walk backwards through the payments. The last one will include the

   * face value as well as the final coupon.

   *

   compute cdate=mdate

   while (cdate > 0.0) {

      if cdate==mdate

         compute receipt=coupon(i)+100.0

      else

         compute receipt=coupon(i)

      *

      * Adjust the value for the forced "1" in the base cubic

      *

      compute valueadj(i)=valueadj(i)-receipt

      do j=1,3

         compute baseregs(j)(i)=baseregs(j)(i)+receipt*cdate^j

      end do j

      do k=1,nknots

         compute knotregs(k)(i)=knotregs(k)(i)+receipt*%plus(cdate-knots(k))^3

      end do k

      compute cdate=cdate-1

   }

   *

   * Adjust for simple interest payable by the purchaser for the initial

   * coupon. cdate will be -(fraction of period).

   *

   compute valueadj(i)=valueadj(i)-coupon(i)*cdate

end do i

*

linreg valueadj

# baseregs knotregs

*

* Graph the estimated yield curve from maturities of 0->10 periods (5

* years). After the present value function is evaluated, the maturity is

* switched to years and the annual yield computed.

*

function cspline m

type real cspline m

*

compute cspline=1.0+%beta(1)*m+%beta(2)*m^2+%beta(3)*m^3

do k=1,nknots

   compute cspline=cspline+%beta(3+k)*%plus(m-knots(k))^3

end do k

end spline

*

set testm 1 50  = .20*t

set pvalue 1 50 = cspline(testm)

*

* Convert the discount factor into an annualized yield curve

*

set testm 1 50  = testm/2

set yield 1 50  = -100.0*log(pvalue)/testm

scatter(style=line,header="Yield Curve",hlabel="Years",vlabel="Yield")

# testm yield


 

Output

Linear Regression - Estimation by Least Squares

Dependent Variable VALUEADJ

Usable Observations                        20

Degrees of Freedom                         13

Centered R^2                        0.9999138

R-Bar^2                             0.9998741

Uncentered R^2                      0.9999783

Mean of Dependent Variable       -17.00996528

Std Error of Dependent Variable   10.11615070

Standard Error of Estimate         0.11351627

Sum of Squared Residuals         0.1675172733

Log Likelihood                        19.4452

Durbin-Watson Statistic                3.0522

 

    Variable                        Coeff      Std Error      T-Stat      Signif

************************************************************************************

1.  BASEREGS(1)                  -0.027617599  0.002329879    -11.85366  0.00000002

2.  BASEREGS(2)                  -0.003125137  0.002225416     -1.40429  0.18367020

3.  BASEREGS(3)                   0.000786045  0.000508590      1.54554  0.14620552

4.  KNOTREGS(1)                  -0.001083921  0.000734908     -1.47491  0.16404094

5.  KNOTREGS(2)                   0.000566519  0.000443154      1.27838  0.22346887

6.  KNOTREGS(3)                  -0.000492874  0.000463276     -1.06389  0.30674222

7.  KNOTREGS(4)                   0.000032001  0.000990301      0.03231  0.97471224

 

 

Graph


Copyright © 2026 Thomas A. Doan