I have created some sample code for an optimization problem I am struggling with. The idea is that I have a vector of length 100 which represents various assets. Each asset has a factor associated with it. There is a vector of current assets held and their allocation percentages. Since this is a portion of a greater budget, this allocation sums to some value less than 100%. The objective is to move the assets around such that the allocation (70% in this problem) remains the same and that the target weighted average factor value is reached as close as possible. An additional constraint is that no more than 5 transactions can be made. This means you could reduce one asset and add another, and that would be 2 transactions.
The problem is when I run this optimization, it produces the initial weightings. I suspect it is because as soon as a change is made, the value_constraint is violated. Does anyone have any recommendations for how to approach this problem?
This is the code you can use to run the model, I have included a made up scenario (test case) where two assets are traded for 2 different ones, if it's not helpful for you feel free to ignore it, but this scenario meets both constraints, and with seed(1) produces a worse result.
set.seed(1)
number_of_assets <- 100
max_transactions <- 5
sum_of_assets_value <- 0.70
factors <- runif(number_of_assets, 0, 10)
current_weights <- c(rep(sum_of_assets_value/5, 5), rep(0, number_of_assets-5))
current_factor <- current_weights %*% factors
lower_bound <- -current_weights
upper_bound <- rep(sum_of_assets_value, number_of_assets)
#test model manually with simple scenario
weights <- c(rep(0, 2), rep(sum_of_assets_value/5, 5), rep(0, number_of_assets-7)) #test case for functionality
change_count_constraint <- sum((current_weights^2 - weights^2)^2 > 0) <= max_transactions #constraint should be met with only 4 assets changed
total_value_constraint <- sum(weights) == sum_of_assets_value # constraint is met since weights sum to desired amount
new_factor <- weights %*% factors #new factor from the test case
target_factor <- 1.5 #target factor for testing
difference <- (target_factor - new_factor)^2 #square the difference, since we are attempting to minimize the absolute value of the difference
#end test case
#this is the function for the optimization, includes the two constraints and assigns a penalty if violated
evalFunc <- function(optweights){
new_factor <- optweights %*% factors
count_constraint <- sum((current_weights^2 - optweights^2)^2 > 0) <= max_transactions
value_constraint <- sum(optweights) == sum_of_assets_value
if(count_constraint == FALSE | value_constraint == FALSE){penalty <- 100000}
result <- (target_factor - new_factor)^2 + penalty
result
}
optimization <- optim(current_weights, #starting weights
evalFunc,
lower=lower_bound, upper=upper_bound,
method="L-BFGS-B",
control= list(maxit=5000))