In chapter 2 we take a look at using R markdown to help us distinguish returns on investments and use it to track our overall portfolios performance. We also learn how to calculate price returns and total returns. Then, for statistical and programming consideration, we learn how to calculate logarithmic total returns. Total returns are a culmination of the cash flow received on an investment and the intermediate cash flow.
the dollar change based solely on the closing price of a security is called capital gains and the percentage price in the closing price of a security is its price return. The price return is measured over some investment horizon the length of the period depends on the application.
at the start of each chapter we begin by loading the quantmod and xts packages. Then we use what we learned in chapter 1 to create and read the IBM Yahoo.csv file
library(quantmod)
## Loading required package: xts
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
## Loading required package: TTR
## Version 0.4-0 included new data defaults. See ?getSymbols.
library(xts)
data.IBM<-read.csv("IBMYahoo.csv",header=TRUE)
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[,1])
names(data.IBM)<-
paste(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
the price return is calculated off the stock’s closing price. in data.IBM, this is IBM.Close or column 4. we then subset the data to only include the IBM 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
we can apply eq.(2.1) to the IBM closing price to calculate the price return. This equation is implemented in R using the Delt command. for example, the price return on January 3, 2011 is equal to .49% [=(147.48/146.76)-1]
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
the output above shows that December 31,2010 has a return of NA and the first return in the series is on January 3, 2011, which is the first trading day of 2011. As such, we can delete the first observation in IBM.prc.ret. In addition, since we will be dealing with returns, we do not need IBM.Close and the first column can also be deleted
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)
In this section we take a look at how to calculate dividend returns, if available, for a stock.
data.IBM[715:720,]
## IBM.Open IBM.High IBM.Low IBM.Close IBM.Volume IBM.Adjusted
## 2013-11-01 179.81 180.34 178.88 179.23 3644500 161.0826
## 2013-11-04 179.90 180.80 179.34 180.27 3483300 162.0173
## 2013-11-05 179.54 179.80 177.71 177.85 6096800 159.8423
## 2013-11-06 177.91 179.75 177.78 179.19 4560700 161.9115
## 2013-11-07 179.60 181.39 179.60 180.00 5219500 162.6434
## 2013-11-08 178.83 180.08 177.35 179.99 6275000 162.6344
Since we previously called-in the IBM data, We only need to check that it is still in the R memory. If so, we then keep the adjusted close price or Column 6 in data.IBM
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
We apply the Delt command on the adjusted close price to calculate the total return. note that due to roudning of the adjusted close price, it would appear that the January 3, 2011 total return is lower than the price return calculated in the prior section. logically the total return is at least as large as the price return because total return equals price return on non ex-dividend days and the total return is higher than the price return on ex-dividend days
IBM.ret$IBM.tot.ret=Delt(IBM.ret$IBM.Adjusted)
IBM.ret[c(1:3,nrow(IBM.ret)),]
## IBM.Adjusted IBM.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
To output the data, we only show the total return column and limit the number of decimals on display using the digits=3 option
options(digits=3)
IBM.ret<-IBM.ret[,2]
IBM.ret[c(1:3,nrow(IBM.ret)),]
## IBM.tot.ret
## 2010-12-31 NA
## 2011-01-03 0.00491
## 2011-01-04 0.00108
## 2013-12-31 0.00622
options(digits=7)
The returns calculated in the preceding section using Eq. (2.2) and the Delt command are called arithmetic returns or simple returns. in this section we show how to calculaate logarithmic returns or log returns. Logarithmic returns are used extensively in derivatives pricing, among other areas of finance. ### step 1: Import Adjusted Closing Price Data since we are calculating total returns, we still need the adjusted closing price data as our base data source.
IBM.log.ret<-data.IBM[,6]
IBM.log.ret[c(1:3,nrow(IBM.log.ret)),]
## IBM.Adjusted
## 2010-12-31 125.8031
## 2011-01-03 126.4203
## 2011-01-04 126.5574
## 2013-12-31 169.4835
we use a combination of the diff and log commands to calculate logarithmic returns
IBM.log.ret$IBM.log.ret<-diff(log(IBM.log.ret$IBM.Adjusted))
IBM.log.ret[c(1:3,nrow(IBM.log.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
we then clean up AMZN.log.ret to delete the first column and keep only the logarithmic return series
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)
Below we show how to combine the two total return calculations using the cbind command. We see that the differences on each day are fairly small and hard to spot by visual inspection
options(digits=3,scipen=100)
tot.rets<-cbind(IBM.ret,IBM.log.ret)
tot.rets[c(1:3,nrow(tot.rets)),]
## IBM.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(tot.rets$IBM.tot.ret-tot.rets$IBM.log.ret),na.rm=TRUE)
## [1] 0.00363
min(abs(tot.rets$IBM.tot.ret-tot.rets$IBM.log.ret),na.rm=TRUE)
## [1] 0.00000000118
options(digits=7,scipen=0)
To fully capture the effects of being able to reinvest dividends, we should calculate daily returns and string those returns together for longer periods. Otherwise, if we simply apply Eq. (2.2) using prices at the beginning and end of the investment horizon and add the dividends were not reinvested and were kept under the mattress, then this calculation may be appropriate. ## 2.4.1: Cumulating Arithmetic Returns To string together multiple days of arithmetic returns, we have to take the product of the daily gross returns. The gross return is one plus the net return Rt. That is, for a 2-day cumulative return, we take (1+R1) X (1+R2) ### step 1: Import Data and Calculate Arithmetic Returns since we have already calculated the daily arithmetic total returns above, we call IBM.ret to see that we have the correct data still available in the R memory
IBM.acum<-IBM.ret
IBM.acum[c(1:3,nrow(IBM.acum)),]
## IBM.tot.ret
## 2010-12-31 NA
## 2011-01-03 0.004905977
## 2011-01-04 0.001084913
## 2013-12-31 0.006222858
Because we assume that we are making the inevstment on December 31, 2010, we should set the return on that day equal to zero
IBM.acum[1,1]<-0
IBM.acum[c(1:3,nrow(IBM.acum)),]
## IBM.tot.ret
## 2010-12-31 0.000000000
## 2011-01-03 0.004905977
## 2011-01-04 0.001084913
## 2013-12-31 0.006222858
We then create a new variable for the gross return, which is simply one plus the net total return
IBM.acum$GrossRet<-1+IBM.acum$IBM.tot.ret
IBM.acum[c(1:3,nrow(IBM.acum)),]
## IBM.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
We use the cumprod command to take the cumulative product of the gross return. cumprod takes the product of all the gross returns from December 31, 2010 to the valuation date
IBM.acum$GrossCum<-cumprod(IBM.acum$GrossRet)
IBM.acum[c(1:3,nrow(IBM.acum)),]
## IBM.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
Note that the above value is still a gross return number. So the last step would require us to subtract one from the GrossCum to calculate the net cumulative return or NetCum
IBM.acum$NetCum<-IBM.acum$GrossCum-1
IBM.acum[c(1:3,nrow(IBM.acum)),]
## IBM.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
an alternative way to calculate multi-period returns is to take the sum of the daily logarithmic returns. ### step 1: Import Data and Calculate Logarithmic Returns Since we have already calculated the daily log total returns above, we call IBM.logret to see that we have the correct data still available in the R memory.
IBM.logcum<-IBM.log.ret
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
We also set the return on December 31, 2010 to zero as we are calculating returns as if we purchased the IBM shares at the close on December 31, 2010
IBM.logcum[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
We add up the values in IBM.log.ret variable using the sum command
logcumret=sum(IBM.logcum$IBM.log.ret)
logcumret
## [1] 0.2980377
Unlike the arithmetic cumulative return, the logarithmic cumulative return may not have any practical interpretation. Therefore, we would need to convert the cumulative logarithmic return to a cumulative arithmetic return. We do this by taking the exponential of the logarithmic return using the exp command
cumret=exp(logcumret)-1
cumret
## [1] 0.3472126
Using IBM stock as an exmaple and the technique to calculate multi-period arithmetic returns discussed above, we now show that the total return yields higher returns than price returns for a stock that pays dividends ### step 1: Import Data and Calculate Price and Total Returns Since we already have combined the price and total returns data previously in tot.rets, we only need to call-in the data at this stage, Then, we rename the data to better identify the variables as prc.ret and tot.ret
IBM.Ret<-cbind(IBM.prc.ret,IBM.ret)
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
We then set the December 31, 2011 price and total return 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
Then, we calculate the gross price return gross.prc and gross total return gross.tot
IBM.Ret$gross.prc<-1+IBM.Ret$prc.ret
IBM.Ret$gross.tot<-1+IBM.Ret$tot.ret
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
Lastly, we calculate the cumulative price return cum.prc and cumulative total return cum.tot by using the cumrpod command
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
we then plot the cum.prc and cum.tot variables. We first plot the cum.tot variable, and then plot the cum.prc variable. Using the abline command, we add horizontal line at $1 to make it easy for us to interpret whether the investment is making money or losing money
y.range<-range(IBM.Ret[,5:6])
y.range
## [1] 1.000000 1.526869
plot(IBM.Ret$cum.tot,
type="l",
auto.grid=FALSE,
xlab="Date",
ylab="Value of Investment ($)",
ylim=y.range,
minor.ticks=FALSE,
main="IBM Stock Performance Based On
Total Returns and Price Returns
December 31, 2010 - December 31, 2013")
lines(IBM.Ret$cum.prc,
type="l",
lty=3)
abline(h=1,col="black")
legend("topleft",
col=c("black","black"),
lty=c(1,3),
c("Value Based on Total Return",
"Value Based on Price Return"))
Another option for lesser frequency returns are monthly returns. The implementation is similar to calculating weekly returns. ### step 1: Import Data Into R We again use data.AMZN we imported in the earlier section as a starting point for our monthly return calculations
data.AMZN<-read.csv("AMZNYahoo.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
mo<-data.AMZN
mo[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
using the to.monthly command, we convert the daily data to monthly data notice the warning message that appears every time we use the to.monthly command. This is because the object’s time appears to be in Coordinated Universal Time
AMZN.monthly<-to.monthly(mo)
AMZN.monthly[c(1:3,nrow(AMZN.monthly)),]
## Warning: timezone of object (UTC) is different than current timezone ().
## 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
We subset the data to only show the adjusted close price, because that is the only variable we need to calculate monthly returns
AMZN.monthly<-AMZN.monthly[,6]
AMZN.monthly[c(1:3,nrow(AMZN.monthly)),]
## Warning: timezone of object (UTC) is different than current timezone ().
## mo.Adjusted
## Dec 2010 180.00
## Jan 2011 169.64
## Feb 2011 173.29
## Dec 2013 398.79
Using the Delt command, we can calculate the percentage change in the end-of-the-month adjusted close price. as such, we get a month-end to month-end return using this approach
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
Since December 2010 has NA for its return and since we only need the return column, we subset the data by deleting the first row and keeping the second column
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