[Returnanalytics-commits] r3094 - pkg/PortfolioAnalytics/R
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Fri Sep 13 19:10:17 CEST 2013
Author: rossbennett34
Date: 2013-09-13 19:10:17 +0200 (Fri, 13 Sep 2013)
New Revision: 3094
Modified:
pkg/PortfolioAnalytics/R/random_portfolios.R
Log:
adding grid method for random portfolios.
Modified: pkg/PortfolioAnalytics/R/random_portfolios.R
===================================================================
--- pkg/PortfolioAnalytics/R/random_portfolios.R 2013-09-13 16:37:51 UTC (rev 3093)
+++ pkg/PortfolioAnalytics/R/random_portfolios.R 2013-09-13 17:10:17 UTC (rev 3094)
@@ -420,6 +420,109 @@
return(out)
}
+#' Generate random portfolios based on grid search method
+#'
+#' This function generates random portfolios based on the \code{gridSearch}
+#' function from the 'NMOF' package.
+#'
+#' @details
+#' The number of levels is calculated based on permutations and number of assets.
+#' The number of levels must be an integer and may not result in the exact number
+#' of permutations. We round up to the nearest integer for the levels so the
+#' number of portfolios generated will be greater than or equal to permutations.
+#'
+#' The grid search method only satisfies the \code{min} and \code{max} box
+#' constraints. The \code{min_sum} and \code{max_sum} leverage constraints will
+#' likely be violated and the weights in the random portfolios should be
+#' normalized. Normalization may cause the box constraints to be violated and
+#' will be penalized in \code{constrained_objective}.
+#'
+#' @param portfolio
+#' @param permutations
+#' @param normalize TRUE/FALSE
+#' @param \dots any passthru parameters. Currently ignored
+#' @return matrix of random portfolios
+#' @export
+rp_grid <- function(portfolio, permutations=2000, normalize=TRUE, ...){
+
+ # get the constraints from the portfolio
+ constraints <- get_constraints(portfolio)
+
+ # box constraints to generate the grid
+ min <- constraints$min
+ max <- constraints$max
+
+ # number of parameters and length.out levels to generate
+ npar <- length(min)
+ n <- ceiling(exp(log(permutations) / npar))
+
+ levels <- vector("list", length = length(min))
+ for (i in seq_len(npar)){
+ levels[[i]] <- seq(min[[i]], max[[i]], length.out = max(n, 2L))
+ }
+ np <- length(levels)
+ res <- vector("list", np)
+ rep.fac <- 1L
+ nl <- sapply(levels, length)
+ nlp <- prod(nl)
+
+ # create the grid
+ for (i in seq_len(np)) {
+ x <- levels[[i]]
+ nx <- length(x)
+ nlp <- nlp/nx
+ res[[i]] <- x[rep.int(rep.int(seq_len(nx), rep.int(rep.fac, nx)), nlp)]
+ rep.fac <- rep.fac * nx
+ }
+
+ # create the random portfolios from the grid
+ nlp <- prod(nl)
+ lstLevels <- vector("list", length = nlp)
+ for (r in seq_len(nlp)) {
+ lstLevels[[r]] <- sapply(res, `[[`, r)
+ }
+ # lstLevels is a list of random portfolios, rbind into a matrix
+ rp <- do.call(rbind, lstLevels)
+
+ # min_sum and max_sum will likely be violated
+ # Normalization will likely cause min and max to be violated. This can be
+ # handled by the penalty in constrained_objective.
+ if(normalize){
+ normalize_weights <- function(weights){
+ # normalize results if necessary
+ if(!is.null(constraints$min_sum) | !is.null(constraints$max_sum)){
+ # the user has passed in either min_sum or max_sum constraints for the portfolio, or both.
+ # we'll normalize the weights passed in to whichever boundary condition has been violated
+ # NOTE: this means that the weights produced by a numeric optimization algorithm like DEoptim
+ # might violate your constraints, so you'd need to renormalize them after optimizing
+ # we'll create functions for that so the user is less likely to mess it up.
+
+ ##' NOTE: need to normalize in the optimization wrapper too before we return, since we've normalized in here
+ ##' In Kris' original function, this was manifested as a full investment constraint
+ if(!is.null(constraints$max_sum) & constraints$max_sum != Inf ) {
+ max_sum=constraints$max_sum
+ if(sum(weights)>max_sum) { weights<-(max_sum/sum(weights))*weights } # normalize to max_sum
+ }
+
+ if(!is.null(constraints$min_sum) & constraints$min_sum != -Inf ) {
+ min_sum=constraints$min_sum
+ if(sum(weights)<min_sum) { weights<-(min_sum/sum(weights))*weights } # normalize to min_sum
+ }
+
+ } # end min_sum and max_sum normalization
+ return(weights)
+ }
+
+ stopifnot("package:foreach" %in% search() || require("foreach",quietly = TRUE))
+ out <- foreach(1=1:nrow(rp)) %dopar% {
+ tmp <- normalize_weights(weights=rp[i,])
+ tmp
+ }
+ out <- do.call(rbind, out)
+ }
+ if(normalize) return(out) else return(rp)
+}
+
# EXAMPLE: start_t<- Sys.time(); x=random_walk_portfolios(rep(1/5,5), generatesequence(min=0.01, max=0.30, by=0.01), max_permutations=500, permutations=5000, min_sum=.99, max_sum=1.01); end_t<-Sys.time(); end_t-start_t;
# > nrow(unique(x))
# [1] 4906
More information about the Returnanalytics-commits
mailing list