Numerical Calculation of FRN Duration in 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.
The duration of a floating rate note (FRN) is the remaining time until the first next payment date. Using this fact, a duration of FRN has not been calculated explicitly but has been understood conceptually. Instead of this reasoning, this post tries to calculate it directly based on the numerical differentiation using R code. Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
We have investigated the properties of a price and duration of FRN and calculated its price in the following previous post
Price and Duration of FRN
In the previous post, we find that a price of FRN at time \(t\) is. \[\begin{align} P_{zero}^{FRN} &= \begin{cases} 1, & \text{payment date} \\ D_{0,\tau} (1+R_{reset}), & \text{otherwise}\\ \end{cases} \\ \\ \tau &= t_{payment}^{1st} – t \end{align}\] Here \(t_{payment}^{1st}\) is the first next payment dates after the pricing date (\(t\)). \(D(0,t)\) denotes a discount factor for a cashflow at time \(t\).
Duration of FRN is zero right before the reset date and is an interest payment period right after the reset date and is a linearly interpolated year when pricing date is between two consecutive payment dates. Duration of FRN is summarized as follows. \[\begin{align} D_{zero}^{FRN} = \begin{cases} 0, & \text{payment date} \\ \tau, & \text{otherwise}\\ \end{cases} \end{align}\]
Effective Duration
The effective duration is of the follwing form of numerical differentiation. \[\begin{align} D &= \frac{P_u – P_d}{2 \Delta y \times P_0} \end{align}\] Here, \(P_0\) denotes an initial bond price with yield to maturity (\(y\)). \(P_u\) and \(P_d\) represent bond prices after downward (\(y-\Delta y\)) and upward (\(y+\Delta y\)) shocks to interest rates (yield to maturity) respectively.
Refer the following post for more details of the effective duration
We intend to use this formula to calculate a FRN duration but how can we apply this YTM change in the framework of FRN pricing? For this matter, we need to generate a zero curve from a parallel shift of the YTM curve.
Zero curve from Parallel Shift of YTM curve
Unlike the fixed rate bond which can be priced by using the YTM or zero pricing, FRN use zero pricing so that when we apply the numerical differentiation for duration, we need to generate a zero curve from a parallel shift of market yield (YTM or swap rate) curve which consists of market instruments. The following figure shows three zero curves generated from baseline,1 bp upward shifted, and 1 bp downward shifted YTM curves.
Refer the following post for more details of a zero curve bootstrapping
In summary, in duration calculation, a change in the market yield curve means a parallel shift of the market yield curve, not a individual yield change at a specific maturity.
R code
The following R code implements the above effective duration formula and applies it to the calculation of 3-year FRN’s duration with quarterly frequency, and finally compares it with the actual remaining time between the pricing date and the first next payment date (\(\tau\)) for three cases (pricing date : t=0, 1/12, 2/12).
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 | #========================================================# # Quantitative ALM, Financial Econometrics & Derivatives # ML/DL using R, Python, Tensorflow by Sang-Heon Lee # # https://kiandlee.blogspot.com #——————————————————–# # Calculate a duration of FRN # using numerical differentiation #========================================================# graphics.off() # clear all graphs rm(list = ls()) # remove all files from your workspace #——————————————————- # Input #——————————————————- # continuously compounded zero rate # zr0 : baseline zero curve # zru : zero curve generated from 1 bp downward shifted YTM curve # zrd : zero curve generated from 1 bp upward shifted YTM curve str.zero <–“month zr0 zru zrd 3 0.006594635 0.006694472 0.006494797 6 0.006819495 0.006919243 0.006719675 9 0.00704844 0.007148193 0.006948601 12 0.00731956 0.007419349 0.007219723 15 0.007630967 0.007730765 0.007531127 18 0.00794161 0.008041417 0.007841763 21 0.008232426 0.008332244 0.008132565 24 0.008522513 0.008622352 0.008422642 27 0.008767559 0.008867411 0.008667681 30 0.009012877 0.009112739 0.008912988 33 0.009257467 0.009357346 0.009157564 36 0.00960459 0.009704503 0.009504658″ df.raw <– read.table(text = str.zero, header = TRUE) k <– 4 # interest payment frequency (quarterly) dr <– 0.0001 # yield change (1 bp) #——————————————————- # Calculation of Price and Duration of FRN # by using Numerical Differentiation #——————————————————- for(t in c(0,1,2)) { # initialize df <– df.raw # remaining maturity (monthly) df$mat <– (df$month – t)/12 # interest period df$tau <– df$mat df$tau[2:12] <– df$mat[2:12] – df$mat[1:11] # discount factor df$df0 <– exp(–df$zr0*df$mat) df$dfu <– exp(–df$zru*df$mat) df$dfd <– exp(–df$zrd*df$mat) # forward rate df$fd0 <– df$zr0 df$fdu <– df$zru df$fdd <– df$zrd df$fd0[2:12] <– (1/df$tau[2:12])*(df$df0[1:11]/df$df0[2:12]–1) df$fdu[2:12] <– (1/df$tau[2:12])*(df$dfu[1:11]/df$dfu[2:12]–1) df$fdd[2:12] <– (1/df$tau[2:12])*(df$dfd[1:11]/df$dfd[2:12]–1) # reset the first coupon rate when pricing date is reset date # assumption of no reset lag if(t == 0) { # reset date # newly reset the reference index r0_reset <– 0.00660 # spot rate at spot date ru_reset <– 0.00660 rd_reset <– 0.00660 } # forward rates as cash flows df$cf0 <– df$fd0/k df$cfu <– df$fdu/k df$cfd <– df$fdd/k # set the first coupon rate df$cf0[1] <– r0_reset/k df$cfu[1] <– ru_reset/k df$cfd[1] <– rd_reset/k # add nominal principal (1) df$cf0[nrow(df)] <– 1 + df$cf0[nrow(df)] df$cfu[nrow(df)] <– 1 + df$cfu[nrow(df)] df$cfd[nrow(df)] <– 1 + df$cfd[nrow(df)] # FRN price as sum of discounted variable CF P0 <– sum(df$df0*df$cf0) Pd <– sum(df$dfu*df$cfu) Pu <– sum(df$dfd*df$cfd) Dr <– (Pu–Pd)/(2*dr)/P0 # Duration # Print cat(paste0(“\nResults for FRN (t=”,t,“)\n\n”, “Price = “, P0, “\n”, “Duration = “, Dr, “\n”, “time to the first next payment date\n”, ” = “, (3–t)/12, “\n\n”)) } | cs |
From he following output of the above R code, we can find that the duration of FRN for each case is equal to the actual remaining time between the pricing date and the first next payment date (\(\tau\))
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 | # Print Results for FRN (t=0) Price = 0.999999981495524 Duration = 0.249593750056916 time to the first next payment date = 0.25 Results for FRN (t=1) Price = 1.00054968543389 Duration = 0.166395833356961 time to the first next payment date = 0.166666666666667 Results for FRN (t=2) Price = 1.00109969154668 Duration = 0.0831979166709382 time to the first next payment date = 0.0833333333333333 | cs |
Concluding Remarks
From this post, we calculate the duration of FRN directly by using numerical differentiation. This intuitive exercise reminds us of fact that a market yield change means a parallel shift of the market yield curve and then this change is translated and spread to a zero curve change. This is plain but easy to overlook. Using this changed zero curve, an effective duration of FRN can be obtained numerically.
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.