Carry and Roll-Down on a Yield Curve using R code

This post shows how to calculate a carry and roll-down on a yield curve using R. In the fixed income, the carry is a current YTM like a dividend yield in stock. But unlike stocks, even though market conditions remain constant over time, the remaining maturity (life) is bound to decrease due to its maturity date. This makes so called the roll-down.


Carry and Roll-Down on a Yield Curve



Assume that the following yield curve remains constant over time (1 year).
Calculation of Carry and Roll-Down on the Yield Curve using R code

Carry and roll-down are defined under the yield curve unchanged between an investment horizon (3-month or 1-year and so on)  as follows.


“Carry” is the difference between the yield on a longer-maturity bond and the cost of borrowing (funding cost or risk-free rate or short-term rate).

“Roll” offers capital gains when yields dip with the remaining maturity decreasing.




Carry


If we borrow $1 million at 3% (funding cost) and invest it in a 3-year bond that yields 4% (YTM). After 1 year (investment horizon), we have earned a "carry" of $10,000.

1,000,000 × (4% – 3%) × (360 ÷ 360) = 10,000

Of course, when the investment horizon is a quarter, (360 ÷ 360) is replaced by (90 ÷ 360) in the above equation.



Roll-Down


In the same example above, if we invest $1 million in 3-year bond priced at par (100) and after a year, this bond will be the 2-year bond which price is priced 102 assuming the yield curve is unchanged, we will have gained $20,000.

(102 – 100) × 10,000 = 20,000


R code


The R code below implements the above explanations with 1-year investment horizon and annual coupon payments. Coupon bond price is calculated easily by using derivmkts R package.

We assume that we invest a par coupon bond at time t so that coupon bond price at time t+1 is calculated with time t par yield (coupon rate), t-1 maturity, and time t+1 par yield (discounting).

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
#========================================================#
# Quantitative Financial Econometrics & Derivatives 
# ML/DL using R, Python, Tensorflow by Sang-Heon Lee 
#
# https://shleeai.blogspot.com
#--------------------------------------------------------#
# Carry and Roll-down on the yield curve
#========================================================#
 
graphics.off(); rm(list = ls())
 
library(derivmkts) # bond price function
 
#-------------------------------------------------------
# Input
#-------------------------------------------------------
 
fc    <- 0.01    # funding cost
 
v.mat <- 1:10    # maturity
 
# ytm
v.ytm <- c(0.022,
           0.030,
           0.040,
           0.046,
           0.050,
           0.052,
           0.053,
           0.053,
           0.053,
           0.054
)
 
# placeholder for output
df <- data.frame(mat=v.mat, ytm = v.ytm, p0 = NA, p1 = NA,
                 carry = NA, rolldown = NA, CR = NA)
 
#-------------------------------------------------------
# sequential calculation
#-------------------------------------------------------
for(t in 1:10) {
    
    # bond price at time t
    mat0 <- df$mat[t]
    ytm0 <- df$ytm[t]
    
    df$p0[t] <- bondpv(ytm0, mat0, ytm0, 11)
    
    # bond price at time t+1
    if(t==1) {
        
        df$p1[t] <- 1 # deterministic
        
    } else {
        
        # maturity reduction at time t+1
        mat1 <- df$mat[t-1
        ytm1 <- df$ytm[t-1]
        
        # previous coupon(t) and current ytm(t+1)
        df$p1[t] <- bondpv(ytm0, mat1, ytm1, 11)
    }
    
    # carry
    df$carry[t] <- ytm0 - fc 
    
    # roll-down
    df$rolldown[t] <- (df$p1[t] - df$p0[t])/df$p0[t]
    
    # carry + roll-down
    df$CR[t] <- df$carry[t] + df$rolldown[t]
}
 
#-------------------------------------------------------
# output and graph
#-------------------------------------------------------
print(df)
 
x11(width=16/2, height=9/2);
matplot(df[,c(5,6,7)]*100, type="b", pch = 16:18, lty = 1
        lwd=3, col=1:3, main = "Carry and Roll-down"
        xlab = "maturity(year)", ylab = "yield(%)")
legend("right", cex=1, col=1:3
       legend=c("Carry""Roll-down""Carry + Roll-down"), 
       pch = c(15), border="white", box.lty=0)
 
cs


Running the above R code delivers the following table for the current bond prices and next ones, carry and roll-down yield components.
Calculation of Carry and Roll-Down on the Yield Curve using R code

Finally, the next figure shows a series of carry, roll-down, and their sum. In an upward sloping yield curve, as maturity gets longer, carry is high but roll-down is low and vice versa when maturity gets shorter. It is not the case but a tendency.

However we can find that the sum of two components is maximized at some medium-term maturity as trade-off between them exists.
Calculation of Carry and Roll-Down on the Yield Curve using R code

Concluding Remarks


In this post we have understand the basic concept of carry and roll-down and calculate them by hands with R code. These days there are strong expectation of interest rate hikes. This leads to an increasing curvature of a yield curve. Therefore we can analyze this circumstance where carry and roll-down are higher simultaneously at medium-term maturities. \(\blacksquare\)



No comments:

Post a Comment