[Returnanalytics-commits] r2496 - in pkg/PortfolioAnalytics: . R man sandbox
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Thu Jul 4 00:49:48 CEST 2013
Author: rossbennett34
Date: 2013-07-04 00:49:48 +0200 (Thu, 04 Jul 2013)
New Revision: 2496
Added:
pkg/PortfolioAnalytics/man/group_fail.Rd
pkg/PortfolioAnalytics/sandbox/testing_rp_transform.R
Modified:
pkg/PortfolioAnalytics/NAMESPACE
pkg/PortfolioAnalytics/R/constraint_fn_map.R
pkg/PortfolioAnalytics/man/rp_transform.Rd
Log:
Updating rp_transform to include group constraints. Added testing script and updated documentation.
Modified: pkg/PortfolioAnalytics/NAMESPACE
===================================================================
--- pkg/PortfolioAnalytics/NAMESPACE 2013-07-03 10:42:15 UTC (rev 2495)
+++ pkg/PortfolioAnalytics/NAMESPACE 2013-07-03 22:49:48 UTC (rev 2496)
@@ -27,6 +27,7 @@
export(generatesequence)
export(get.constraints)
export(group_constraint)
+export(group_fail)
export(is.constraint)
export(is.objective)
export(is.portfolio)
Modified: pkg/PortfolioAnalytics/R/constraint_fn_map.R
===================================================================
--- pkg/PortfolioAnalytics/R/constraint_fn_map.R 2013-07-03 10:42:15 UTC (rev 2495)
+++ pkg/PortfolioAnalytics/R/constraint_fn_map.R 2013-07-03 22:49:48 UTC (rev 2496)
@@ -196,11 +196,11 @@
return(weights)
}
-#' Transform a weights vector to min_sum/max_sum leverage and min/max box constraints using logic from randomize_portfolio
+#' Transform a weights vector to satisfy leverage, box, and group 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 or box constraints are violated.
+#' constraints, box constraints, or group constraints are violated.
#' The resulting weights vector might be quite different from the original weights vector.
#'
#' @param w weights vector to be transformed
@@ -208,18 +208,28 @@
#' @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 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_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){
+rp_transform <- function(w, min_sum=0.99, max_sum=1.01, min, max, groups, cLO, cUP, 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
+ # 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
# 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.
+ # 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)))){
+ 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)
@@ -229,8 +239,8 @@
# 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) {
+ # 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) {
permutations = permutations + 1
# check our box constraints on total portfolio weight
# reduce(increase) total portfolio size till you get a match
@@ -240,8 +250,8 @@
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)) {
+ # 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)) {
# randomly permute and increase a random portfolio element
cur_index <- random_index[i]
cur_val <- tmp_w[cur_index]
@@ -256,8 +266,11 @@
}
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)) {
+ # 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)) {
# randomly permute and decrease a random portfolio element
cur_index <- random_index[i]
cur_val <- tmp_w[cur_index]
@@ -294,6 +307,40 @@
return(portfolio)
}
+#' Test if group constraints have been violated
+#'
+#' The function loops through each group and tests if cLO or cUP have been violated
+#' for the given group. This is a helper function for \code{\link{rp_transform}}.
+#'
+#' @param weights weights vector to test
+#' @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
+#' @return logical vector: TRUE if group constraints are violated for a given group
+#' @author Ross Bennett
+#' @export
+group_fail <- function(weights, groups, cLO, cUP){
+ # return FALSE if groups, cLO, or cUP is NULL
+ if(is.null(groups) | is.null(cLO) | is.null(cUP)) return(FALSE)
+
+ n.groups <- length(groups)
+ group_fail <- vector(mode="logical", length=n.groups)
+ k <- 1
+ l <- 0
+ for(i in 1:n.groups){
+ j <- groups[i]
+ tmp.w <- weights[k:(l+j)]
+ grp.min <- cLO[i]
+ grp.max <- cUP[i]
+ # return TRUE if grp.min or grp.max is violated
+ group_fail[i] <- ( sum(tmp.w) < grp.min | sum(tmp.w) > grp.max )
+ k <- k + j
+ l <- k - 1
+ }
+ # returns logical vector of groups. TRUE if either cLO or cUP is violated
+ return(group_fail)
+}
+
# test
# w <- c(0.1, 0.25, 0.3, 0.15, 0.05, 0.15)
# min <- rep(0.1, length(w))
Added: pkg/PortfolioAnalytics/man/group_fail.Rd
===================================================================
--- pkg/PortfolioAnalytics/man/group_fail.Rd (rev 0)
+++ pkg/PortfolioAnalytics/man/group_fail.Rd 2013-07-03 22:49:48 UTC (rev 2496)
@@ -0,0 +1,30 @@
+\name{group_fail}
+\alias{group_fail}
+\title{Test if group constraints have been violated}
+\usage{
+ group_fail(weights, groups, cLO, cUP)
+}
+\arguments{
+ \item{weights}{weights vector to test}
+
+ \item{groups}{vector specifying the groups of the assets}
+
+ \item{cLO}{numeric or vector specifying minimum weight
+ group constraints}
+
+ \item{cUP}{numeric or vector specifying minimum weight
+ group constraints}
+}
+\value{
+ logical vector: TRUE if group constraints are violated
+ for a given group
+}
+\description{
+ The function loops through each group and tests if cLO or
+ cUP have been violated for the given group. This is a
+ helper function for \code{\link{rp_transform}}.
+}
+\author{
+ Ross Bennett
+}
+
Modified: pkg/PortfolioAnalytics/man/rp_transform.Rd
===================================================================
--- pkg/PortfolioAnalytics/man/rp_transform.Rd 2013-07-03 10:42:15 UTC (rev 2495)
+++ pkg/PortfolioAnalytics/man/rp_transform.Rd 2013-07-03 22:49:48 UTC (rev 2496)
@@ -1,9 +1,9 @@
\name{rp_transform}
\alias{rp_transform}
-\title{Transform a weights vector to min_sum/max_sum leverage and min/max box constraints using logic from randomize_portfolio}
+\title{Transform a weights vector to satisfy leverage, box, and group constraints using logic from \code{randomize_portfolio}}
\usage{
rp_transform(w, min_sum = 0.99, max_sum = 1.01, min, max,
- max_permutations = 200)
+ groups, cLO, cUP, max_permutations = 200)
}
\arguments{
\item{w}{weights vector to be transformed}
@@ -20,6 +20,14 @@
\item{max}{numeric or named vector specifying maximum
weight box constraints}
+ \item{groups}{vector specifying the groups of the assets}
+
+ \item{cLO}{numeric or vector specifying minimum weight
+ group constraints}
+
+ \item{cUP}{numeric or vector specifying minimum weight
+ group constraints}
+
\item{max_permutations}{integer: maximum number of
iterations to try for a valid portfolio, default 200}
}
@@ -29,10 +37,10 @@
\description{
This function uses a block of code from
\code{\link{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.
+ 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.
}
\author{
Peter Carl, Brian G. Peterson, Ross Bennett (based on an
Added: pkg/PortfolioAnalytics/sandbox/testing_rp_transform.R
===================================================================
--- pkg/PortfolioAnalytics/sandbox/testing_rp_transform.R (rev 0)
+++ pkg/PortfolioAnalytics/sandbox/testing_rp_transform.R 2013-07-03 22:49:48 UTC (rev 2496)
@@ -0,0 +1,96 @@
+library(PortfolioAnalytics)
+
+# Testing to see how rp_transform handles group constraints
+
+##### EX1 #####
+# first group exceeds cUP
+weights <- c(0.15, 0.35, 0.50)
+sum(weights)
+
+groups <- c(2, 1)
+cLO <- c(0.1, 0.10)
+cUP <- c(0.45, 0.8)
+min_sum <- 0.99
+max_sum <- 1.01
+min <- rep(0.05, length(weights))
+max <- rep(0.65, length(weights))
+
+group_fail(weights, groups, cLO, cUP)
+
+w <- rp_transform(weights, min_sum, max_sum, min, max, groups, cLO, cUP, 200)
+w
+group_fail(w, groups, cLO, cUP)
+
+##### EX2 #####
+# The assets are grouped into 3 groups of 2
+# The sum of the weights for the first group assets must be between 0.05 and 0.35
+# The sum of the weights for the second group of assets must be between 0.10 and 0.45
+# The sum of the weights for the last group of assets must be between 0.05 and 0.25
+
+# first group exceeds cUP
+weights <- c(0.15, 0.30, 0.15, 0.25, 0.05, 0.10)
+sum(weights)
+
+groups <- c(2, 2, 2)
+cLO <- c(0.05, 0.10, 0.05)
+cUP <- c(0.4, 0.45, 0.35)
+min_sum <- 0.99
+max_sum <- 1.01
+min <- rep(0.05, length(weights))
+max <- rep(0.65, length(weights))
+
+
+group_fail(weights, groups, cLO, cUP)
+
+# groups is 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
+
+# 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
+group_fail(w, groups, cLO, cUP)
+
+##### Ex3 #####
+# The second group is below cLO and the third weight is below min
+weights <- c(0.15, 0.25, 0.08, 0.2, 0.22, 0.10)
+sum(weights)
+
+groups <- c(2, 1, 3)
+cLO <- c(0.05, 0.10, 0.05)
+cUP <- c(0.4, 0.45, 0.65)
+min_sum <- 0.99
+max_sum <- 1.01
+min <- rep(0.1, length(weights))
+max <- rep(0.65, length(weights))
+
+
+group_fail(weights, groups, cLO, cUP)
+
+w <- rp_transform(weights, min_sum, max_sum, min, max, groups, cLO, cUP, 500)
+w
+group_fail(w, groups, cLO, cUP)
+
+##### Ex4 #####
+# The second group is above cUP and the fourth group is below cLO
+weights <- c(0.06, 0.1, 0.07, 0.2, 0.22, 0.10, 0.05, 0.08, 0.05, 0.04, 0.03)
+sum(weights[1:2])
+sum(weights[3:6])
+sum(weights[7:10])
+sum(weights[10:11])
+sum(weights)
+
+groups <- c(2, 4, 3, 2)
+cLO <- c(0.05, 0.10, 0.05, 0.08)
+cUP <- c(0.4, 0.55, 0.65, 0.45)
+min_sum <- 0.99
+max_sum <- 1.01
+min <- rep(0.05, length(weights))
+max <- rep(0.65, length(weights))
+
+group_fail(weights, groups, cLO, cUP)
+
+# 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)
More information about the Returnanalytics-commits
mailing list