R/wfo_equitycurve.R

Defines functions wfo_equitycurve

Documented in wfo_equitycurve

####################################################################################
# FILE wfo_equitycurve.R
#
#
#
####################################################################################
# FUNCTION wfo_equitycurve
#
#' Build the equity based on WFO weights data
#'
#'
#' @param wfodata      The data structure containing the walk-forward optimization
#'                     information.  It should be of class "optimize.portfolio.rebalancing"
#'                     or otherwise, it must be a list containing two objects:  $weights, an
#'                     xts of weights, and $R, an xts of daily returns over the entire
#'                     period to build the equity curve.
#'
#' @param rebal_offset The offset in days past the weight rebalance date and when
#'                     the portfolio is balanced.  Default is zero, which means
#'                     the portfolio is rebalanced on the very next day after
#'                     the weights date i.e. it include the next day's return, therefore
#'                     the rebalance is done on the weight date closing prices.
#'
#' @return Returns an xts matrix of two columns.  The first column is the equity curve,
#'         and the second column is the daily returns of the equity curve.
#'
#'
#' @seealso wfo_statfolio
#'
#' @export
#----------------------------------------------------------------------------------
wfo_equitycurve <- function(wfodata, rebal_offset = 0) {

  # ###### For TESTING  #######
  # library(ResilientPortfolio)
  # rebal_offset = 4
  # #wfodata  = wfo_dataquarters
  # xprices   = xts_data["2008/2009", c("SPY", "BND")]
  # wfodates = index(xprices[endpoints(xprices, on = "quarters")[-1], ])
  # wfodata = NULL
  # wfodata$weights = xts(matrix(data = rep(c(0.3, 0.7), length(wfodates)),
  #                              ncol = 2, byrow = TRUE,
  #                              dimnames = list(NULL, c("SPY", "BND"))),
  #                       order.by = as.Date(wfodates))
  # wfodata$weights[7, ] <- c(0.50, 0.50)
  # wfodata$R  = ROC(xprices, type = "discrete")[-1]
  #
  # ########

  #--------------------------------------------------------------------
  # Allow simple data structure for storing weights by testing class
  #--------------------------------------------------------------------
  if(class(wfodata) == "optimize.portfolio.rebalancing")
    weights <- extractWeights(wfodata)
  else
    weights <- wfodata$weights  # For any other class

  weight_dates  <- as.Date(index(weights))
  Ndates        <- length(weight_dates)

  #--------------------------------------------------------------------
  # Extract the asset returns and build equity curves over timeframe
  #--------------------------------------------------------------------
  rets          <- wfodata$R
  timeframe     <- paste0(weight_dates[1], "/", index(last(rets)))
  prices        <- cumprod_na(1 + rets)

  rets          <- rets[timeframe, ]
  prices        <- prices[timeframe, ]

  Nrets         <- nrow(rets)              # same and nrow(prices)
  dailyindex    <- as.Date(index(rets))
  rebal_i       <- rets[dailyindex %in% weight_dates, , which.i = TRUE]

  #-------------------------------------------------------------------
  # Offset dates by adding to rebal_i to get proper rebal_dates
  # Add one to ensure no lookahead bias (at rebal_offset = 0)
  #-------------------------------------------------------------------
  rebal_ioffset  <- rebal_i + rebal_offset
  rebal_ioffset  <- rebal_ioffset[rebal_ioffset <= (Nrets - rebal_offset - 1)]

  rebal_ioffset1 <- rebal_ioffset + 1
  rebal_ioffset1 <- rebal_ioffset1[rebal_ioffset1 <= Nrets]

  if(last(rebal_ioffset1) < Nrets) {
    rebal_ioffset1 <- c(rebal_ioffset1, Nrets)
    rebal_ioffset  <- c(rebal_ioffset,  Nrets - 1)
  }

  rebal_dates    <- index(rets[rebal_ioffset,])
  rebal_dates1   <- index(rets[rebal_ioffset1, ])

  #-----------------------------------------------------------------------------
  # On each rebal_date and until the next one, build the normalized
  # equity curves for each asset, apply their portfolio weight during
  # the timeframe, and sum up the results to get the portfolio equity curve.
  # Then convert that EC to daily returns to build the returns for that
  # timeframe.
  #
  # .ecrets holds the equity curves normalized at each  rebal_date
  # .rebal_dates1 is the next day after rebal_dates (last day dropped)
  #-----------------------------------------------------------------------------
  ecrets       <- emptyxts(cnames = "ec", order.by = index(prices[timeframe, ]))

  daily_weights  <- emptyxts(cnames = colnames(weights), order.by = index(ecrets))
  daily_weights[rebal_dates, ] <- weights[1:length(rebal_dates), ]
  daily_weights  <- na.locf(daily_weights)

  # If rebal_dates is NOT the last date, then need on extra iteration

  for(i in 2:length(rebal_dates)) {
    tf       <- paste0(rebal_dates[i-1], "/", rebal_dates1[i])
    tf1      <- paste0(rebal_dates1[i-1], "/", rebal_dates1[i])  # skips first day!
    x        <- xtsnormalize(prices[tf, ])
    x2       <- as.xts(t(apply(x, 1, function(z) z * daily_weights[rebal_dates[i-1], ])))
    x2$ec    <- rowSums(x2)
    partrets <- ROC(x2$ec, type = "discrete")[-1]
    ecrets[tf1, ] <- partrets
  }

  #----------------------------------------------------------------------------
  # Build the equity curve for the entire timeframe from the daily returns
  #----------------------------------------------------------------------------
  ec      <- cumprod_na(1 + ecrets)
  ec$rets <- ecrets

  xtsplot(ec[, "ec"])

  #--------------------------------------------------------
  # Return xts for equity curve
  #--------------------------------------------------------
  return(ec)

}  #########  END FUNCTION wfo_equitycurve ##########


#--------------------------------------------------------
# Build portfolio xts using asset returns and weights
# .weights_offset is the weights offset at rebal_dates
# .subrets starts at first rebal date
# .daily_weights is daily version of weights_offset
#--------------------------------------------------------
# weights_offset <- xts(weights[1:length(rebal_dates), ],
#                       order.by = as.Date(rebal_dates))
# subrets        <- rets[rebal_ioffset[1]:nrow(rets), ]
# daily_weights  <- emptyxts(cnames = colnames(weights_offset),
#                            order.by = index(subrets))
#
# daily_weights[rebal_dates, ] <- weights_offset
# daily_weights  <- na.locf(daily_weights)

#--------------------------------------------------------
# Build the portfolio weights * rets, Equity Curve
# This is wrong!  It assumes daily weights applied
# to each asset, ignoring their changing weight during
# the month.
#--------------------------------------------------------
# portrets  <- daily_weights * subrets
#
# ec    <- emptyxts(cnames = "rets", order.by = index(subrets))
# ec[]  <- t(apply(portrets, 1, sum))
#
# ec$ec <- cumprod_na(1 + ec$rets)
jeanmarcgp/ResilientPortfolio documentation built on April 8, 2018, 5:43 p.m.