Key Rate Duration using R code
Ho (1992) introduced the concept of the key rate duration (hereafter KRD), which is a new measure of interest rate risk exposure. KRD is a vector of the price sensitivity of a bond to each key rate change. The sum of the key rate durations is identical to the effective duration. The sum of the product of key rate durations and each yield changes in key rates (with negative sign) is the bond price change due to the non-parallel shift of the yield curve.
Key Rate Shifts
Unlike the traditional effective duration, KRD is calculated not from a par yield curve but from a zero curve (spot rate) so that the bump and reprice are performed on selected spot rates (key rates). In other words, individual effective durations are calculated by shift of each spot rate at each key maturity and the sum of them is the KRD.
Formally, ith key rate shift is defined to be zero shift for maturities shorter than (i-1)th key rate and longer than (i+1)th key rate. Interestingly, the shift between these two adjacent key rates is defined by the linear interpolation with the peak at the ith key rate.
As can be seen in the above figure, yellow colored maturity is assumed to be the selected maturities of key rates. Ho (1992) suggests the size of shift as 10 bp but we use 1%(=100bp) simply for illustration purpose. A shift of one key rate by 1% affects its neighborhood of that key rate with linear interpolation. Rates outside the range of selected key maturities are set simply by the nearest key rate.
In particular, the light blue colored line (bottom) illustrates the shifts at all maturities, which resulted from 60M key rate's change. In this case, all the key rates except 60M are not affected but two adjacent rates at 54M and 66M are affected linearly.
The ith shifted yield curve is the sum of the initial yield curve (blue colored solid line) and its shifts at all maturities, which resulted from the change of ith key rate. When we add up all shifted changes together on the initial yield curve, we can get the parallel shifted curve (red colored solid line).
Key Rate Durations
By shifting each key rates, we can get N shifted zero curves (N is the number of key rates). Using these N shifted zero curves, each effective duration (\(KRD_i, i=1,...,N \)) is calculated with the initial zero curve.
\[\begin{align} KRD_i = \frac{P_{i,down} - P_{i,up}}{2 \times P_0 \times \Delta s(t_i)} \end{align}\]
Here, \(P_{i,down}\) and \(P_{i,up}\) are bond prices with up and down shifts to ith key rate respectively and \(s(t_i)\) is a spot rate at time \(t_i\).
The percent change in bond price given a shift in ith key rate is calculated as follows.
\[\begin{align} \frac{\Delta P_i}{P} = -KRD_i \times \Delta s(t_i) \end{align}\]
By definition, the sum of KRDs is the effective duration of a bond.
\[\begin{align} D = \sum_{i=1}^N KRD_i \end{align}\]
The shift of the yield curve can be approximated by the sum of all the key rate shifts.
\[\begin{align} \frac{\Delta P}{P} = - \sum_{i=1}^N KRD_i \times \Delta s(t_i) \end{align}\]
Key Rate Shifts in R code
As will be shown in R code, it is worth noting that a vector of shifts due to a key rate movement is appended horizontally with the name of its key rates as follows.
Therefore, each shifted zero curve can be calculated by simply summing the initial zero curve and the corresponding shift vector.
R code
R code below implements the above explanations. After calculating we compare the sum of key rate durations with the traditional effective duration. When we use not 0.01 (1%) but 0.0001 (1bp) as a small change in a key rate, two duration measures are nearly the same in the perspective of numerical calculation.
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 | #========================================================# # Quantitative Financial Econometrics & Derivatives # ML/DL using R, Python, Tensorflow by Sang-Heon Lee # # https://shleeai.blogspot.com #--------------------------------------------------------# # Key Rate Durations #========================================================# graphics.off(); rm(list = ls()) #======================================================= # read data #======================================================= str.zero <- "matm zero 12 0.022 24 0.030 36 0.040 48 0.046 60 0.050 72 0.052 84 0.053 96 0.053 108 0.053 120 0.054" df <- read.table(text = str.zero, header = TRUE) v.key_matm <- df$matm # maturities for key rates nkey <- length(v.key_matm) # linear interpolation of zero rates f_interpol <- approxfun(df$matm, df$zero, rule = 2) # fill rates between key rates by 6M tenor matm = seq(6,120,6) df.sa <- data.frame(matm = matm) nobs <- length(matm) df.sa$zero <- f_interpol(matm) # 10Y YTM YTM10 <- 0.0527780789520333 CPN10 <- YTM10 # 10Y coupon = par yield rate #======================================================= # read data #======================================================= # rate shift : 0.0001 is preferable dr = 0.0001 # make a table of dr for each key rates for(n in 1:nkey) { df.sa <- cbind(df.sa, NA) colnames(df.sa)[2+n] <- as.character(v.key_matm[n]) key_matm <- v.key_matm[n] # set dr to the same key maturity # set 0 to other key rates # set NA to rates between key rates for(i in 1:nobs) { matmi <- df.sa$matm[i] if(matmi == key_matm) { df.sa[i,2+n] <- dr } else if (matmi %in% v.key_matm){ df.sa[i,2+n] <- 0 } } # rates between key rates is linearly interpolated f_interpol <- approxfun(matm, df.sa[,2+n], rule = 2, na.rm = TRUE) df.sa[,2+n] <- f_interpol(matm) } # p0 zero <- df.sa$zero P0 <- sum((YTM10/2)/(1+zero/2)^(matm/6)) + 1/(1+zero[nobs]/2)^(matm[nobs]/6) # all the key rate shifts zerou <- zero + rowSums(df.sa[,1:nkey+2]) zerod <- zero - rowSums(df.sa[,1:nkey+2]) # effective duration : traditional Pu <- sum((YTM10/2)/(1+zerou/2)^(matm/6)) + 1/(1+zerou[nobs]/2)^(matm[nobs]/6) Pd <- sum((YTM10/2)/(1+zerod/2)^(matm/6)) + 1/(1+zerod[nobs]/2)^(matm[nobs]/6) ED <- (Pd - Pu)/(2*P0*dr) # Key rate duations df.KRD <- data.frame(matm = df$matm, ED = NA) for(n in 1:nkey) { # key rate shifts zerou <- zero + df.sa[,2+n] zerod <- zero - df.sa[,2+n] # effective duration : KRD Pu <- sum((YTM10/2)/(1+zerou/2)^(matm/6)) + 1/(1+zerou[nobs]/2)^(matm[nobs]/6) Pd <- sum((YTM10/2)/(1+zerod/2)^(matm/6)) + 1/(1+zerod[nobs]/2)^(matm[nobs]/6) df.KRD[n,2] <- (Pd - Pu)/(2*P0*dr) } df.KRD # check if sum of KRDs is equal to effective duration dr sum(df.KRD$ED) ED | cs |
Running this R code, we can get the following results which show that calculation of key rate durations is proper when we use 1bp as the size of shift. Of course, it depends on which problem is investigated.
Concluding Remarks
In this post we implemented the key rate durations which is invented by Ho (1992). This can be used in the case of the non-parallel shifts of yield curve and has broad application: replicating portfolio of option embedded bonds, managing fixed-income portfolio, analyzing complex interest rate contingent claims, and so on.
Reference
Ho, T.S.Y. (1992), "Key Rate Durations: Measures of Interest Rate Risks," The Journal of Fixed Income 2-2, pp.29-44. \(\blacksquare\)
No comments:
Post a Comment