Friday, October 7, 2011

Create Nelson-Siegel function for yield curve

U.S. Treasury bonds with maturity ranging from 1 year to 30 years are daily updated on the Treasury’s website. However, some yields, such as from 4 years maturity bond, have to be inferred. The Nelson-Siegel function is probably one of the most important formulas to construct the yield curve. Many people use EXCEL’s Solver to find the nonlinear estimates of the four parameters (a1, a2, a3 and beta) for the Nelson-Siegel function. SAS’s PROC NLIN can also do this job smoothly. I copied today’s yield data and imported into SAS. Then I assigned some initial values to the unknown parameters and solved those parameters. With the PROC FCMP, I was able to build a function to predict the yields at any given year. Finally I plotted the yield curve (I also fitted the real yields with a quadratic regression line). The results showed that the nonlinear Nelson-Siegel function behaves better at longer maturities than OLS regression.


**********************(1) IMPORT STEP******************************************;
data _1;
   input ytm : $4. @@;
   cards;
1mo   3mo   6mo   1yr   2yr   3yr   5yr   7yr   10yr 20yr   30yr
;;;

data _2;
   input yield : 3.2 @@;
   cards;
0.01 0.01   0.03   0.09 0.29 0.46   1.01   1.52   2.01   2.71   2.96
;;;

data _3(keep=yield years);
   set _1;
   set _2;
   if find(ytm, 'yr') gt 0;
   years = input(compress(ytm, 'yr'),3.);
   yield = yield / 100;
run;

**********************(2) SOLVE PARAMETERS************************************;
proc nlin data=_3 method=newton;
   parms a1 = 0.05 a2 = 0.05
      a3 = 0.05 beta = 1;
   model yield=a1+(a2+a3)*(beta/years)*(1-exp(-years/beta))-a3*exp(-years/beta);
   ods output parameterestimates = parmds;
run;

data _null_;
   set parmds;
   call symput(parameter, estimate);
run;

**********************(3) BUILD FUNCTION AND APPLY IT****************************;
proc fcmp outlib = work.func.finance;
   function nelson_siegel(years);
      return(  
         &a1 + (&a2+&a3)*(&beta/years)*(1-exp(-years/&beta))
         - &a3*exp(-years/&beta)
   );
   endsub;
run;
options cmplib=work.func;
data _4;
   do years = 1 to 30;
      predyield = nelson_siegel(years);
      output;
   end;
run;

data _5;
   merge _3(rename=(yield=realyield)) _4(in=a);
   by years;
   if a;
run;

ods html style = money;
proc sgplot data = _5;
   scatter x = years y = predyield;
   series x = years y = realyield ;
   reg x = years y = realyield / degree = 2;
   xaxis grid; yaxis grid label = ' ';
   format realyield percent8.2;
run;
ods html style = htmlbluecml;
********************END OF ALL CODING*****************************************;

Good math, bad engineering

As a formal statistician and a current engineer, I feel that a successful engineering project may require both the mathematician’s abilit...