Disclaimer: The content of this RMarkdown note came from a course called Analyzing Financial Data and Implementing Financial Models Using R.
how to calculate total return
Key Issues
Calculate the daily price returns for IBM stock form 2011 to 2013. Use IBM stock as the example b/c IBM pays dividends so we can compare the results for price returns and total returns.
# To clean up the memory of your current R session run the following line
rm(list=ls(all=TRUE))
# Step 1: Import IBM Data from Yahoo Finance
library(quantmod)
library(xts)
data.IBM <- read.csv("data/IBM Yahoo.csv")
head(data.IBM)
## Date Open High Low Close Volume Adj.Close
## 1 2013-12-31 186.49 187.79 186.30 187.57 3619700 169.4835
## 2 2013-12-30 185.32 186.70 184.67 186.41 3018600 168.4353
## 3 2013-12-27 185.84 186.50 184.56 185.08 3381600 167.2336
## 4 2013-12-26 183.56 185.56 183.51 185.35 3325700 167.4775
## 5 2013-12-24 181.96 183.50 181.91 183.22 1613600 165.5529
## 6 2013-12-23 181.05 182.93 180.61 182.23 4079900 164.6584
date <- as.Date(data.IBM$Date, format("%Y-%m-%d"))
data.IBM <- cbind(date, data.IBM[, -1])
data.IBM <- data.IBM[order(data.IBM$date), ]
data.IBM <- xts(data.IBM[, 2:7], order.by = data.IBM$date)
names(data.IBM) <- c("IBM.Open", "IBM.High", "IBM.Low",
"IBM.Close", "IBM.Volume", "IBM.Adjusted")
data.IBM[c(1:3, nrow(data.IBM)), ]
## IBM.Open IBM.High IBM.Low IBM.Close IBM.Volume IBM.Adjusted
## 2010-12-31 146.73 147.07 145.96 146.76 2969800 125.8031
## 2011-01-03 147.21 148.20 147.14 147.48 4603800 126.4203
## 2011-01-04 147.56 148.22 146.64 147.64 5060100 126.5574
## 2013-12-31 186.49 187.79 186.30 187.57 3619700 169.4835
# Adj price doesn't match the textbook
# This is due to div payments and stock splits after this book was published
# Refer to the discussion regarding this topic in total returns (p. 58)
# Step 2: Subset the Data to Only Include the Closing Price
IBM.prc.ret <- data.IBM[, 4]
IBM.prc.ret[c(1:3, nrow(IBM.prc.ret)), ]
## IBM.Close
## 2010-12-31 146.76
## 2011-01-03 147.48
## 2011-01-04 147.64
## 2013-12-31 187.57
# Step 3: Calculate IBM's Price Return
IBM.prc.ret$IBM.prc.ret <- Delt(IBM.prc.ret$IBM.Close)
IBM.prc.ret[c(1:3, nrow(IBM.prc.ret)), ]
## IBM.Close IBM.prc.ret
## 2010-12-31 146.76 NA
## 2011-01-03 147.48 0.004905976
## 2011-01-04 147.64 0.001084913
## 2013-12-31 187.57 0.006222858
# Step 4: Clearn up Data Object
options(digits = 3)
IBM.prc.ret <- IBM.prc.ret[-1, 2]
IBM.prc.ret[c(1:3, nrow(IBM.prc.ret)), ]
## IBM.prc.ret
## 2011-01-03 0.00491
## 2011-01-04 0.00108
## 2011-01-05 -0.00400
## 2013-12-31 0.00622
options(digits = 7)
A Note on Stock Splits and the Use of Closing Prices from Yahoo Finance (p. 57)
Calculate IBM’s total returns from January 2011 to December 2013.
Total return is the sum of
Adj closing price (Yahoo Finance) incorporates:
The adjustments are made retroactively
Three dividend dates in understanding total returns
# Step 1: Import Adjusted Closing Price Data
IBM.ret <- data.IBM[, 6]
IBM.ret[c(1:3, nrow(IBM.ret)), ]
## IBM.Adjusted
## 2010-12-31 125.8031
## 2011-01-03 126.4203
## 2011-01-04 126.5574
## 2013-12-31 169.4835
# Step 2: Calculate Total Return
IBM.ret$tot.ret <- Delt(IBM.ret$IBM.Adjusted)
IBM.ret[c(1:3, nrow(IBM.ret)), ]
## IBM.Adjusted tot.ret
## 2010-12-31 125.8031 NA
## 2011-01-03 126.4203 0.004905977
## 2011-01-04 126.5574 0.001084913
## 2013-12-31 169.4835 0.006222858
# Step 3: Clean up the Data
options(digits = 3)
IBM.ret <- IBM.ret[, 2] #typo on page 61: it reads IBM.log.ret when it's IBM.ret
IBM.ret[c(1:3, nrow(IBM.ret)), ]
## tot.ret
## 2010-12-31 NA
## 2011-01-03 0.00491
## 2011-01-04 0.00108
## 2013-12-31 0.00622
options(digits = 7)
simple return versus logarithmic returns Logarithmic returns makes it easier to calculate cumulative returns.
Calculate the logarithmic total returns for IBM stock from January 2011 to December 2013.
# Step 1: Import Adjusted Closing Price Data
IBM.log.ret <- data.IBM[, 6]
IBM.log.ret[c(1:3, nrow(IBM.ret)), ]
## IBM.Adjusted
## 2010-12-31 125.8031
## 2011-01-03 126.4203
## 2011-01-04 126.5574
## 2013-12-31 169.4835
# Step 2: Calculate Log Returns
IBM.log.ret$IBM.log.ret <- diff(log(IBM.log.ret$IBM.Adjusted))
IBM.log.ret[c(1:3, nrow(IBM.ret)), ]
## IBM.Adjusted IBM.log.ret
## 2010-12-31 125.8031 NA
## 2011-01-03 126.4203 0.004893982
## 2011-01-04 126.5574 0.001084325
## 2013-12-31 169.4835 0.006203576
# Step 3: Clean up the Data
options(digits = 3)
IBM.log.ret <- IBM.log.ret[, 2]
IBM.log.ret[c(1:3, nrow(IBM.log.ret)), ]
## IBM.log.ret
## 2010-12-31 NA
## 2011-01-03 0.00489
## 2011-01-04 0.00108
## 2013-12-31 0.00620
options(digits = 7)
# Compare Log Returns with Arithmetic Returns
options(digits =3, scipen = 100) #scipen to change threshold before R converts to scientific no
tot.rets <- cbind(IBM.ret, IBM.log.ret)
tot.rets[c(1:3, nrow(tot.rets)), ]
## tot.ret IBM.log.ret
## 2010-12-31 NA NA
## 2011-01-03 0.00491 0.00489
## 2011-01-04 0.00108 0.00108
## 2013-12-31 0.00622 0.00620
max(abs(IBM.ret$tot.ret - IBM.log.ret$IBM.log.ret), na.rm = TRUE)
## [1] 0.00363
min(abs(IBM.ret$tot.ret - IBM.log.ret$IBM.log.ret), na.rm = TRUE)
## [1] 0.00000000118
options(digits =7, scipen = 0)
Differences on each are fairly small
How much would an investment in Amazon have made through the end of 2013 if we puchased AMZN shares at the closing price on December 31, 2010? Assume that we reinvested dividends.
# Step 1: Import Data and Calculate Arithmetic Returns
IBM.acum <- IBM.ret #from Section 2.2
IBM.acum[c(1:3, nrow(IBM.acum)), ]
## tot.ret
## 2010-12-31 NA
## 2011-01-03 0.004905977
## 2011-01-04 0.001084913
## 2013-12-31 0.006222858
# Step 2: Set First Day Total Return Value to Zero
IBM.acum[1,1] <- 0
IBM.acum[c(1:3, nrow(IBM.acum)), ]
## tot.ret
## 2010-12-31 0.000000000
## 2011-01-03 0.004905977
## 2011-01-04 0.001084913
## 2013-12-31 0.006222858
# Step 3: Calcualte Gross Daily Returns
IBM.acum$GrossRet <- IBM.acum$tot.ret + 1
IBM.acum[c(1:3, nrow(IBM.acum)), ]
## tot.ret GrossRet
## 2010-12-31 0.000000000 1.000000
## 2011-01-03 0.004905977 1.004906
## 2011-01-04 0.001084913 1.001085
## 2013-12-31 0.006222858 1.006223
# Step 4: Calculate Cummulative Gross Returns
IBM.acum$GrossCum <- cumprod(IBM.acum$GrossRet)
IBM.acum[c(1:3, nrow(IBM.acum)), ]
## tot.ret GrossRet GrossCum
## 2010-12-31 0.000000000 1.000000 1.000000
## 2011-01-03 0.004905977 1.004906 1.004906
## 2011-01-04 0.001084913 1.001085 1.005996
## 2013-12-31 0.006222858 1.006223 1.347213
# Step 5: Convert Cummulative Gross Returns to Cumulative Net Returns
IBM.acum$NetCum <- IBM.acum$GrossCum - 1
IBM.acum[c(1:3, nrow(IBM.acum)), ]
## tot.ret GrossRet GrossCum NetCum
## 2010-12-31 0.000000000 1.000000 1.000000 0.000000000
## 2011-01-03 0.004905977 1.004906 1.004906 0.004905977
## 2011-01-04 0.001084913 1.001085 1.005996 0.005996213
## 2013-12-31 0.006222858 1.006223 1.347213 0.347212558
Interpretation
An alternative way is to take the sum of the daily logarithmic returns.
# Step 1: Import Data and Calculate Logarithmic Returns
IBM.logcum <- IBM.log.ret #from Section 2.3
IBM.logcum[c(1:3, nrow(IBM.logcum)),]
## IBM.log.ret
## 2010-12-31 NA
## 2011-01-03 0.004893982
## 2011-01-04 0.001084325
## 2013-12-31 0.006203576
# Step 2: Set the First Log Return to Zero
IBM.logcum$IBM.log.ret[1, 1] <- 0
IBM.logcum[c(1:3, nrow(IBM.logcum)), ]
## IBM.log.ret
## 2010-12-31 0.000000000
## 2011-01-03 0.004893982
## 2011-01-04 0.001084325
## 2013-12-31 0.006203576
# Step 3: Take the Sum of all Logarithmic Returns during the Investment Period
logcumret <- sum(IBM.logcum$IBM.log.ret)
logcumret
## [1] 0.2980377
# Step 4: Convert Log Return Back to Arithmetic Return
cumret <- exp(logcumret) - 1
cumret
## [1] 0.3472126
Interpretation
Cumulating arithmetic returns versus logarithmic returns
Show that total return yields higher returns than price returns for a stock that pays div.
# Step 1: Import Data and Calculate Price and Total Returns
IBM.Ret <- cbind(IBM.prc.ret, IBM.ret) #from Section 2.1 & 2.2
names(IBM.Ret) <- c("prc.ret", "tot.ret")
IBM.Ret[c(1:3, nrow(IBM.Ret)), ]
## prc.ret tot.ret
## 2010-12-31 NA NA
## 2011-01-03 0.004905976 0.004905977
## 2011-01-04 0.001084913 0.001084913
## 2013-12-31 0.006222858 0.006222858
# Step 2: Set First Returns to Zero
IBM.Ret$prc.ret[1] <- 0
IBM.Ret$tot.ret[1] <- 0
IBM.Ret[c(1:3, nrow(IBM.Ret)), ]
## prc.ret tot.ret
## 2010-12-31 0.000000000 0.000000000
## 2011-01-03 0.004905976 0.004905977
## 2011-01-04 0.001084913 0.001084913
## 2013-12-31 0.006222858 0.006222858
# Step 3: Calculate Gross Returns
IBM.Ret$gross.prc <- IBM.Ret$prc.ret + 1
IBM.Ret$gross.tot <- IBM.Ret$tot.ret + 1
IBM.Ret[c(1:3, nrow(IBM.Ret)), ]
## prc.ret tot.ret gross.prc gross.tot
## 2010-12-31 0.000000000 0.000000000 1.000000 1.000000
## 2011-01-03 0.004905976 0.004905977 1.004906 1.004906
## 2011-01-04 0.001084913 0.001084913 1.001085 1.001085
## 2013-12-31 0.006222858 0.006222858 1.006223 1.006223
# Step 4: Cumulate the Gross Returns
IBM.Ret$cum.prc <- cumprod(IBM.Ret$gross.prc)
IBM.Ret$cum.tot <- cumprod(IBM.Ret$gross.tot)
IBM.Ret[c(1:3, nrow(IBM.Ret)), ]
## prc.ret tot.ret gross.prc gross.tot cum.prc cum.tot
## 2010-12-31 0.000000000 0.000000000 1.000000 1.000000 1.000000 1.000000
## 2011-01-03 0.004905976 0.004905977 1.004906 1.004906 1.004906 1.004906
## 2011-01-04 0.001084913 0.001084913 1.001085 1.001085 1.005996 1.005996
## 2013-12-31 0.006222858 0.006222858 1.006223 1.006223 1.278073 1.347213
# Step 5: Plot the Two Return Series
y.range <- range(IBM.Ret[, 5:6])
y.range
## [1] 1.000000 1.526869
title1 <- "IBM Stock Performance Based on.exit"
title2 <- "Total Return and Price Returns"
title3 <- "December 31, 2010 - December 31, 2013"
plot(IBM.Ret$cum.tot,
type = "l",
auto.grid = FALSE,
xlab = "Date",
ylab = "Value of Investment ($)",
ylim = y.range,
minor.ticks = FALSE,
main = paste(title1, "\n", title2, "\n", title3))
lines(IBM.Ret$cum.prc, type = "l", lty = 3)
legend("topleft",
col = c("black", "black"),
c("Value Based on Total Return", "Value Based on Price Return"),
lty = c(1, 3))
Interpretation
# To clean up the memory of your current R session run the following line
rm(list=ls(all=TRUE))
# Step 1: Import IBM Data from Yahoo Finance
library(quantmod)
library(xts)
data.AMZN <- read.csv("data/AMZN Yahoo.csv", header = TRUE)
date <- as.Date(data.AMZN$Date, format = "%Y-%m-%d")
data.AMZN <- cbind(date, data.AMZN[, -1])
data.AMZN <- data.AMZN[order(data.AMZN$date), ]
data.AMZN <- xts(data.AMZN[, 2:7], order.by = data.AMZN[, 1])
names(data.AMZN) <- paste(c("AMZN.Open", "AMZN.High", "AMZN.Low",
"AMZN.Close", "AMZN.Volume", "AMZN.Adjusted"))
data.AMZN[c(1:3, nrow(data.AMZN)), ]
## AMZN.Open AMZN.High AMZN.Low AMZN.Close AMZN.Volume
## 2010-12-31 181.96 182.30 179.51 180.00 3451900
## 2011-01-03 181.37 186.00 181.21 184.22 5331400
## 2011-01-04 186.15 187.70 183.78 185.01 5031800
## 2013-12-31 394.58 398.83 393.80 398.79 1996500
## AMZN.Adjusted
## 2010-12-31 180.00
## 2011-01-03 184.22
## 2011-01-04 185.01
## 2013-12-31 398.79
# Step 1: Import Data into R
wk <- data.AMZN
wk[c(1:3, nrow(wk)), ]
## AMZN.Open AMZN.High AMZN.Low AMZN.Close AMZN.Volume
## 2010-12-31 181.96 182.30 179.51 180.00 3451900
## 2011-01-03 181.37 186.00 181.21 184.22 5331400
## 2011-01-04 186.15 187.70 183.78 185.01 5031800
## 2013-12-31 394.58 398.83 393.80 398.79 1996500
## AMZN.Adjusted
## 2010-12-31 180.00
## 2011-01-03 184.22
## 2011-01-04 185.01
## 2013-12-31 398.79
# Step 2: Convert to Daily Data to Weekly Data
AMZN.weekly <- to.weekly(wk)
AMZN.weekly[c(1:3, nrow(AMZN.weekly)), ]
## wk.Open wk.High wk.Low wk.Close wk.Volume wk.Adjusted
## 2010-12-31 181.96 182.30 179.51 180.00 3451900 180.00
## 2011-01-07 181.37 188.45 181.21 185.49 22183400 185.49
## 2011-01-14 185.04 188.94 182.51 188.75 15899000 188.75
## 2013-12-31 399.41 399.92 392.45 398.79 4483600 398.79
# Step 3: Clean up Weekly Data to Keep Only the Adj Closing Prices at the End of Each Week
AMZN.weekly <- AMZN.weekly[, 6]
AMZN.weekly[c(1:3, nrow(AMZN.weekly)), ]
## wk.Adjusted
## 2010-12-31 180.00
## 2011-01-07 185.49
## 2011-01-14 188.75
## 2013-12-31 398.79
# Step 4: Calculate Weekly Returns
# Delt: calculates the % change from Friday of a week to Friday of the following week
AMZN.weekly$Ret <- Delt(AMZN.weekly$wk.Adjusted)
AMZN.weekly[c(1:3, nrow(AMZN.weekly)), ]
## wk.Adjusted Ret
## 2010-12-31 180.00 NA
## 2011-01-07 185.49 0.030500028
## 2011-01-14 188.75 0.017575044
## 2013-12-31 398.79 0.001783616
# Step 5: Clean up Weekly Returns Data by Deleting the First Observation
AMZN.weekly <- AMZN.weekly[-1, 2]
AMZN.weekly[c(1:3, nrow(AMZN.weekly)), ]
## Ret
## 2011-01-07 0.030500028
## 2011-01-14 0.017575044
## 2011-01-21 -0.060026501
## 2013-12-31 0.001783616
Verify Weekly Return Calculations (p. 71)
# Step 1: Import Data into R
mo <- data.AMZN
mo[c(1:3, nrow(mo)), ]
## AMZN.Open AMZN.High AMZN.Low AMZN.Close AMZN.Volume
## 2010-12-31 181.96 182.30 179.51 180.00 3451900
## 2011-01-03 181.37 186.00 181.21 184.22 5331400
## 2011-01-04 186.15 187.70 183.78 185.01 5031800
## 2013-12-31 394.58 398.83 393.80 398.79 1996500
## AMZN.Adjusted
## 2010-12-31 180.00
## 2011-01-03 184.22
## 2011-01-04 185.01
## 2013-12-31 398.79
# Step 2: Convert to Daily Data to monthly Data
AMZN.monthly <- to.monthly(mo)
AMZN.monthly[c(1:3, nrow(AMZN.monthly)), ]
## mo.Open mo.High mo.Low mo.Close mo.Volume mo.Adjusted
## Dec 2010 181.96 182.30 179.51 180.00 3451900 180.00
## Jan 2011 181.37 191.60 166.90 169.64 113611300 169.64
## Feb 2011 170.52 191.40 169.51 173.29 95776400 173.29
## Dec 2013 399.00 405.63 379.50 398.79 55686700 398.79
# Step 3: Clean up monthly Data to Keep Only the Adj Closing Prices at the End of Each Week
AMZN.monthly <- AMZN.monthly[, 6]
AMZN.monthly[c(1:3, nrow(AMZN.monthly)), ]
## mo.Adjusted
## Dec 2010 180.00
## Jan 2011 169.64
## Feb 2011 173.29
## Dec 2013 398.79
# Step 4: Calculate monthly Returns
# Delt: calculates the % change from Friday of a week to Friday of the following week
AMZN.monthly$Ret <- Delt(AMZN.monthly$mo.Adjusted)
AMZN.monthly[c(1:3, nrow(AMZN.monthly)), ]
## mo.Adjusted Ret
## Dec 2010 180.00 NA
## Jan 2011 169.64 -0.05755556
## Feb 2011 173.29 0.02151612
## Dec 2013 398.79 0.01313453
# Step 5: Clean up monthly Returns Data by Deleting the First Observation
AMZN.monthly <- AMZN.monthly[-1, 2]
AMZN.monthly[c(1:3, nrow(AMZN.monthly)), ]
## Ret
## Jan 2011 -0.05755556
## Feb 2011 0.02151612
## Mar 2011 0.03947148
## Dec 2013 0.01313453
AABA replaced YHOO in the textbook. The shares of what used to be known as Yahoo under the ticker symbol YHOO started trading Monday as Altaba (think alternative Alibaba) and trade under the symbol AABA.Jun 19, 2017.
# See what objects are in the R memory
ls()
## [1] "AMZN.monthly" "AMZN.weekly" "data.AMZN" "date"
## [5] "mo" "wk"
# Delete all these objects
rm(list = ls())
ls()
## character(0)
# Compare total returns of multiple securities - AMZN, IBM, AABA, ^GSPC
# Which of these investments performed better from 12/31/2010 to 12/31/2013
# Pay dividends: IBM
# Don't pay: AMZN, AABA, ^GSPC
#Step 1: Importing Price Data
library(quantmod)
data.AMZN <- getSymbols("AMZN", from = "2010-12-31", to = "2014-01-01", auto.assign = FALSE)
data.AABA<- getSymbols("AABA", from = "2010-12-31", to = "2014-01-01", auto.assign = FALSE)
data.IBM <- getSymbols("IBM", from = "2010-12-31", to = "2014-01-01", auto.assign = FALSE)
data.GSPC <- getSymbols("^GSPC", from = "2010-12-31", to = "2014-01-01", auto.assign = FALSE)
#to = "2013-12-31" in the book was replaced by to = "2014-01-01"
#B/c that code doesn't produce the output that includes stock price of 2013-12-31the date.
# Step 2: Combine Data
multi <- data.AMZN[, 6] # Need to create a new data object before cbinding
multi <- merge(multi, data.GSPC[, 6])
multi <- merge(multi, data.AABA[, 6])
multi <- merge(multi, data.IBM[, 6])
#multi <- cbind(multi, data.GSPC[, 6], data.AABA[, 6], data.IBM[, 6])
multi[c(1:3, nrow(multi)), ]
## AMZN.Adjusted GSPC.Adjusted AABA.Adjusted IBM.Adjusted
## 2010-12-31 180.00 1257.64 16.63 123.2834
## 2011-01-03 184.22 1271.87 16.75 123.8883
## 2011-01-04 185.01 1270.20 16.59 124.0227
## 2013-12-31 398.79 1848.36 40.44 166.0890
# Step 3: Convert Data into a data.frame
multi.df <- cbind(index(multi),
data.frame(multi))
names(multi.df) <- c("date", "AMZN", "GSPC", "AABA", "IBM")
multi.df[c(1:3, nrow(multi.df)), ]
## date AMZN GSPC AABA IBM
## 2010-12-31 2010-12-31 180.00 1257.64 16.63 123.2834
## 2011-01-03 2011-01-03 184.22 1271.87 16.75 123.8883
## 2011-01-04 2011-01-04 185.01 1270.20 16.59 124.0227
## 2013-12-31 2013-12-31 398.79 1848.36 40.44 166.0890
# Step 4: Calculate Normalized Values for Each Security
multi.df$AMZN.idx <- multi.df$AMZN / multi.df$AMZN[1]
multi.df$GSPC.idx <- multi.df$GSPC / multi.df$GSPC[1]
multi.df$AABA.idx <- multi.df$AABA/ multi.df$AABA[1]
multi.df$IBM.idx <- multi.df$IBM / multi.df$IBM[1]
multi.df[c(1:3, nrow(multi.df)), 6:9]
## AMZN.idx GSPC.idx AABA.idx IBM.idx
## 2010-12-31 1.000000 1.000000 1.0000000 1.000000
## 2011-01-03 1.023444 1.011315 1.0072159 1.004906
## 2011-01-04 1.027833 1.009987 0.9975948 1.005996
## 2013-12-31 2.215500 1.469705 2.4317499 1.347213
# Step 5: Plot the Capital Appreciation of Each Security
# GSPC first
y.range = range(multi.df[, 6:9])
y.range
## [1] 0.6668671 2.4564041
plot(x = multi.df$date,
y = multi.df$GSPC.idx,
type = "l",
xlab = "Date",
ylab = "Value of Investment ($)",
ylim = y.range,
col = "black",
lty = 1,
lwd = 2,
main = "Value of $1 Investment in AMZN, IBM, AABA,
And the S&P 500 Index Based on Total Returns
December 31, 2010 - December 31, 2013")
# Add a line for AMZN, AABA, IBM
lines(x = multi.df$date,
y = multi.df$AMZN.idx,
col = "black",
lty = 2,
lwd = 1)
lines(x = multi.df$date,
y = multi.df$IBM.idx,
col = "gray40",
lty = 1,
lwd = 2)
lines(x = multi.df$date,
y = multi.df$AABA.idx,
col = "gray60",
lty = 1,
lwd = 1)
abline(h = 1, lty = 1, col = "black")
legend("topleft",
c("S&P 500 Index", "AMZN", "IBM", "AABA"),
col = c("black", "black", "gray40", "gray60"),
lty = c(1, 2, 1, 1),
lwd = c(2, 1, 2, 1))