## 1.4 Return Calculations with Data in R

This section discusses representing time series data in R using `xts`

objects,
the calculation of returns from historical prices in R, as well as the graphical display of prices and returns.

### 1.4.1 Representing time series data using `xts`

objects

The examples in this section are based on the daily adjusted closing price
data for Microsoft and Starbucks stock over the period January 4, 1993
through December 31, 2014^{5}. These data are available as the `xts`

objects `msftDailyPrices`

and `sbuxDailyPrices`

in the R package
**IntroCompFinR**^{6}

```
suppressPackageStartupMessages(library(IntroCompFinR))
suppressPackageStartupMessages(library(xts))
suppressPackageStartupMessages(library(methods))
data(msftDailyPrices, sbuxDailyPrices)
head(cbind(msftDailyPrices,sbuxDailyPrices), 3)
```

```
## MSFT SBUX
## 1993-01-04 1.89 1.08
## 1993-01-05 1.92 1.10
## 1993-01-06 1.98 1.12
```

`## [1] "xts" "zoo"`

There are many different ways of representing a time series of data in R. For financial
time series `xts`

(extensible time series) objects from the **xts** package are especially
convenient and useful. An `xts`

object consists of two pieces of information: (1) a `matrix`

of numeric data with different time series in the columns, (2) an R object representing the common time indexes associated with the rows of the data. `xts`

objects extend and enhance the `zoo`

class of time series objects from the **zoo** package written by Achim Zeileis (zoo stands
for Z’s ordered observations).

The `matrix`

of time series data can be extracted from the `xts`

object using the **xts** function `coredata()`

:

```
## MSFT
## [1,] 1.89
## [2,] 1.92
## [3,] 1.98
```

The resulting `matrix`

of data does not have any date information. The date index can be
extracted using the **xts** function `index()`

:

`## [1] "1993-01-04" "1993-01-05" "1993-01-06"`

The object `date.index`

is of class `Date`

:

`## [1] "Date"`

When a `Date`

object is printed, the date is displayed in the format `yyyy-mm-dd`

.
However, internally each date represents the number of days since January 1, 1970:

`## [1] 8404`

Here, `1993-01-04`

(January 4, 1993) is \(8,404\) days after January 1, 1970. This allows
for simple *date arithmetic* (e.g. adding and subtracting dates, etc). More sophisticated
date arithmetic is available using the functions in the **lubridate** package.

There are several advantages of using `xts`

objects to represent financial time series data. Most
financial time series do not follow an equally spaced regular calendar. The time index of a `xts`

object can be any strictly increasing date sequence which can match the times and dates for which assets trade on an exchange. For example, assets traded on the main US stock exchanges (e.g. NYSE and NASDAQ) trade only on weekdays between 9:30AM and 4:00PM Eastern Standard Time and do not trade on a number of holidays.

Another advantage of `xts`

objects is that you can easily extract observations at or between specific dates. For example, to extract the daily price on January 3, 2014 use

```
## MSFT
## 2014-01-03 35.67
```

To extract prices between January 3, 2014 and January 7, 2014, use

```
## MSFT
## 2014-01-03 35.67
## 2014-01-06 34.92
## 2014-01-07 35.19
```

Or to extract all of the prices for January, 2014 use:

```
## MSFT
## 2014-01-02 35.91
## 2014-01-03 35.67
## 2014-01-06 34.92
## 2014-01-07 35.19
## 2014-01-08 34.56
## 2014-01-09 34.34
## 2014-01-10 34.83
## 2014-01-13 33.81
## 2014-01-14 34.58
## 2014-01-15 35.53
## 2014-01-16 35.65
## 2014-01-17 35.16
## 2014-01-21 34.96
## 2014-01-22 34.73
## 2014-01-23 34.85
## 2014-01-24 35.58
## 2014-01-27 34.82
## 2014-01-28 35.05
## 2014-01-29 35.43
## 2014-01-30 35.62
## 2014-01-31 36.57
```

Two or more `xts`

objects can be merged together and aligned to a common date index
using the **xts** function `merge()`

:

```
## MSFT SBUX
## 1993-01-04 1.89 1.08
## 1993-01-05 1.92 1.10
## 1993-01-06 1.98 1.12
```

If two or more `xts`

objects have a common date index then they can be combined using `cbind()`

.

#### 1.4.1.1 Basic calculations on `xts`

objects.

Because `xts`

objects typically contain a matrix of numeric data, many R functions that operate on matrices also operate on `xts`

objects. For example, to transform `msftDailyPrices`

to log prices use

```
## MSFT
## 1993-01-04 0.6365768
## 1993-01-05 0.6523252
## 1993-01-06 0.6830968
```

If two or more `xts`

objects have the same time index then they can be added, subtracted, multiplied, and divided. For example,

```
msftPlusSbuxDailyPrices = msftDailyPrices + sbuxDailyPrices
colnames(msftPlusSbuxDailyPrices) = "MSFT+SBUX"
head(msftPlusSbuxDailyPrices,3)
```

```
## MSFT+SBUX
## 1993-01-04 2.97
## 1993-01-05 3.02
## 1993-01-06 3.10
```

To compute the average of the Microsoft daily prices use

`## [1] 19.85533`

If an R function, for some unknown reason, is not operating correctly on an `xts`

object
first extract the data using `coredata()`

and then call the R function. For example,

`## [1] 19.85533`

#### 1.4.1.2 Changing the frequency of an `xts`

object

Data at the daily frequency is the highest frequency of data considered in this book.
However, in many of the examples we want to use data at the weekly or monthly frequency. The
conversion of data at a daily frequency to data at a monthly frequency is easy to
do with `xts`

objects. For example, end-of-month prices can be extracted from the daily prices using the **xts** function `to.monthly()`

:

```
msftMonthlyPrices = to.monthly(msftDailyPrices, OHLC=FALSE)
sbuxMonthlyPrices = to.monthly(sbuxDailyPrices, OHLC=FALSE)
msftSbuxMonthlyPrices = to.monthly(msftSbuxDailyPrices, OHLC=FALSE)
head(msftMonthlyPrices, 3)
```

```
## MSFT
## Jan 1993 1.92
## Feb 1993 1.85
## Mar 1993 2.06
```

By default, `to.monthly()`

extracts the data for the last day of the month and creates
a **zoo** `yearmon`

date index. For monthly data, the `yearmon`

date index is
convenient for printing and plotting as the month and year are nicely printed. To
preserve the `Date`

class of the time index and show the end-of-month date, use the
optional argument `indexAt = "lastof"`

in the call to `to.monthly()`

:

```
## MSFT
## 1993-01-31 1.92
## 1993-02-28 1.85
## 1993-03-31 2.06
```

In the above calls to `to.monthly()`

, the optional argument `OHLC=FALSE`

prevents the creation of open, high, low, and closing prices for the month.

In a similar fashion, you can extract end-of-week prices using the `xts`

function `to.weekly()`

:

```
msftWeeklyPrices = to.weekly(msftDailyPrices, OHLC=FALSE, indexA="lastof")
head(msftWeeklyPrices, 3)
```

```
## MSFT
## 1993-01-08 1.94
## 1993-01-15 2.00
## 1993-01-22 1.99
```

Here, the weekly data are the closing prices on each Friday of the week:

`## [1] "Friday" "Friday" "Friday"`

#### 1.4.1.3 Plotting `xts`

objects with `plot.xts()`

and `plot.zoo`

Time plots of `xts`

objects can be created with the generic `plot()`

function as there is a method function in the **xts** package for
objects of class `xts`

. For example, Figure
1.1 shows a basic time plot of the
monthly closing prices of Microsoft and Starbucks created with:

The default plot style in `plot.xts()`

is a single-panel plot with
multiple series. You can also create multi-panel plots, as in Figure
1.2, by setting the optional argument
`multi.panel = TRUE`

in the call to `plot.xts()`

See the help file for `plot.xts()`

for more examples of plotting `xts`

objects.

Because the `xts`

class inherits from the `zoo`

class, the **zoo**
method function `plot.zoo()`

can also be used to plot `xts`

objects.
Figure 1.3 is created with

```
plot.zoo(msftSbuxMonthlyPrices, plot.type="single",
main="Monthly Closing Prices",
lwd = 2, col=c("black", "red"), ylab="Price")
grid()
legend(x="topleft", legend=colnames(msftSbuxMonthlyPrices),
lwd = 2, col=c("black", "red"))
```

A muti-panel plot, shown in Figure 1.4, can be created using

```
plot.zoo(msftSbuxMonthlyPrices, plot.type="multiple", main="",
lwd = 2, col=c("black", "red"), cex.axis=0.8)
```

Creating plots with `plot.zoo()`

is a bit more involved than with `plot.xts()`

, as
`plot.xts()`

is newer. See the help file for `plot.zoo()`

for more examples.

#### 1.4.1.4 Ploting `xts`

objects using `autoplot()`

from **ggplot2**

The plots created using `plot.xts()`

and `plot.zoo()`

are created using the base
graphics system in R. This allows for a lot of flexibility but often the resulting
plots do not look very exciting or modern. In addition, these functions are not
well suited for plotting many time series together in a single plot.

Another very popular graphics system in R is provided by the **ggplot2** package by
Hadley Wickham of RStudio. For plotting `xts`

objects, especially with multiple
columns (data series), the **ggplot2** function `autoplot()`

is especially
convenient and easy:

```
library(ggplot2)
autoplot(msftSbuxDailyPrices, facets = NULL) +
ggtitle("Daily Closing Prices") +
ylab("Closing Price Per Share") +
xlab("Year")
```

The syntax for creating graphs with `autoplot()`

uses the *grammar of graphics*
syntax from the **ggplot2** package. See the R Graphics Cookbook
for more details and examples on using the **ggplot2** package. The call to `autoplot()`

first invokes the method function `autoplot.zoo()`

from the **zoo** package and
creates a basic time series plot. Additional layers showing a main title and axes
labels are added using `+`

. The optional argument `facets = NULL`

specifies that
all series are plotted together on a single plot with different colors.

To produce a multi-panel plot call `autoplot()`

with `facets = Series ~ .`

:

```
autoplot(msftSbuxDailyPrices, facets = Series ~ .) +
ggtitle("Daily Closing Prices") +
ylab("Closing Price Per Share") +
xlab("Year")
```

See the help file for `autoplot.zoo()`

for more examples.

### 1.4.2 Calculating returns

In this sub-section, we illustrate how to calculate a time series of returns from a time series of prices.

#### 1.4.2.1 Brute force return calculations

Consider computing simple monthly returns, \(R_{t}=\frac{P_{t}-P_{t-1}}{P_{t-1}}\),
from historical prices using the `xts`

object `sbuxMonthlyPrices`

. The R code for
a brute force calculation is:

```
## SBUX
## Jan 1993 NA
## Feb 1993 -0.06250000
## Mar 1993 0.04761905
```

Here, the `diff()`

function computes the first difference in the prices,
\(P_{t}-P_{t-1}\), and the `lag()`

function computes the lagged price,
\(P_{t-1}.\)^{7} An equivalent calculation is
\(R_{t}=\frac{P_{t}}{P_{t-1}}-1\):

```
## SBUX
## Jan 1993 NA
## Feb 1993 -0.06250000
## Mar 1993 0.04761905
```

Notice that the return for January, 1993 is `NA`

(missing value). To
automatically remove this missing value, use the R function `na.omit()`

or explicitly exclude the first observation:

```
## SBUX
## Feb 1993 -0.06250000
## Mar 1993 0.04761905
## Apr 1993 0.01818182
```

```
## SBUX
## Feb 1993 -0.06250000
## Mar 1993 0.04761905
## Apr 1993 0.01818182
```

To compute continuously compounded returns from simple returns, use:

```
## SBUX
## Feb 1993 -0.06453852
## Mar 1993 0.04652002
## Apr 1993 0.01801851
```

Or, equivalently, to compute continuously compounded returns directly from prices, use:

```
## SBUX
## Feb 1993 -0.06453852
## Mar 1993 0.04652002
## Apr 1993 0.01801851
```

The above calculations used an `xts`

object with a single column. If an `xts`

object has multiple columns the same calculations work for each column. For example,

```
msftSbuxMonthlyReturns = diff(msftSbuxMonthlyPrices)/lag(msftSbuxMonthlyPrices)
head(msftSbuxMonthlyReturns, n=3)
```

```
## MSFT SBUX
## Jan 1993 NA NA
## Feb 1993 -0.03645833 -0.06250000
## Mar 1993 0.11351351 0.04761905
```

Also,

```
## MSFT SBUX
## Jan 1993 NA NA
## Feb 1993 -0.03713955 -0.06453852
## Mar 1993 0.10752034 0.04652002
```

These are examples of *vectorized* calculations. That is, the calculations are
performed on all columns simultaneously. This is computationally more efficient
than looping the same calculation for each column. In R, you should try to vectorize
calculations whenever possible.

#### 1.4.2.2 Calculating returns using `Return.calculate()`

Simple and continuously compounded returns can be computed using the
**PerformanceAnalytics** function `Return.calculate()`

:

```
suppressPackageStartupMessages(library(PerformanceAnalytics))
# Simple returns
sbuxMonthlyReturns = Return.calculate(sbuxMonthlyPrices)
head(sbuxMonthlyReturns, n=3)
```

```
## SBUX
## Jan 1993 NA
## Feb 1993 -0.06250000
## Mar 1993 0.04761905
```

```
# CC returns
sbuxMonthlyReturnsC = Return.calculate(sbuxMonthlyPrices, method="log")
head(sbuxMonthlyReturnsC, n=3)
```

```
## SBUX
## Jan 1993 NA
## Feb 1993 -0.06453852
## Mar 1993 0.04652002
```

`Return.calculate()`

also works with `xts`

objects with multiple columns:

```
## MSFT SBUX
## Jan 1993 NA NA
## Feb 1993 -0.03645833 -0.06250000
## Mar 1993 0.11351351 0.04761905
```

The advantages of using `Return.calculate()`

instead of brute force calculations are: (1) clarity of code (you know what is being computed), (2) the same function is used for both simple and continuously compounded returns, (3) built-in error checking.

#### 1.4.2.3 Equity curves

To directly compare the investment performance of two or more assets,
plot the simple multi-period cumulative returns of each asset on the
same graph. This type of graph, sometimes called an *equity curve*,
shows how a one dollar investment amount in each asset grows over
time. Better performing assets have higher equity curves. For simple
returns, the *k*-period returns are \(R_{t}(k)=\prod\limits _{j=0}^{k-1}(1+R_{t-j})\)
and represent the growth of one dollar invested for \(k\) periods.
For continuously compounded returns, the *k*-period returns
are \(r_{t}(k)=\sum\limits _{j=0}^{k-1}r_{t-j}\). However, this
continuously compounded \(k\)-period return must be converted to a simple \(k\)-period return, using \(R_{t}(k)=\exp\left(r_{t}(k)\right)-1\), to properly represent the growth of one dollar invested for \(k\) periods.

**Example 1.21 (Equity curves for Microsoft and Starbucks monthly returns)**

To create the equity curves for Microsoft and Starbucks based
on simple returns use:^{8}

```
msftMonthlyReturns = na.omit(Return.calculate(msftMonthlyPrices))
sbuxMonthlyReturns = na.omit(Return.calculate(sbuxMonthlyPrices))
equityCurveMsft = cumprod(1 + msftMonthlyReturns)
equityCurveSbux = cumprod(1 + sbuxMonthlyReturns)
dataToPlot = merge(equityCurveMsft, equityCurveSbux)
plot(dataToPlot, main="Monthly Equity Curves", legend.loc="topleft")
```

The R function `cumprod()`

creates the cumulative products
needed for the equity curves. Figure 1.5
shows that a one dollar investment in Starbucks dominated a one dollar
investment in Microsoft over the given period. In particular,
$1 invested in Microsoft grew to about only $22 (over about 20 years)
whereas $1 invested in Starbucks grew over $70.
Notice the huge increases and decreases in value of Microsoft during
the dot-com bubble and bust over the period 1998 - 2001, and the enormous increase in value of Starbucks from 2009 - 2014.

\(\blacksquare\)

### 1.4.3 Calculating portfolio returns from time series data

As discussed in sub-section 1.3, the calculation of portfolio returns depends on the assumptions made about the portfolio weights over time.

#### 1.4.3.1 Constant portfolio weights

The easiest case assumes that portfolio weights are constant over time. To illustrate, consider an equally weighted portfolio of Microsoft and Starbucks stock. A time series a portfolio monthly returns can be created directly from the monthly returns on Microsoft and Starbucks stock:

```
x.msft = x.sbux = 0.5
msftMonthlyReturns = na.omit(Return.calculate(msftMonthlyPrices))
sbuxMonthlyReturns = na.omit(Return.calculate(sbuxMonthlyPrices))
equalWeightPortMonthlyReturns = x.msft*msftMonthlyReturns +
x.sbux*sbuxMonthlyReturns
head(equalWeightPortMonthlyReturns, 3)
```

```
## MSFT
## Feb 1993 -0.04947917
## Mar 1993 0.08056628
## Apr 1993 -0.02974404
```

The same calculation can be performed using the **PerformanceAnalytics** function
`Return.portfolio()`

:

```
equalWeightPortMonthlyReturns =
Return.portfolio(na.omit(msftSbuxMonthlyReturns),
weights = c(x.msft, x.sbux),
rebalance_on = "months")
head(equalWeightPortMonthlyReturns, 3)
```

```
## portfolio.returns
## Feb 1993 -0.04947917
## Mar 1993 0.08056628
## Apr 1993 -0.02974404
```

Here, the optional argument `rebalance_on = "months"`

specifies that the portfolio
is to be rebalanced to the specified weights at the beginning of every month.

If you also want the asset contributions to the portfolio return set the
optional argument `contribution = TRUE`

(recall, asset contributions sum to the
portfolio return):

```
equalWeightPortMonthlyReturns =
Return.portfolio(na.omit(msftSbuxMonthlyReturns),
weights = c(x.msft, x.sbux),
rebalance_on = "months",
contribution = TRUE)
head(equalWeightPortMonthlyReturns, 3)
```

```
## portfolio.returns MSFT SBUX
## Feb 1993 -0.04947917 -0.01822917 -0.031250000
## Mar 1993 0.08056628 0.05675676 0.023809524
## Apr 1993 -0.02974404 -0.03883495 0.009090909
```

You can see the rebalancing calculations by setting the optional argument `verbose = TRUE`

:

```
equalWeightPortMonthlyReturns =
Return.portfolio(na.omit(msftSbuxMonthlyReturns),
weights = c(x.msft, x.sbux),
rebalance_on = "months",
verbose = TRUE)
names(equalWeightPortMonthlyReturns)
```

```
## [1] "returns" "contribution" "BOP.Weight" "EOP.Weight" "BOP.Value"
## [6] "EOP.Value"
```

In this case `Return.portfolio()`

returns a list with the above components. The
component `BOP.Weight`

shows the beginning-of-period portfolio weights, and the
component `EOP.Weight`

shows the end-of-period portfolio weights (before any rebalancing).

```
## MSFT SBUX
## Feb 1993 0.5 0.5
## Mar 1993 0.5 0.5
## Apr 1993 0.5 0.5
```

With monthly returns and with `rebalance_on = "months"`

, the beginning-of-period
weights are always rebalanced to the initially supplied weights.

```
## MSFT SBUX
## Feb 1993 0.5068493 0.4931507
## Mar 1993 0.5152454 0.4847546
## Apr 1993 0.4753025 0.5246975
```

Because the returns for Microsoft and Starbux are different every month the end-of-period weights drift away from the beginning-of-period weights.

#### 1.4.3.2 Buy-and-hold portfolio

In the buy-and-hold portfolio, no rebalancing of the initial portfolio is done
and the portfolio weights are allowed to evolve over time based on the returns
of the assets. Hence, the computation of the portfolio return each month requires
knowing the weights on each asset each month. You can use `Return.portfolio()`

to
compute the buy-and-hold portfolio returns as follows:

```
buyHoldPortMonthlyReturns =
Return.portfolio(na.omit(msftSbuxMonthlyReturns),
weights = c(x.msft, x.sbux))
head(buyHoldPortMonthlyReturns, 3)
```

```
## portfolio.returns
## Feb 1993 -0.04947917
## Mar 1993 0.08101761
## Apr 1993 -0.03186097
```

Omitting the optional argument `rebalance_on`

tells `Return.portfolio()`

to not
rebalance the portfolio at all (default behavior of the function).

#### 1.4.3.3 Periodic rebalancing

In practice, a portfolio may be rebalanced at a specific frequency that is different than the frequency of the returns. For example, with monthly returns the portfolio might be rebalanced quarterly or annually. For example, to rebalance the equally weighted portfolio of Microsoft and Starbucks stock each quarter (every three months) use

```
equalWeightQtrPortMonthlyReturns =
Return.portfolio(na.omit(msftSbuxMonthlyReturns),
weights = c(x.msft, x.sbux),
rebalance_on = "quarters")
head(equalWeightQtrPortMonthlyReturns, 3)
```

```
## portfolio.returns
## Feb 1993 -0.04947917
## Mar 1993 0.08101761
## Apr 1993 -0.02974404
```

In between quarters, the portfolio evolves as a buy-and-hold portfolio. To see
the details of the rebalancing set `verbose = TRUE`

in the call to `Return.Portfolio()`

.

#### 1.4.3.4 Active portfolio weights

If the weights are actively chosen at specific time periods, these weights can be
supplied to the function `Return.portfolio()`

to compute the portfolio return.

### 1.4.4 Downloading financial data from the internet

The data for the examples in this book, available in the **IntroCompFinR** package,
were downloaded from finance.yahoo.com using the `getSymbols()`

function from the **quantmod** package.

For example, to download daily data on Amazon and Google stock (ticker symbols AMZN and GOOG) from January 3, 2007 through January 3, 2020 use `getSymbols()`

as follows:

```
options("getSymbols.warning4.0"=FALSE)
suppressPackageStartupMessages(library(quantmod))
getSymbols(Symbols = c("AMZN", "GOOG"), from="2007-01-03", to="2020-01-03",
auto.assign=TRUE, warnings=FALSE)
```

`## [1] "AMZN" "GOOG"`

`## [1] "xts" "zoo"`

The `xts`

objects `AMZN`

and `GOOG`

each have six columns containing the daily open price for the day, high price for the day, low price for the day, close price for the day, volume for the day, and (dividend and split) adjusted closing price for the day:

```
## AMZN.Open AMZN.High AMZN.Low AMZN.Close AMZN.Volume AMZN.Adjusted
## 2007-01-03 38.68 39.06 38.05 38.70 12405100 38.70
## 2007-01-04 38.59 39.14 38.26 38.90 6318400 38.90
## 2007-01-05 38.72 38.79 37.60 38.37 6619700 38.37
```

```
## GOOG.Open GOOG.High GOOG.Low GOOG.Close GOOG.Volume GOOG.Adjusted
## 2007-01-03 232.1299 237.4400 229.6940 232.9220 15470772 232.9220
## 2007-01-04 233.6243 241.0714 233.3005 240.7277 15834329 240.7277
## 2007-01-05 240.3491 242.8398 238.1623 242.6853 13795717 242.6853
```

These are prices that are adjusted for dividends and stock splits. That is, any dividend payments have been included in the prices and historical prices have been divided by the split ratio associated with any stock splits.↩︎

See the Appendix Working with Time Series Data in R for an overview of

`xts`

objects and Zivot (2016) for a comprehensive coverage.↩︎The method function

`lag.xts()`

works differently than generic`lag()`

function and the method function`lag.zoo()`

. In particular,`lag.xts()`

with optional argument`k=1`

gives the same result as`lag()`

and`lag.zoo()`

with`k=-1`

.↩︎You can also use the

**PerformanceAnalytics**function`chart.CumReturns()`

.↩︎