Ch. 2: Individual Security Returns

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.

2.1: Price Returns

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.

step 1: Import IBM Data from Yahoo Finance

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

step 2: Subset the Data to Only Include the Closing Price

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

step 3: Calculate IBM’s Price Return

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

step 4: Clean up Data Object

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)

2.2: Total Returns

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

step 1: Import Adjusted Closing Price Data

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

step 2: Calculate Total Return

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

step 3: Clean up the Data

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)

2.3: Logarithmic Total Returns

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

step 2: Calculate Log Returns

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

step 3: Clean up the Data

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)

compare log returns with arithmetic returns

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)

2.4: Cumulating Multi-Day Returns

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

step 2: Set First Day Total Return Value to Zero

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

step 3: Calculate Gross Daily Returns

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

step 4: Calculate Cumulative Gross Returns

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

step 5: Convert Cumulative Gross Returns to Cumulative Net Returns

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

2.4.2: Cumulating Logarithmic Returns

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

step 2: Set the First Log Return to Zero

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

step 3: Take the sum of all Logarithmic Returns During the Investment Period

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

step 4: Convert Log Return Back to Arithmetic Return

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

2.4.3: Comparing Price Return and Total Return

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

step 2: Set First Returns to Zero

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

step 3: Calculate Gross Returns

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

step 4: Cumulate the Gross Returns

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

step 5: Plot the Two Return Series

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"))

2.6: Monthly Returns

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

step 2: convert Daily Data to Monthly Data

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

step 3: Clean up Data to Include Only Adjusted Prices for the End of Each Month

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

step 4: Calculate Monthly Returns

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

step 5: Cleanup Monthly Data Object

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