[Returnanalytics-commits] r2502 - in pkg/PortfolioAnalytics: R man sandbox
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Fri Jul 5 15:34:49 CEST 2013
Author: rossbennett34
Date: 2013-07-05 15:34:48 +0200 (Fri, 05 Jul 2013)
New Revision: 2502
Modified:
pkg/PortfolioAnalytics/R/constraint_fn_map.R
pkg/PortfolioAnalytics/man/rp_transform.Rd
pkg/PortfolioAnalytics/sandbox/testing_rp_transform.R
Log:
added position limit constraints to rp_transform
Modified: pkg/PortfolioAnalytics/R/constraint_fn_map.R
===================================================================
--- pkg/PortfolioAnalytics/R/constraint_fn_map.R 2013-07-05 07:59:10 UTC (rev 2501)
+++ pkg/PortfolioAnalytics/R/constraint_fn_map.R 2013-07-05 13:34:48 UTC (rev 2502)
@@ -312,11 +312,11 @@
return(weights)
}
-#' Transform a weights vector to satisfy leverage, box, and group constraints using logic from \code{randomize_portfolio}
+#' Transform a weights vector to satisfy leverage, box, group, and position_limit constraints using logic from \code{randomize_portfolio}
#'
#' This function uses a block of code from \code{\link{randomize_portfolio}}
#' to transform the weight vector if either the weight_sum (leverage)
-#' constraints, box constraints, or group constraints are violated.
+#' constraints, box constraints, group constraints, or position_limit constraints are violated.
#' The resulting weights vector might be quite different from the original weights vector.
#'
#' @param w weights vector to be transformed
@@ -327,11 +327,12 @@
#' @param groups vector specifying the groups of the assets
#' @param cLO numeric or vector specifying minimum weight group constraints
#' @param cUP numeric or vector specifying minimum weight group constraints
+#' @param max_pos maximum assets with non-zero weights
#' @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, groups, cLO, cUP, max_permutations=200){
+rp_transform <- function(w, min_sum=0.99, max_sum=1.01, min, max, groups, cLO, cUP, max_pos=NULL, max_permutations=200){
# Uses logic from randomize_portfolio to "normalize" a weights vector to
# satisfy min_sum and max_sum while accounting for box and group constraints
# Modified from randomize_portfolio to trigger the while loops if any weights
@@ -339,15 +340,21 @@
# in randomize_portfolio if min_sum and max_sum were satisfied, but the
# min/max constraints were violated.
+ tolerance=.Machine$double.eps^0.5
+ if(is.null(max_pos)) max_pos <- length(w)
+
# return w if all constraints are satisfied
if((sum(w) >= min_sum & sum(w) <= max_sum) &
(all(w >= min) & all(w <= max)) &
- (all(!group_fail(weights, groups, cLO, cUP)))){
+ (all(!group_fail(weights, groups, cLO, cUP))) &
+ (sum(abs(w) > tolerance) <= max_pos)){
return(w)
}
# generate a sequence of weights based on min/max box constraints
weight_seq <- generatesequence(min=min(min), max=max(max), by=0.005)
+ # make sure there is a 0 in weight_seq
+ if(!is.null(max_pos) & !is.element(0, weight_seq)) weight_seq <- c(0, weight_seq)
# start the permutations counter
permutations <- 1
@@ -355,19 +362,38 @@
# 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 or group constraints 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) | any(group_fail(tmp_w, groups, cLO, cUP))) & permutations <= max_permutations) {
+ # Create a temporary min vector that will be modified, because a feasible
+ # portfolio is rarely created if all(min > 0). This is due to the while
+ # loop that checks any(tmp_w < min).
+ tmp_min <- min
+
+ # while portfolio is outside min_sum/max_sum or tmp_min/max or group or postion_limit constraints and we have not reached max_permutations
+ while ((sum(tmp_w) <= min_sum | sum(tmp_w) >= max_sum | any(tmp_w < tmp_min) | any(tmp_w > max) | any(group_fail(tmp_w, groups, cLO, cUP)) | (sum(abs(tmp_w) > tolerance) > max_pos)) & 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
+ # 1> check to see which bound you've failed on, probably 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))
+ # reset tmp_w and tmp_min to their original values
+ tmp_w <- w
+ tmp_min <- min
+
+ random_index <- sample(1:length(tmp_w), max_pos)
+
+ # Get the index values that are not in random_index and set them equal to 0
+ full_index <- 1:length(tmp_w)
+ not_index <- setdiff(full_index, random_index)
+ tmp_w[not_index] <- 0
+
+ # set some tmp_min values equal to zero so the while loops do not see a
+ # violation of any(tmp_w < tmp_min)
+ tmp_min[not_index] <- 0
+
i = 1
- # while sum of weights is less than min_sum or min/max box or group constraint is violated
- while ((sum(tmp_w) <= min_sum | any(tmp_w < min) | any(tmp_w > max) | any(group_fail(tmp_w, groups, cLO, cUP))) & i <= length(tmp_w)) {
+ # while sum of weights is less than min_sum or tmp_min/max box or group constraint is violated
+ while ((sum(tmp_w) <= min_sum | any(tmp_w < tmp_min) | any(tmp_w > max) | any(group_fail(tmp_w, groups, cLO, cUP))) & i <= length(tmp_w)) {
# randomly permute and increase a random portfolio element
cur_index <- random_index[i]
cur_val <- tmp_w[cur_index]
@@ -385,17 +411,17 @@
# need to reset i here otherwise the decreasing loop will be ignored
# group_fail does not test for direction of violation, just that group constraints were violated
i = 1
- # while sum of weights is greater than max_sum or min/max box or group constraint is violated
- while ((sum(tmp_w) >= max_sum | any(tmp_w < min) | any(tmp_w > max) | any(group_fail(tmp_w, groups, cLO, cUP))) & i <= length(tmp_w)) {
+ # while sum of weights is greater than max_sum or tmp_min/max box or group constraint is violated
+ while ((sum(tmp_w) >= max_sum | any(tmp_w < tmp_min) | any(tmp_w > max) | any(group_fail(tmp_w, groups, cLO, cUP))) & 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)
+ if (length(weight_seq[(weight_seq <= cur_val) & (weight_seq >= tmp_min[cur_index])] ) > 1) {
+ # randomly sample an element from weight_seq that is less than cur_val and greater than tmp_min
+ tmp_w[cur_index] <- sample(weight_seq[(weight_seq <= cur_val) & (weight_seq >= tmp_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])]
+ if (length(weight_seq[(weight_seq <= cur_val) & (weight_seq >= tmp_min[cur_index])] ) == 1) {
+ tmp_w[cur_index] <- weight_seq[(weight_seq <= cur_val) & (weight_seq >= tmp_min[cur_index])]
}
}
i=i+1 # increment our counter
Modified: pkg/PortfolioAnalytics/man/rp_transform.Rd
===================================================================
--- pkg/PortfolioAnalytics/man/rp_transform.Rd 2013-07-05 07:59:10 UTC (rev 2501)
+++ pkg/PortfolioAnalytics/man/rp_transform.Rd 2013-07-05 13:34:48 UTC (rev 2502)
@@ -1,9 +1,10 @@
\name{rp_transform}
\alias{rp_transform}
-\title{Transform a weights vector to satisfy leverage, box, and group constraints using logic from \code{randomize_portfolio}}
+\title{Transform a weights vector to satisfy leverage, box, group, and position_limit constraints using logic from \code{randomize_portfolio}}
\usage{
rp_transform(w, min_sum = 0.99, max_sum = 1.01, min, max,
- groups, cLO, cUP, max_permutations = 200)
+ groups, cLO, cUP, max_pos = NULL,
+ max_permutations = 200)
}
\arguments{
\item{w}{weights vector to be transformed}
@@ -28,6 +29,8 @@
\item{cUP}{numeric or vector specifying minimum weight
group constraints}
+ \item{max_pos}{maximum assets with non-zero weights}
+
\item{max_permutations}{integer: maximum number of
iterations to try for a valid portfolio, default 200}
}
@@ -38,9 +41,10 @@
This function uses a block of code from
\code{\link{randomize_portfolio}} to transform the weight
vector if either the weight_sum (leverage) constraints,
- box constraints, or group constraints are violated. The
- resulting weights vector might be quite different from
- the original weights vector.
+ box constraints, group constraints, or position_limit
+ constraints are violated. The resulting weights vector
+ might be quite different from the original weights
+ vector.
}
\author{
Peter Carl, Brian G. Peterson, Ross Bennett (based on an
Modified: pkg/PortfolioAnalytics/sandbox/testing_rp_transform.R
===================================================================
--- pkg/PortfolioAnalytics/sandbox/testing_rp_transform.R 2013-07-05 07:59:10 UTC (rev 2501)
+++ pkg/PortfolioAnalytics/sandbox/testing_rp_transform.R 2013-07-05 13:34:48 UTC (rev 2502)
@@ -17,7 +17,7 @@
group_fail(weights, groups, cLO, cUP)
-w <- rp_transform(weights, min_sum, max_sum, min, max, groups, cLO, cUP, 200)
+w <- rp_transform(weights, min_sum, max_sum, min, max, groups, cLO, cUP, 2, 200)
w
group_fail(w, groups, cLO, cUP)
@@ -42,13 +42,13 @@
group_fail(weights, groups, cLO, cUP)
-# groups is NULL and box and leverage constraints are satisfied so this should
+# groups and max_pos are NULL and box and leverage constraints are satisfied so this should
# just return the original weights vector
-w <- rp_transform(weights, min_sum, max_sum, min, max, groups=NULL, cLO, cUP, 500)
+w <- rp_transform(weights, min_sum, max_sum, min, max, groups=NULL, cLO, cUP, max_pos=NULL, 500)
w
# The first group exceeds cUP so the weights vector should be modified
-w <- rp_transform(weights, min_sum, max_sum, min, max, groups, cLO, cUP, 1000)
+w <- rp_transform(weights, min_sum, max_sum, min, max, groups, cLO, cUP, 4, 1000)
w
group_fail(w, groups, cLO, cUP)
@@ -68,7 +68,7 @@
group_fail(weights, groups, cLO, cUP)
-w <- rp_transform(weights, min_sum, max_sum, min, max, groups, cLO, cUP, 500)
+w <- rp_transform(weights, min_sum, max_sum, min, max, groups, cLO, cUP, 5, 500)
w
group_fail(w, groups, cLO, cUP)
@@ -93,4 +93,5 @@
# Note that this was typically not working with max_permutations=200
# Relax constraints or increase max_permutations
-rp_transform(weights, min_sum, max_sum, min, max, groups, cLO, cUP, 1000)
+w <- rp_transform(weights, min_sum, max_sum, min, max, groups, cLO, cUP, 7, 1000)
+w
More information about the Returnanalytics-commits
mailing list