Path: blob/master/R/mult.layer.portfolio.R
1433 views
12# I am going to start with two levels. Once that is working, I will generalize3# to any arbitrary number of levels.45#' Multple Layer Portfolio Specification6#'7#' Create and specify a multiple layer portfolio8#'9#' The \code{sub.portfolios} slot is a list where each element contains the10#' portfolio object and rebalancing parameters for the optimization of the11#' sub portfolio.12#' This allows, for example, each sub portfolio to have different rebalancing13#' frequencies (i.e. monthly or quarterly), optimization methods, etc.14#'15#' Each sub portfolio is optimized with \code{optimize.portfolio.rebalancing}16#' to create a time series of proxy returns.17#'18#' The "top level" portfolio is used to specify the constraints and objectives19#' to control the optimization given the proxy returns of each sub portfolio.20#'21#' @param portfolio the "top level" portfolio22#' @param levels number of levels of sub-portfolios23#' @param \dots any additional parameters24#' @return a \code{mult.portfolio.spec} object with the top level portfolio25#' and sub portfolios with optimization parameters for each sub portfolio26#' @author Ross Bennett27#' @export28mult.portfolio.spec <- function(portfolio, levels=2, ...){29structure(c(list(top.portfolio = portfolio,30sub.portfolios = list()),31list(...)),32class="mult.portfolio.spec")33}3435# constructor for sub.portfolio object36sub.portfolio <- function(portfolio,37optimize_method = c("DEoptim","random","ROI","pso","GenSA"),38search_size = 20000,39rp = NULL,40rebalance_on = NULL,41training_period = NULL,42trailing_periods = NULL,43...){44# Check to make sure that the portfolio passed in is a portfolio object45if (!is.portfolio(portfolio)) stop("portfolio passed in is not of class 'portfolio'")4647# structure and return48return(structure( c(list(portfolio = portfolio,49optimize_method = optimize_method[1],50search_size = search_size,51rp = rp,52rebalance_on = rebalance_on,53training_period = training_period,54trailing_periods = trailing_periods),55list(...)),56class="sub.portfolio"57) # end structure58)59}6061#' Add sub-portfolio62#'63#' Add a sub-portfolio to a multiple layer portfolio specification object64#'65#' @param mult.portfolio a \code{mult.portfolio.spec} object66#' @param portfolio a \code{portfolio} object to add as a sub portfolio.67#' @param optimize_method optimization method for the sub portfolio68#' @param search_size integer, how many portfolios to test, default 20,00069#' @param rp matrix of random portfolio weights, default NULL, mostly for automated use by rebalancing optimization or repeated tests on same portfolios70#' @param rebalance_on haracter string of period to rebalance on. See71#' \code{\link[xts]{endpoints}} for valid names.72#' @param training_period an integer of the number of periods to use as73#' a training data in the front of the returns data74#' @param trailing_periods an integer with the number of periods to roll over75#' (i.e. width of the moving or rolling window), the default is NULL will76#' run using the returns data from inception77#' @param \dots additonal passthrough parameters to \code{\link{optimize.portfolio.rebalancing}}78#' @param indexnum the index number of the sub portfolio. If \code{indexnum=NULL}79#' (the default), then the sub portfolio object is appended to the list of80#' sub portfolios in the \code{mult.portfolio} object. If \code{indexnum} is81#' specified, the portfolio in that index number is overwritten.82#' @seealso \code{\link{mult.portfolio.spec}} \code{\link{portfolio.spec}} \code{\link{optimize.portfolio}} \code{\link{optimize.portfolio.rebalancing}}83#' @author Ross Bennett84#' @export85add.sub.portfolio <- function(mult.portfolio,86portfolio,87optimize_method = c("DEoptim","random","ROI","pso","GenSA"),88search_size = 20000,89rp = NULL,90rebalance_on = NULL,91training_period = NULL,92trailing_periods = NULL,93...,94indexnum = NULL){95# Check to make sure that the portfolio passed in is a portfolio mult.portfolio96if(!inherits(mult.portfolio, "mult.portfolio.spec")) stop("mult.portfolio must be of class 'mult.portfolio.spec'")9798# construct a sub portfolio object99tmp_portfolio <- sub.portfolio(portfolio=portfolio,100optimize_method=optimize_method[1],101search_size=search_size,102rp=rp,103rebalance_on=rebalance_on,104training_period=training_period,105trailing_periods=trailing_periods,106...=...)107108if(inherits(tmp_portfolio, "sub.portfolio")){109if(!hasArg(indexnum) | (hasArg(indexnum) & is.null(indexnum))){110indexnum <- length(mult.portfolio$sub.portfolios)+1111}112mult.portfolio$sub.portfolios[[indexnum]] <- tmp_portfolio113}114return(mult.portfolio)115}116117# This function calls optimize.portfolio.rebalancing on each sub portfolio118# according to the given optimization parameters and returns an xts object119# representing the proxy returns of each sub portfolio120proxy.mult.portfolio <- function(R, mult.portfolio, ...){121# Check to make sure that the mult.portfolio passed in is a122# mult.portfolio.spec object123if(!inherits(mult.portfolio, "mult.portfolio.spec")){124stop("mult.portfolio must be of class 'mult.portfolio.spec'")125}126127n.sub.portfolios <- length(mult.portfolio$sub.portfolios)128if(n.sub.portfolios <= 1) stop("Must have more than 1 sub portfolio")129130# Initialize list to store the returns for each sub portfolio131ret <- vector("list", n.sub.portfolios)132133# Loop through the sub portfolios and call optimize.portfolio.rebalancing134# on each sub portfolio and its optimization parameters135for(i in 1:n.sub.portfolios){136#print(paste("sub portfolio", i))137tmp <- mult.portfolio$sub.portfolios[[i]]138139# We need to subset the R object based on the names of portfolio$assets in140# the sub portfolio141# This requires that asset names match colnames(R)142R.tmp <- R[,names(tmp$portfolio$assets)]143if(ncol(R.tmp) != length(tmp$portfolio$assets)){144stop("R object of returns not subset correctly. Make sure the names of145the assets in the sub portfolio match the column names of the R object")146}147# This needs to support anything in ... that could be passed to optimize.portfolio148.formals <- formals(optimize.portfolio.rebalancing)149.formals <- modify.args(formals=.formals, arglist=NULL, R=R, dots=TRUE)150.formals <- modify.args(formals=.formals, arglist=tmp, dots=TRUE)151.formals$... <- NULL152#print(.formals)153opt <- try(do.call(optimize.portfolio.rebalancing, .formals), silent=TRUE)154if(!inherits(opt, "try-error")) {155w <- extractWeights(opt)156# geometric chaining TRUE/FALSE, should be FALSE if any weights are negative157g <- ifelse(any(w < 0), FALSE, TRUE)158ret.tmp <- Return.portfolio(R.tmp, weights = w, geometric = g)159colnames(ret.tmp) <- paste("proxy", i, sep=".")160ret[[i]] <- ret.tmp161#print(ret[[i]])162} else {163stop(paste("optimize.portfolio.rebalancing for sub portfolio", i, "generated an error or warning:", opt))164}165}166proxy.ret <- na.omit(do.call(cbind, ret))167return(proxy.ret)168}169170171172173