[Returnanalytics-commits] r2492 - pkg/PortfolioAnalytics/R
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Wed Jul 3 03:44:31 CEST 2013
Author: rossbennett34
Date: 2013-07-03 03:44:29 +0200 (Wed, 03 Jul 2013)
New Revision: 2492
Modified:
pkg/PortfolioAnalytics/R/constraint_fn_map.R
Log:
adding rp_transform function that transforms a vector to satisfy min_sum/max_sum constraints and min/max box constraints using randomize_portfolio logic
Modified: pkg/PortfolioAnalytics/R/constraint_fn_map.R
===================================================================
--- pkg/PortfolioAnalytics/R/constraint_fn_map.R 2013-07-02 22:52:25 UTC (rev 2491)
+++ pkg/PortfolioAnalytics/R/constraint_fn_map.R 2013-07-03 01:44:29 UTC (rev 2492)
@@ -196,6 +196,114 @@
return(weights)
}
+#' Transform a weights vector to min_sum/max_sum leverage and min/max box constraints using logic from randomize_portfolio
+#'
+#' This function uses a block of code from \link{\code{randomize_portfolio}}
+#' to transform the weight vector if either the weight_sum (leverage)
+#' constraints or box constraints are violated.
+#' The resulting weights vector might be quite different from the original weights vector.
+#'
+#' @param w weights vector to be transformed
+#' @param min_sum minimum sum of all asset weights, default 0.99
+#' @param max_sum maximum sum of all asset weights, default 1.01
+#' @param min numeric or named vector specifying minimum weight box constraints
+#' @param max numeric or named vector specifying maximum weight box constraints
+#' @param max_permutations integer: maximum number of iterations to try for a valid portfolio, default 200
+#' @return named weighting vector
+#' @author Peter Carl, Brian G. Peterson, Ross Bennett (based on an idea by Pat Burns)
+#' @export
+rp_transform <- function(w, min_sum=0.99, max_sum=1.01, min, max, max_permutations=200){
+ # Uses logic from randomize_portfolio to "normalize" a weights vector to
+ # satisfy min_sum and max_sum while account for min and max box constraints
+ # Modified from randomize_portfolio to trigger the while loops if any weights
+ # violate min or max box constraints. A weights vector would not be transformed
+ # in randomize_portfolio if min_sum and max_sum were satisfied, but the
+ # min/max constraints were violated.
+
+ # generate a sequence of weights based on min/max box constraints
+ weight_seq <- generatesequence(min=min(min), max=max(max), by=0.005)
+
+ # start the permutations counter
+ permutations <- 1
+
+ # create a temporary weights vector that will be modified in the while loops
+ tmp_w <- w
+
+ # while portfolio is outside min_sum/max_sum or min/max and we have not reached max_permutations
+ while ((sum(tmp_w) <= min_sum | sum(tmp_w) >= max_sum | any(tmp_w < min) | any(tmp_w > max)) & permutations <= max_permutations) {
+ permutations = permutations + 1
+ # check our box constraints on total portfolio weight
+ # reduce(increase) total portfolio size till you get a match
+ # 1> check to see which bound you've failed on, brobably set this as a pair of while loops
+ # 2> randomly select a column and move only in the direction *towards the bound*, maybe call a function inside a function
+ # 3> check and repeat
+
+ random_index <- sample(1:length(tmp_w), length(tmp_w))
+ i = 1
+ # while sum of weights is less than min_sum or min/max box constraint is violated
+ while ((sum(tmp_w) <= min_sum | any(tmp_w < min) | any(tmp_w > max)) & i <= length(tmp_w)) {
+ # randomly permute and increase a random portfolio element
+ cur_index <- random_index[i]
+ cur_val <- tmp_w[cur_index]
+ if (length(weight_seq[(weight_seq >= cur_val) & (weight_seq <= max[cur_index])]) > 1) {
+ # randomly sample an element from weight_seq that is greater than cur_val and less than max
+ tmp_w[cur_index] <- sample(weight_seq[(weight_seq >= cur_val) & (weight_seq <= max[cur_index])], 1)
+ # print(paste("new val:",tmp_w[cur_index]))
+ } else {
+ if (length(weight_seq[(weight_seq >= cur_val) & (weight_seq <= max[cur_index])]) == 1) {
+ tmp_w[cur_index] <- weight_seq[(weight_seq >= cur_val) & (weight_seq <= max[cur_index])]
+ }
+ }
+ i=i+1 # increment our counter
+ } # end increase loop
+ # while sum of weights is greater than max_sum or min/max box constraint is violated
+ while ((sum(tmp_w) >= max_sum | any(tmp_w < min) | any(tmp_w > max)) & i <= length(tmp_w)) {
+ # randomly permute and decrease a random portfolio element
+ cur_index <- random_index[i]
+ cur_val <- tmp_w[cur_index]
+ if (length(weight_seq <= cur_val & weight_seq >= min[cur_index] ) > 1) {
+ # randomly sample an element from weight_seq that is less than cur_val and greater than min
+ tmp_w[cur_index] <- sample(weight_seq[which(weight_seq <= cur_val & weight_seq >= min[cur_index] )], 1)
+ } else {
+ if (length(weight_seq <= cur_val & weight_seq >= min[cur_index] ) == 1) {
+ tmp_w[cur_index] <- weight_seq[(weight_seq <= cur_val) & (weight_seq >= min[cur_index])]
+ }
+ }
+ i=i+1 # increment our counter
+ } # end decrease loop
+ } # end final walk towards the edges
+
+ portfolio <- tmp_w
+
+ colnames(portfolio)<-colnames(w)
+
+ # checks for infeasible portfolio
+ if (sum(portfolio)<=min_sum | sum(portfolio)>=max_sum){
+ portfolio <- w
+ warning("Infeasible portfolio created, defaulting to w, perhaps increase max_permutations.")
+ }
+ if(isTRUE(all.equal(w,portfolio))) {
+ if (sum(w)>=min_sum & sum(w)<=max_sum) {
+ warning("Unable to generate a feasible portfolio different from w, perhaps adjust your parameters.")
+ return(w)
+ } else {
+ warning("Unable to generate a feasible portfolio, perhaps adjust your parameters.")
+ return(NULL)
+ }
+ }
+ return(portfolio)
+}
+
+# test
+# w <- c(0.1, 0.25, 0.3, 0.15, 0.05, 0.15)
+# min <- rep(0.1, length(w))
+# max <- rep(0.45, length(w))
+# w1 <- rp_normalize(w=w, min_sum=0.99, max_sum=1.01, min=min, max=max)
+# w1
+# sum(w1)
+# any(w1 < min)
+# any(w1 > max)
+
# library(PortfolioAnalytics)
# data(edhec)
# ret <- edhec[, 1:4]
More information about the Returnanalytics-commits
mailing list