Numerical Calculation of FRN Duration in R

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.



Numerical Calculation of FRN Duration



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}^\text{1st next} - t \end{align}\] Here \(t_{payment}^\text{1st next}\) is the first next payment date after the pricing date (\(t\)). \(D(0,t)\) denotes a discount factor for a cash flow at time \(t\). \(R_{reset}\) is the predetermined fixing rate at the very previous reset date.

Duration of FRN is zero right before the payment date and is an interest payment period right after the payment 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 (\(\Delta y \)) in the framework of FRN pricing? It's because we do use a zero curve to price a FRN instead of a YTM curve. For this matter, we need to generate zero curves from parallel shifts of the a YTM curve (\(y \pm \Delta y \)).


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.

Numerical Calculation of Duration of FRN in R


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 Financial Econometrics & Derivatives 
# ML/DL using R, Python, Tensorflow by Sang-Heon Lee 
#
# https://shleeai.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/
        df$cfu[1<- ru_reset/
        df$cfd[1<- rd_reset/
        
        # 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. \(\blacksquare\)


No comments:

Post a Comment