I'm researching a way to speed up a problem I already have in Excel's Solver.
I wanna know if my approach is correct (I doubt it tbh) and if there're better alternatives.
I have a matrix of scores I have already calculated through means non relevant to this topic and I want to maximize the lagged correlation of the weighted sum of these scores with the return of a certain asset.
The restrictions are simple:
- Weights have to be greater than 0
- Weights have to be smaller than 1
- Weights have to sum 1
I'm having issues with the last one and have read other posts regarding the issue. However their preferred solution seems to be to rebalance the optim output such that the weights sum 1. I do not believe that would work in my case (I could be wrong).
Reproducible example:
library(tidyr)
library(dplyr)
set.seed(42)
days <- 500
cols <- 5
lag_score <- 30*3
corr_window <- 30*6
scores <- matrix(runif(days*cols), nrow = days, ncol = cols)
colnames(scores) <- c("Momentum","Growth","Quality","Value","Volatility")
returns <- rnorm(days,mean = 0,sd = 0.05)
#General procedure
weights <- rep(0.2,cols)
f_score <- scores %*% weights
x <- f_score[lag_score:(lag_score+corr_window-1)]
y <- returns[1:corr_window]
#What I want to maximize
correl <- cor(x,y)
My attempt so far is the following:
#Function to maximize
cor.model <- function(w=rep(0.2,5),
sc=scores,
ret=returns,
lag_sc=lag_score,
corr_w=corr_window){
f_score <- sc %*% (w/sum(w))
x <- f_score[lag_sc:(lag_sc+corr_w-1)]
y <- ret[1:corr_w]
correl <- cor(x,y)
return(correl)
}
#Output
out <- optim(par = rep(1/cols,cols),
fn = cor.model,
method = "L-BFGS-B",
lower = rep(0,cols), # W_i >= 0 for all i
upper = rep(1,cols), # W_i <= 1 for all i)
control = list(fnscale = -1),
sc=scores,
ret=returns,
lag_sc=lag_score,
corr_w=corr_window)
Alternative with nloptr
:
library(nloptr)
optres <- nloptr(x0 = rep(1/cols,cols),
eval_f = cor.model.min,
lb = rep(0,cols),
ub = rep(1,cols),
opts = list('algorithm' = "NLOPT_LN_BOBYQA",
'print_level' = 2,
'maxeval' = 10000,
'xtol_rel' = 0),
sc=scores,
ret=returns,
lag_sc=lag_score,
corr_w=corr_window)
cor.model.min
is cor.model
with a negative result. (-correl
)
According to other posts my answer should be out$par/sum(out$par)
or optres$solution/sum(optres$solution)
depending on the approach. Is this correct?
The problem in my head is the following:
(C being correlation and not complex)
s.t.
The restrictions stated above.
Where Score is the matrix multiplication of the scores matrix and the weights vector and Ret is the returns vector.