2
$\begingroup$

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:

general (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.

$\endgroup$
2
$\begingroup$

Yes. The final vector of weights is, as you stated: out$par/sum(out$par)

Also, do you realize that optim minimizes by default? Because your code comment says you want to maximize correlation. You can flip it around by doing return(-correl) in your function.

$\endgroup$
  • $\begingroup$ Why the double normalization and could you please explain why rebalancing works even if the operation is non linear? $\endgroup$ – GonzaloXavier Jan 2 '19 at 19:34
  • 1
    $\begingroup$ you're not really doing it twice... having the normalization in the function just ensures that whatever is fed in for weights gets pushed into a conforming vector. But the optimizer does not have the information that it's getting normalized. So it returns what was passed to the function. As for "why", I don't think what you are optimizing is non-linear. Your second example uses a nonlinear optimizer, but I think the problem here is linear. $\endgroup$ – JD Long Jan 2 '19 at 19:40
  • $\begingroup$ As of the double normalization I meant Line 1 and 2 of the function, inside f_score there's already a w/sum(w). In my head doing a correlation function turns what would be linear into non-linear because of the variance and covariances. In my optim example I'm using a negative fnscale so that it maximizes instead of minizing. Thanks for your input! $\endgroup$ – GonzaloXavier Jan 2 '19 at 19:56
  • $\begingroup$ oops.. that's me not paying attention. Um, sorry. you're totally right, it normalized twice :) You were doing it right all along $\endgroup$ – JD Long Jan 2 '19 at 20:36
  • $\begingroup$ I altered my answer because it might be confusing to someone later in its prior form with my lack of attention to detail :) $\endgroup$ – JD Long Jan 3 '19 at 13:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.