Thomas
Thomas

Reputation: 23

Optimization code in R, am I missing something?

I'm trying to optimize the parameters of a simple strategy as the code below by maximizing the sharpe ratio. The output results are clearly wrong. Can you please provide some help?

library(xts)
library(zoo)
library(quantmod)
library(PerformanceAnalytics)
library(TTR)

f_opt <- function(x, data){

a <- x[1]
b <- x[2]

sma <- SMA(Cl(data), n = a)
fma <- EMA(Cl(data), n = b)
signal <- Lag(ifelse(sma < fma, 1, -1))
ret <- Return.calculate(data, method = "discrete") * signal
colnames(ret) <- c("MA Strategy")
ret <- na.omit(ret)

sharpe <- SharpeRatio.annualized(ret, Rf = 0, scale = 252) * -1
return(as.numeric(sharpe))

}

SYMBL <- getSymbols("^GSPC", auto.assign=F, from="2011-01-01", to="2021-02-08") 
data <- na.omit(SYMBL[,4])

optim(par = c(1,1), fn = f_opt, data = data, method = "L-BFGS-B", lower = 1, upper = 200)

OUTPUT

[1] 1.869527 1.000000

$value [1] -0.6721263

$counts function gradient 7 7

$convergence [1] 0

$message [1] "CONVERGENCE: NORM OF PROJECTED GRADIENT <= PGTOL"

Upvotes: 1

Views: 293

Answers (1)

Ben Bolker
Ben Bolker

Reputation: 226057

optim() and related methods can find optima of smooth surfaces. With only two parameters it's easy enough to compute the objective function over a surface by brute force (I use functions from the emdbook and plot3D packages for convenience, but you could easily do this with for() loops and the built-in persp() function ...) (code below)

extremely rough objective function surface

I know nothing about your subject area (finance?) or what's going on under the hood in the objective function, but it's not at all surprising that the optimization didn't work.

I was concerned that maybe the problem was with non-integer values of the parameters (which would present a problem for optim() in any case, but might suggest other approaches), but even restricting to integer values in the range (5-20, 180-200) we still get a rough-looking surface:

another rough surface

I have found the DEoptim (optimization by differential evolution) function useful for problems like this.

d1 <- DEoptim(f_opt, data=data,lower=c(1,1),upper=c(200,200))
## $optim
## $optim$bestmem
##      par1      par2 
##  12.87796 190.91548 
## 
## $optim$bestval
## [1] -1.158693
library(emdbook)
## this step takes a while
system.time(
    cc <- curve3d(f_opt(c(x,y), data=data),
                  from=c(1,1),to=c(200,200),
                  n=61,
                  sys3d="none",
                  .progress="text")
)

## Cairo::Cairo(file="plot3d.png")

library(plot3D)
with(cc,persp3D(x=replicate(61,x),
               y=t(replicate(61,y)),
               z,
               border="black")
     )

## dev.off()


cc2 <- curve3d(f_opt(c(x,y), data=data),
               from=c(5,180),to=c(20,200),
               n=c(16,21),
               sys3d="none",
               .progress="text")

## Cairo::Cairo(file="plot3dB.png",width=1280,height=960)
with(cc2,persp3D(x=replicate(21,x),
                y=t(replicate(16,y)),
                cc2$z,
                border="black"))
## dev.off()

Upvotes: 3

Related Questions