Overview
Data
Here, we just hard code the data as
let data = [
{price:96.60, maturity:1, coupon:2},
{price:93.71, maturity:2, coupon:2.5},
{price:91.56, maturity:3, coupon:3},
{price:90.24, maturity:4, coupon:3.5},
{price:89.74, maturity:5, coupon:4},
{price:90.04, maturity:6, coupon:4.5},
{price:91.09, maturity:7, coupon:5},
{price:92.82, maturity:8, coupon:5.5},
{price:95.19, maturity:9, coupon:6},
{price:98.14, maturity:10, coupon:6.5},
{price:101.60, maturity:11, coupon:7},
{price:105.54, maturity:12, coupon:7.5},
{price:109.90, maturity:13, coupon:8},
{price:114.64, maturity:14, coupon:8.5},
{price:119.73, maturity:15, coupon:9},
];
Basis Functions
Next, the basis functions need to be implemented. The cubic library provides a function, g, which evaluates each basis function given the knot points and the time variable.
let cs = await import('/lib/finance/fixed-income/curves/v1.0.0/cubic.mjs');
let knots = [0,7.5,15];
let test1 = cs.g(0, 2, knots)
let test2 = cs.g(0, 0, knots)
let test3 = cs.g(1, 0, knots)
let test4 = cs.g(2, 8, knots)
let test5 = cs.g(3, 8, knots)
let test6 = cs.g(2, 1, knots)
Try it!
Computing Cash Flows
Next, we compute the cash flows for each bond. This is done by defining a cash flow function to compute the cash flows from the bond defintion. (NOTE: we do not go to the full complexity of using day count conventions etc.... to exactly compute the cash flows. see cash flows. )
let cashFlows = function(item){
let ans = [];
for(let i=1;i<=item.maturity;i++){
if(i==item.maturity){
ans.push({
date:i,
value:100*(1+item.coupon/100)
});
}
else ans.push({
date:i,
value:100*item.coupon
});
}
return ans;
}
Try it!
Computing the C Matrix
The {% C %} matrix is defined by
{% C_{i k} = \sum_{j=1} CF_{ij} \times g_k(t_{j}) %}
That is, there is row for each bond in the dataset. Each column represents a single basis function.
let C = data.map((p,i)=>{
let row = [];
let flows = cashFlows(p);
for(let k=0;k<=knots.length;k++){
let value = 0;
flows.forEach(q=>{
value += q.value * cs.g(k, q.date, knots);
})
row.push(value);
}
return row;
});
Try it!
Computing the Adjusted Price Vector
Next, the vector {% P' %} is computed, given the following defintion.
{% P'_i = P_i - \sum_{j=1} CF_j %}
let sums = [];
data.map((p,i)=>{
let flows = cashFlows(p);
let sum = 0;
flows.forEach(p=>{
sum += p.value;
});
sums.push(sum);
});
let y = data.map((p,i)=>[p.price-sums[i]]);
Computing the Alpha Values
The final equation used to determine the {% \alpha %} values is
{% \vec{P'} = C \vec{\alpha} %}
On the surface, it appears that you could take the inverse of {% C %} and then multiply through. However, {% C %}
is not a square matrix and hence is not invertible. On the other hand,
the
Moore Penrose Inverse
can be applied. This can be effectively implemented using
OLS regression.
let regression = olsregression.regress(y, C);
let alphas = regression.Coefficients.map(p=>p[0]);
Implementation
Try it!