Calculating portfolio level returns

287 views Asked by At

EDIT UPDATED I've found a great post by the authors of performanceAnalytics. This post basically sums up the ins-outs of cumulative portfolio returns, and as the author shows it's pretty tricky (he got it wrong too)! Here it is for reference: https://tradeblotter.wordpress.com/2014/09/25/aggregate-portfolio-contributions-through-time/

SO I've run into a little bit of a stump where my two numbers should be adding up but they are not. Here's an example dataframe with stock choices and their weightings of a portfolio for context:

      stock.choices stock_weights
1          GOOG         0.150
2          AMZN         0.200
3            BA         0.250
4            FB         0.225
5          AAPL         0.175

Then I'm going to use the Return.portfolio function with wealth.index = TRUE to show the return of my portfolio.

Portfolio <- merge.xts(GOOG,AMZN,BA,FB,AAPL)
dollar_growth <- Return.portfolio(Portfolio, weights = stock_weights, wealth.index = TRUE)

I use dygraph to visualise the dollar growth.

dygraph(dollar_growth, main = "Portfolio Growth Base.$1") %>% dyAxis("y", label = "$")%>%
  dyAnnotation("2017-05-01", text = May1, tooltip = "Initial Investment", width = 70, height = 18, tickHeight = -75)%>%
  dyAnnotation(LastDay, text = Today, tooltip = "Percentage Increase",width = 70,  attachAtBottom = TRUE) %>%
  dyAxis("y", label = "Dollars USD")

For this example I'm going to use May 1st as the initial point of investment. On this portfolio I'm getting 11.5% return form May 1st - calculated by taking the current value ($1.37) and dividing that by May 1st ($1.23057) yielding 11.33% increase.

However when I use a different method I get a different answer which is strange because I would have thought this second method was the accurate way of calculating the return of a portfolio.

Firstly I create a dataframe which has the stock values at May 1st and their current values. Then I multiply both by their respective weighting in the portfolio. Here's the output:

      May1 Current Stock.Weights    May1C  CurrentC
GOOG 912.57  926.50         0.150 136.8855 138.97500
AMZN 948.23  965.90         0.200 189.6460 193.18000
BA   182.39  238.78         0.250  45.5975  59.69500
FB   152.46  170.95         0.225  34.3035  38.46375
AAPL 146.58  158.63         0.175  25.6515  27.76025

May1C = May1 * Stock.Weights | CurrentC = Current * Stock.Weights

Now when I sum both May1C and CurrentC I get:

> sum(df$May1C)
[1] 432.084
> sum(df$CurrentC)
[1] 458.074

Which I would think would be the current value of the portfolio as it is the stock choices * their respective weights. This yields only an increase of 6.015%.

My question is: How is the return.portfolio function returning an 11.3% increase, where as the second method is returning a 6.015%?

Edit in reply to the comments I have found that when using return.portfolio the verbose = TRUE function returns the stock weights changing over time. This output shows the weights changing overtime with EOP and BOP.

For reference, here's the complete code to run the dygraph output:

library(PerformanceAnalytics)
library(quantmod)
library(dygraphs)
library(scales)

daily_stock_returns = function(ticker) {

    symbol <- getSymbols(ticker, src = 'google', auto.assign = FALSE, warnings = FALSE)
    symbol <- xts::last(symbol, "1 year")
    data <- periodReturn(symbol, period = 'daily', type = 'log')
    colnames(data) <- as.character(ticker)
    assign(ticker, data, .GlobalEnv)
}


    daily_stock_returns("GOOG")
    daily_stock_returns("AMZN")
    daily_stock_returns("BA")
    daily_stock_returns("FB")
    daily_stock_returns("AAPL")
    Portfolio <- merge.xts(GOOG,AMZN,BA,FB,AAPL)
    test <- periodReturn(Portfolio, period = 'monthly', type = 'log')
    stock_weights <- c(.15, .20, .25, .225, .175)

    dollar_growth <- Return.portfolio(Portfolio, weights = stock_weights, wealth.index = TRUE)
    May1 <- as.numeric(dollar_growth["2017-05-01"]) 
    format(round(May1, 3), nsmall = 2)
    Today <- as.numeric(xts::last(dollar_growth, "1 day"))
    Today <- ((Today/May1)-1) %>% percent()
    format(round(May1, 3), nsmall = 2)
    LastDay <- xts::last(dollar_growth, "1 day")
    dygraph(dollar_growth, main = "Portfolio Growth Base.$1") 
1

There are 1 answers

2
hvollmeier On

If you want to see the Dollar value of the portfolio components and the total portfolio you can do the following. Assuming what you want is investing in a portfolio on “DayStart (2017-01-01)” with allocation “alloc (.15, .20, .25, .225, .175)" and then WITHOUT rebalancing let it run it’s course until “DayEnd (2017-05-01)”:

initial alloc(e.g.1000 USD) for GOOG, AMZN, BA, FB, AAPL: 150, 200, 250, 225, 175

taking your portfolio returns “Portfolio” ( I took ‘discrete' returns not ‘log’):

startCapital <- c(150, 200, 250, 225, 175)
portDollar <- cumprod(1+Portfolio["::2017-05-01”]) * startCapital
portDollar <- cbind(portDollar,portf=rowSums(portDollar))

You can now plot the portfolio value in Dollars or convert it back to returns.

both(portDollar)
               GOOG     AMZN       BA       FB     AAPL    portf
2017-01-03 151.4052 248.5942 175.7486 201.4256 225.6790 1002.853
2017-01-04 202.0686 224.7743 152.2168 255.6943 175.3316 1010.086
2017-01-05 254.8609 180.1164 203.0709 233.9321 151.0465 1023.027
               GOOG     AMZN       BA       FB     AAPL    portf
2017-04-27 195.9950 241.4572 262.7753 190.4188 309.3954 1200.042
2017-04-28 173.9812 303.9860 206.1689 258.2377 278.1846 1220.558
2017-05-01 233.6613 280.3763 174.3678 327.5105 220.7346 1236.650