Black-Derman-Toy Interest Rate model using R

[This article was first published on K & L Fintech Modeling, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

This post implements Black-Derman-Toy (BDT) interest rate tree using R. This implementation is based on the previous post for BDT model.



R Implementation of BDT Interest Rate Tree



We implement BDT tree according to the content of the previous post. The previous post below explains BDT model and provides Excel illustration for the clear understanding.


Black-Derman-Toy Interest Rate model using R

Like previous post, we try to replicate BDT paper’s result.


Two Requirements for No-arbitrage Condition



As stated in previous post, for BDT short rate tree to be arbitrage free, this interest rate tree should fit a given initial term structure exactly. \[\begin{align} P_{…u} &= \frac{1}{2}\frac{P_{…uu}+P_{…ud}}{1+r_{…u}} \\ P_{…d} &= \frac{1}{2}\frac{P_{…du}+P_{…dd}}{1+r_{…d}} \end{align}\] Cross-sectional (at the same time) two adjacent short rates and spot rates are given the following intra volatility restrictions. (\(\Delta t = 1\)) \[\begin{align} \sigma_t^r = \frac{1}{2}\log\left(\frac{r_{…u}}{r_{…d}}\right) \end{align}\] \[\begin{align} \sigma_t^y = \frac{1}{2}\log\left(\frac{y_{u}}{r_{d}}\right) \end{align}\]

R code


Using the above two constraints, we use R optimization to solve for the 8 unknown variables problem. The objective function returns sum of two distances between market and model quantities: discount factors and yield volatilities.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#========================================================#
# Quantitative ALM, Financial Econometrics & Derivatives 
# ML/DL using R, Python, Tensorflow by Sang-Heon Lee 
#
# https://kiandlee.blogspot.com
#——————————————————–#
# Black-Derman-Toy Interest Rate Tree
#========================================================#
 
graphics.off()  # clear all graphs
rm(list = ls()) # remove all files from your workspace
 
#————————————————
# construct short rate tree (rt)
#————————————————
generate_BDT_tree < function(v.rd, v.rv, nmat) {
    
    df.rt  < matrix(0, nmat, nmat) 
    df.rt[1,1< v.rd[1# r0
    for(t in 2:nmat) {
        df.rt[t,t] < v.rd[t]
        for(s in (t1):1) { # cross-sectional iteration
            df.rt[s,t] < df.rt[s+1,t]*exp(2*v.rv[t])
        }
    }
    return(df.rt)
}
 
#————————————————
# discount cash flow at maturity using BDT tree
#————————————————
pricing_BDT_tree < function(df.BDT_tree, v.cf, nmat) {
    
    df.rt < df.BDT_tree
    t     < nmat
    df.pt < matrix(0, t+1, t+1)
    df.pt[,t+1< v.cf # cash flow at maturity
    
    for(b in t:1) { # backward induction
        for(s in 1:b) { # cross-sectional iteration
            df.pt[s,b] < 0.5*
           (df.pt[s,b+1]+df.pt[s+1,b+1])/(1+df.rt[s,b])
        }
    }
    return(df.pt)
}
 
#————————————————
# objective function
#————————————————
# v.unknown : rd, rdd, …, rv2, rv3, …
# df.mkt    : data.frame for mat, y, yv
#————————————————
objfunc_BDT_tree < function(v.unknown, df.mkt) {
    
    v.unknown < v.unknown^2 # non-negativity 
    nmat < length(df.mkt$mat)
 
    # short rate and its volatility 
    v.rd < c(df.mkt$y[1], v.unknown[1:(nmat1)])
    v.rv < c(df.mkt$yv[1],v.unknown[nmat:(2*(nmat1))])
    
    # construct rate tree(rt)
    df.rt < generate_BDT_tree(v.rd, v.rv, nmat)
   
    #————————————————
    # make a price tree for each maturity
    # calculate discount factor difference
    # calculate yield volatility difference
    #————————————————
    v.df_diff < v.yv_diff < rep(0,nmat1)
    
    for(t in 2:nmat) {
        df.pt < pricing_BDT_tree(df.rt, 1, t) 
 
        # difference between model and 
        # market discount factor at time 0
        v.df_diff[t1< df.pt[1,1 1/(1+df.mkt$y[t])^t
        
        # difference between yield volatilities 
        # from up & down discount factors (model) and
        # market discount factors
        yu < (1/df.pt[1,2])^(1/(t1))1
        yd < (1/df.pt[2,2])^(1/(t1))1
        yv < log(yu/yd)/2
        v.yv_diff[t1< yv  df.mkt$yv[t]
    }
    return(sqrt(sum(v.df_diff^2+ sum(v.yv_diff^2)))
}
 
#————————————————
#                   Main
#————————————————
 
# Input data : maturity, yield, yield volatility
df.mkt < data.frame(
    mat = c(12345),            
    y   = c(0.10.110.120.1250.13),
    yv    = c(0.20.190.180.17,  0.16)
)
 
# initial guess for short rate and volatility
# short rate : rd, rdd, rddd, rdddd
# short rate volatilities : rv2, rv3, rv4, rv5
v.initial_guess < c(0.1,  0.1,  0.1,  0.1,  # rd
                     0.190.180.170.16# rv
v.initial_guess < sqrt(v.initial_guess)
 
# calibration of BDT tree
m<optim(v.initial_guess, objfunc_BDT_tree,
         control = list(maxit=5000, trace=2, reltol = 1e16),
         method=c(“BFGS”),df.mkt = df.mkt)
 
# transform and split parameters
v.param_trans < m$par^2
nmat < 5
 
# final calibrated parameters
# short rate : r0, rd, rdd, rddd, rdddd
(v.rd < c(df.mkt$y[1],  v.param_trans[1:(nmat1)]))
# short rate volatilities : rv1, rv2, rv3, rv4, rv5
(v.rv < c(df.mkt$yv[1], v.param_trans[nmat:(2*(nmat1))]))
 
# final BDT short rate tree
(df.rt < generate_BDT_tree(v.rd, v.rv, nmat))
 
# final BDT price tree (5-year)
(pricing_BDT_tree(df.rt, 1, nmat))
 
cs


The above R code is implemented from the logic of the previous post.

generate_BDT_tree() function returns a BDT short rate tree with arguments of unknown short rates and its volatilities. pricing_BDT_tree() function uses backward induction to discount cash flows at maturity using the BDT short rate tree and returns a price tree. Of course, the first element of the price tree is the price of zero coupon bond.

objfunc_BDT_tree() function is the objective function to be minimized, which returns a sum of squared errors of discount factors and yield volatilities. In the objective function, unknown variables are squared because yield volatility is always non-negative and in lognormal model, interest rate is non-negative.

Running the above R code, we can obtain the following results which are the same as that of the previous post.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
> # final calibrated parameters
>
> # short rate : r0, rd, rdd, rddd, rdddd
[1] 0.10000000 0.09791528 0.09760006 0.08717225 0.08653488
>
> # short rate volatilities : rv1, rv2, rv3, rv4, rv5
[1] 0.2000000 0.1899992 0.1719859 0.1526818 0.1352092
> # final BDT short rate tree (5-year)
     [,1]       [,2]       [,3]       [,4]       [,5]
[1,]  0.1 0.14317978 0.19418699 0.21788708 0.25524429
[2,]  0.0 0.09791528 0.13766867 0.16055127 0.19476675
[3,]  0.0 0.00000000 0.09760006 0.11830307 0.14861875
[4,]  0.0 0.00000000 0.00000000 0.08717225 0.11340505
[5,]  0.0 0.00000000 0.00000000 0.00000000 0.08653488
> # final BDT price tree (5-year)
          [,1]      [,2]      [,3]      [,4]      [,5] [,6]
[1,] 0.5427603 0.5509767 0.5888395 0.6706866 0.7966577    1
[2,] 0.0000000 0.6430960 0.6708913 0.7356824 0.8369835    1
[3,] 0.0000000 0.0000000 0.7412386 0.7908217 0.8706109    1
[4,] 0.0000000 0.0000000 0.0000000 0.8363453 0.8981457    1
[5,] 0.0000000 0.0000000 0.0000000 0.0000000 0.9203570    1
[6,] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000    1
cs



Concluding Remarks


From this post, we have implemented BDT short rate tree using R’s optimization routine. This will be used for pricing a fixed income derivatives such as callable bonds and for generating interest rate scenarios for multi-stage stochastic linear programming. \(\blacksquare\)


To leave a comment for the author, please follow the link and comment on their blog: K & L Fintech Modeling.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)