rportfolioperformanceanalyticstidyquant

How to use tidyquant (performance analytics) to calculate portfolio statistics in a portfolio with varying assets by period


I know there are good resources for calculating stock and portfolio returns using performance analytics in tidyquant for R. For example, assume we want to determine the annual portfolio returns (2011 through 2015) for a portfolio that contains "XOM" (0.5), "MA" (0.3), and "GOOG" (0.2), where () indicates the asset weight within the portfolio. The code would simply be:

Ra_symbols <- c("XOM", "MA", "GOOG")

wts_map <- tibble(
  symbols = c("XOM", "MA", "GOOG"),
  weights = c(0.5, 0.3, 0.2)
  )

Ra_2010to2020 <- Ra_symbols %>% 
  tq_get(get  = "stock.prices",
         from = "2010-12-31",
         to   = "2015-12-31") %>%
  group_by(symbol) %>%
  tq_transmute(select = adjusted,
               mutate_fun = periodReturn,
               period = "yearly",
               col_rename = "Ra")

Ra_weightedportfolioreturn <- Ra_2010to2020 %>% 
  tq_portfolio(assets_col  = symbol, 
               returns_col = Ra, 
               weights     = wts_map, 
               col_rename  = "Ra_using_wts_map")

But I cannot find any resource to help with the code if the portfolio contains different assets in each year with varying weights. For example, assume we have two dataframes: one with the symbols for each year and one with the respective portfolio weights. Below is the code to read in the csv file with the symbols and weights, along with images to illustrate the dataframes.

symbols2011to2015 <- read_csv("Symboltest_2011to2015.csv")
weights2011to2015 <- read_csv("wtstest_2011to2015.csv")

Dataframe with symbols by year

Dataframe with symbol weights by year

I'm thinking it's going to involve some tidyverse functions like "apply" or "map", but am not sure. Also, can tidyquant work with symbols (and weights) in a dataframe as I have it, or do I need to convert them to character values similar to the results from c("XOM", "MA", "GOOG")? Eventually, I'd like to expand this concept for monthly periods, but once I figure it out for multiple years the process should be similar.

Any help would be much appreciated!


Solution

  • (This is a follow up to the comment.)

    There is documentation in the PMwR manual.

    The input to returns does not have to be a zoo series: matrices or data-frames will work as well, as long as the prices are arranged in columns. However, working with zoo is quite convenient. To take your example:

    library("zoo")
    library("tidyquant")
    
    P <- tq_get(c("XOM", "MA", "GOOG"),
                get  = "stock.prices",
                from = "2010-12-31",
                to   = "2015-12-31")
    
    P <- do.call(merge, by(P, P$symbol, function(x) zoo(x$adjusted, x$date)))
    ##                GOOG       MA      XOM
    ## 2010-12-31 295.8760 21.09419 50.33540
    ## 2011-01-03 301.0466 20.78734 51.31982
    ## 2011-01-04 299.9358 21.05560 51.56077
    ## 2011-01-05 303.3978 21.67588 51.42308
    ## 2011-01-06 305.6045 21.76818 51.75351
    ## 2011-01-07 307.0690 21.76536 52.03575
    

    Now suppose you have a matrix Wof weights

    W <- rbind(c(1/3, 1/3, 1/3),
               c(0.6, 0.2, 0.2),
               c(1/3, 1/3, 1/3),
               c(0.6, 0.2, 0.2),
               c(1/3, 1/3, 1/3))
    

    and dates when to rebalance:

    when <- as.Date(c("2010-12-31", "2011-12-30", "2012-12-31",
                      "2013-12-31", "2014-12-31"))
    

    Each element in when corresponds to a row in W. Now we can compute portfolio returns.

    library("PMwR")
    R <- returns(P, rebalance.when = when, weights = W)
    ##  2011-01-03   2011-01-04   2011-01-05   2011-01-06  ....
    ## 0.007495421  0.004549025  0.012637607  0.005984054  ....
    
    ## ## If 'P' had not been a zoo matrix:
    ## returns(coredata(P), t = index(P), rebalance.when = when, weights = W)
    ## ## would work as well
    

    returns expects as input a price series. We can easily create such a series, based on R.

    tmp <- cumprod(1 + returns(P, rebalance.when = when, weights = W, pad = 0))
    

    This series we can transform into holding-period returns.

    returns(tmp, period = "month")
    ##       Jan Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec  YTD
    ## 2011  5.7 3.5 -0.4  2.7 -0.9 -0.1  4.5 -1.7 -3.5 10.4  4.8  3.4 31.4
    ## 2012 -7.3 8.4  2.2 -1.7 -6.3  3.0  5.7  4.2  8.4 -5.4  2.3  0.5 13.2
    ## 2013  5.5 2.1  1.4  1.7  3.8  0.6  3.6 -3.8  4.7  9.7  4.6  7.9 49.7
    ## 2014 -0.4 3.3 -5.7 -2.6  4.3  1.0 -0.6  0.6 -0.9  1.0 -2.1 -1.6 -4.0
    ## 2015 -2.8 5.5 -3.3  1.8 -0.1 -1.0  6.8 -3.4 -1.8 13.0  1.3  0.7 16.6
    
    returns(tmp, period = "year")
    ## 2011 2012 2013 2014 2015 
    ## 31.4 13.2 49.7 -4.0 16.6