Description
Bootstrap.gms: Bootstrapping the yield curve. Consiglio, Nielsen and Zenios. PRACTICAL FINANCIAL OPTIMIZATION: A Library of GAMS Models, Section 4.2.3 Last modified: Apr 2008.
Category : GAMS FIN library
Mainfile : Bootstrap.gms includes : BondData.inc
$title Bootstrapping the yield curve
* Bootstrap.gms: Bootstrapping the yield curve.
* Consiglio, Nielsen and Zenios.
* PRACTICAL FINANCIAL OPTIMIZATION: A Library of GAMS Models, Section 4.2.3
* Last modified: Apr 2008.
SET Time Time periods /2001 * 2011/;
ALIAS (Time, t, t1, t2);
SCALARS
Now Current year;
Now = 2001;
PARAMETER
tau(t) Time in years;
* Note: time starts from 0
tau(t) = ORD(t)-1;
SET
Bonds Bonds universe
/DS-8-06, DS-8-03, DS-7-07,
DS-7-04, DS-6-11, DS-6-09,
DS-6-02, DS-5-05, DS-5-03, DS-4-02/;
ALIAS(Bonds, i);
PARAMETERS
Price(i) Bond prices
Coupon(i) Coupons
Maturity(i) Maturities
F(t,i) Cashflows;
* Bond data. Prices, coupons and maturities from the Danish market
$include "BondData.inc"
* Copy/transform data. Note division by 100 to get unit data, and
* subtraction of "Now" from Maturity date (so consistent with tau):
Price(i) = BondData(i,"Price")/100;
Coupon(i) = BondData(i,"Coupon")/100;
Maturity(i) = BondData(i,"Maturity") - Now;
* Calculate the ex-coupon cashflow of Bond i in year t:
F(t,i) = 1$(tau(t) = Maturity(i))
+ coupon(i) $ (tau(t) <= Maturity(i) AND tau(t) > 0);
VARIABLES
r(t) Spot rates
SumOfSquareDev Sum of square deviations;
EQUATION
ObjDef Objective function definition;
ObjDef.. SumOfSquareDev =e= SUM(i, sqr(Price(i) - SUM(t, F(t,i) * exp(-r(t) * tau(t)))));
OPTION SOLVEOPT = REPLACE;
MODEL BootstrapSimple /ObjDef/;
SOLVE BootstrapSimple MINIMIZING SumOfSquareDev USING NLP;
FILE TermStructureHandle /"TermStructure.csv"/;
TermStructureHandle.pc = 5;
PUT TermStructureHandle;
* Write the heading
PUT "Simple Bootstrap"/;
PUT "Time (in years)","Spot Rates","Discount Factors","Forward Rates"/;
* Calculate and store in a file the results: spot rates and discount factors
PARAMETER
Forward(t) One-period forward rates
Discount(t) Discount factors;
Forward(t) = r.l(t) $ ( tau(t) = 0 ) + ((tau(t) * r.l(t) - tau(t-1) * r.l(t-1)) / (tau(t) - tau(t-1))) $ (tau(t) > 0 );
Discount(t) = exp(-r.l(t) * tau(t));
LOOP (t$(tau(t) > 0),
PUT tau(t),r.l(t):6:5,Discount(t):6:5,Forward(t):6:5/;
);
* Also calculate the yield-to-maturity y(i) of each bond.
* This is done by solving a Constrained Nonlinear System, CNS:
POSITIVE VARIABLES
y(i) Yield-to-Maturity of the bonds;
EQUATION
YieldDef(i) Equations defining the yield-to-maturity;
YieldDef(i) .. Price(i) =E= SUM(t, F(t,i) * exp(-y(i) * tau(t)));
MODEL FindYTM /YieldDef/;
* Solve as a square system for the yields-to-maturity
SOLVE FindYTM USING CNS;
PARAMETERS
PriceErrors(i) Price errors;
PriceErrors(i) = Price(i) - SUM(t, F(t,i) * exp(-r.l(t) * tau(t)));
* Write the heading
PUT "Bond","Yield-To-Maturity","Price error"/;
LOOP (i,
PUT i.tl,y.l(i):6:5,PriceErrors(i):6:5/;
);
* Model with positive forward constraints
EQUATION
PosForwardCon(t) Equations to constraint forward rates to be positive;
PosForwardCon(t)$(tau(t) > 0).. tau(t) * r(t) =g= tau(t-1) * r(t-1);
MODEL BootstrapPosForward /ObjDef,PosForwardCon/;
SOLVE BootstrapPosForward MINIMIZING SumOfSquareDev USING NLP;
Forward(t) = r.l(t) $ ( tau(t) = 0 ) + ((tau(t) * r.l(t) - tau(t-1) * r.l(t-1)) / (tau(t) - tau(t-1))) $ (tau(t) > 0 );
Discount(t) = exp(-r.l(t) * tau(t));
PUT "Positive Forwards Bootstrap"/;
PUT "Time (in years)","Spot Rates","Discount Factors","Forward Rates"/;
LOOP (t$(tau(t) > 0),
PUT tau(t),r.l(t):6:5,Discount(t):6:5,Forward(t):6:5/;
);
* Solve as a square system for the yields-to-maturity
SOLVE FindYTM using CNS;
PriceErrors(i) = Price(i) - SUM(t, F(t,i) * exp(-r.l(t) * tau(t)));
* Write the heading
PUT "Bond","Yield-To-Maturity","Price error"/;
LOOP (i,
PUT i.tl,y.l(i):6:5,PriceErrors(i):6:5/;
);
SCALARS
totalError
lambda;
VARIABLES
WeightedSumOfSquares
POSITIVE VARIABLES
ForwardRates(t) One-period forward rates;
EQUATIONS
WeightedObjFun
ForwardDef(t) Equations defining the forward rates;
WeightedObjFun.. WeightedSumOfSquares =e= lambda * SUM(i, sqr(Price(i) - SUM(t, F(t,i) * exp(-r(t) * tau(t))))) + (1-lambda) *
SUM(t$(tau(t) > 0), sqr( ForwardRates(t) - ForwardRates(t-1)));
* Recall that the first forward rate, F(0,1), coincides with the one period spot rate
ForwardDef(t).. ForwardRates(t) =E= r(t) $ ( tau(t) = 0 ) +
((tau(t) * r(t) - tau(t-1) * r(t-1)) / (tau(t) - tau(t-1))) $ (tau(t) > 0 );
MODEL BootstrapSmooth /WeightedObjFun,ForwardDef/;
PUT "Smooth Bootstrap"/;
FOR( lambda = 1.0 DOWNTO 0.0 BY 0.25,
SOLVE BootstrapSmooth MINIMIZING WeightedSumOfSquares USING NLP;
PUT "Lambda","Average Error"/;
totalError = SUM(i, sqr(Price(i) - SUM(t, F(t,i) * exp(-r.l(t) * tau(t)))))
PUT lambda:3:1,totalError:6:5/
PUT "Time (in years)","Spot Rates","Discount Factors","Forward Rates"/;
* Calculate and store in a file the results: spot rates and discount factors
Discount(t) = exp(-r.l(t) * tau(t));
LOOP (t$(tau(t) > 0),
PUT tau(t),r.l(t):6:5,Discount(t):6:5,ForwardRates.l(t):6:5/;
);
);
* Write spot rates to SpotRates.inc and
* yield-to-maturity to YieldRates.inc
* These data will be used by Immunization.gms .
* A smoothing parameter equal to 0.5 guarantees a
* reasonable term structure.
lambda = 0.5
SOLVE BootstrapSmooth MINIMIZING WeightedSumOfSquares USING NLP;
FILE SpotRatesHandle /"SpotRates.inc"/;
PUT SpotRatesHandle;
LOOP (t$(tau(t) > 0),
PUT t.tl:0:0,",",r.l(t):6:5/;
);
PUTCLOSE SpotRatesHandle;
FILE YieldRatesHandle /"YieldRates.inc"/;
PUT YieldRatesHandle;
LOOP (i,
PUT i.tl:0:0,",",y.l(i):6:5/;
);
DISPLAY r.l,y.l;