Construction of SOFR Index from SOFR Rates

[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 replicates the construction process of the SOFR index from daily SOFR rates. Since this index is published in a daily basis officially, there is no need to make it. But in the process of pricing SOFR swaps and floating rate notes, this sort of calculation is needed.



SOFR Rates and Index


LIBOR will transition to an alternative reference rate. The SOFR(Secured Overnight Financing Rate) is the risk-free alternative reference rates for USD and is an in-arrears rate. Unlike LIBOR, SOFR is a secured overnight rate, not a forward looking term rate. SOFR Averages (30-, 90-, and 180-calendar days) are constructed by the geometric average of the daily rates. There are two method to make them. The first is to use the daily rate directly and the second is to use the SOFR index.

Before going into SOFR Averages, we will calculate SOFR Index at first. The following pages are the information regarding the SOFR.
Additional Information about Reference Rates Administered by the New York Fed (https://www.newyorkfed.org/markets/reference-rates/additional-information-about-reference-rates#sofr_ai_calculation_methodology)
SOFR Averages and Index Data (https://www.newyorkfed.org/markets/reference-rates/sofr-averages-and-index#historical-search)

Daily SOFR rates can be downloaded at the following page.
Secured Overnight Financing Rate (SOFR) (https://fred.stlouisfed.org/series/SOFR)
We try to replicate the SOFR index from the following page.
Daily indicative SOFR averages and index (Apr. 2018 – Feb. 2020) (https://www.newyorkfed.org/medialibrary/media/markets/historical_indicative_sofr_avg_ind_data.xlsx)
The above excel file have the following form (to get all visible rows of averages, some selected rows are hidden)


Before going into the detail, It is important to distinguish between publication date and value date (date of rate). SOFR rate available at publication date is the rate which is determined at previous business date(value date). If there is no holiday and weekend in between, the publiation date is the time \(t\) and the previous business date is the time \(t-1\).

The SOFR Index measures the cumulative index of compounding the SOFR on a unit of investment over time, with the initial value set to 1.00000000 on April 2, 2018, the first value date of the SOFR. The Index is compounded by the value of each SOFR thereafter.

\[\begin{align} \text{SOFR Index at time t} = \prod_{i=April, 3, 2018}^{t} \left( 1 + \frac{SOFR_i \times n_i }{ 360}\right) \end{align}\] Here, \(i\) denotes a sequential business day from April, 3, 2018 to \(t\). \(SOFR_i\) is the SOFR applicable on business day i and \(n_i\) is the number of calendar days for which \(SOFR_i\) applies.

From this SOFR Index, SOFR averages can be calculated using the following formula.

\[\begin{align} \text{SOFR Avg btw x and y} = \left(\frac{\text{SOFR Index_y}}{\text{SOFR Index_x}} -1 \right) \times \left(\frac{360}{dc} \right) \end{align}\]
Here, \(x\) and \(y\) are the start and end date of calculation period respectively. \(dc\) is the number of calendar dates in the calculation period.



We can calculate the SOFR index from the daily SOFR rates using the following R code.

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
#=========================================================================#
# Financial Econometrics & Derivatives, ML/DL using R, Python, Tensorflow  
# by Sang-Heon Lee 
#————————————————————————-#
# Calculation of SOFR Index from Daily SOFR Rates
#=========================================================================#
 
# construction of data frame
df < data.frame(rbind(
    c(“2018-04-02”,    1.00000000,    1.80),
    c(“2018-04-03”,    1.00005000,    1.83),
    c(“2018-04-04”,    1.00010084,    1.74),
    c(“2018-04-05”,    1.00014917,    1.75),
    c(“2018-04-06”,    1.00019779,    1.75),
    c(“2018-04-09”,    1.00034365,    1.75),
    c(“2018-04-10”,    1.00039228,    1.75),
    c(“2018-04-11”,    1.00044091,    1.76),
    c(“2018-04-12”,    1.00048982,    1.73),
    c(“2018-04-13”,    1.00053790,    1.72),
    c(“2018-04-16”,    1.00068131,    1.77),
    c(“2018-04-17”,    1.00073051,    1.76),
    c(“2018-04-18”,    1.00077944,    1.75),
    c(“2018-04-19”,    1.00082809,    1.73),
    c(“2018-04-20”,    1.00087618,    1.72),
    c(“2018-04-23”,    1.00101964,    1.70)))
    
colnames(df) < c(“Pub_Date”,“SOFR_Index”“SOFR_Rate”)
 
# string to date format
df$Pub_Date   < as.Date(df$Pub_Date)
df$SOFR_Index < as.numeric(df$SOFR_Index)
df$SOFR_Rate  < as.numeric(df$SOFR_Rate)
 
for(i in 1:nrow(df)) {
    if (i==1) {
        df$Calc_Index[i] = 1
    } else {
        ni = as.numeric(df$Pub_Date[i]  df$Pub_Date[i1])
        df$Calc_Index[i] = df$Calc_Index[i1]*
                           (1+df$SOFR_Rate[i1]/100*ni/360)
    }
}
 
# rounding at 8-decimal
df$Calc_Index < round(df$Calc_Index,8)
 
# print df
print(df)
cs


In the above R code, data.frame (df) have all data as string formats because Pub_Date is of a string type. Therefore type recast is applied. The content of rest of code is the implementation of the SOFR Index by its formula. The following result shows that Calc_Index (the right most column of df) is the same as the SOFR_Index.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
> print(df)
     Pub_Date SOFR_Index SOFR_Rate Calc_Index
1  20180402   1.000000      1.80   1.000000
2  20180403   1.000050      1.83   1.000050
3  20180404   1.000101      1.74   1.000101
4  20180405   1.000149      1.75   1.000149
5  20180406   1.000198      1.75   1.000198
6  20180409   1.000344      1.75   1.000344
7  20180410   1.000392      1.75   1.000392
8  20180411   1.000441      1.76   1.000441
9  20180412   1.000490      1.73   1.000490
10 20180413   1.000538      1.72   1.000538
11 20180416   1.000681      1.77   1.000681
12 20180417   1.000731      1.76   1.000731
13 20180418   1.000779      1.75   1.000779
14 20180419   1.000828      1.73   1.000828
15 20180420   1.000876      1.72   1.000876
16 20180423   1.001020      1.70   1.001020
> 
cs

Next time, we will make SOFR averages from the SOFR index. After that, we try to get the same results from the direct use of SOFR rates successively. \(\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)