[R-SIG-Finance] Using optimize.portfolio

Roger Bos roger@bo@ @end|ng |rom gm@||@com
Mon Jun 8 13:17:47 CEST 2020


Thank you Brian and Alexios.  In case anyone is interested, here is the
code that produces the exact same results for all five methods:

library(tidyquant)
symbols <-
c("MSFT","AAPL","AMZN","NVDA","CSCO","ADBE","AMGN","ORCL","QCOM","GILD")

getYahooReturns <- function(symbols, return_column = "Ad") {
  returns <- list()
  for (symbol in symbols) {
    getSymbols(symbol, from = '2000-01-01', adjustOHLC = TRUE, env =
.GlobalEnv, auto.assign = TRUE)
    return <- Return.calculate(Ad(get(symbol)))
    colnames(return) <- gsub("\\.Adjusted", "", colnames(return))
    returns[[symbol]] <- return
  }
  returns <- do.call(cbind, returns)
  return(returns)
}

returns <- getYahooReturns(symbols)
returns <- returns[-1, ]
returns[is.na(returns)] <- 0

# portfolio.optim from tseries package
library(tseries)
LB <- rep(0, ncol(returns))
UB <- rep(1, ncol(returns))
popt <- portfolio.optim(x = returns, covmat = sigma, reslow = LB, reshigh =
UB)

library(parma)
# optimal reward to risk (covariance matrix)
parmspec <- parmaspec(S = cov(returns), risk = "EV", forecast =
colMeans(returns), riskType = "minrisk", LB = LB, UB = UB, target =
mean(returns))
parm <- parmasolve(parmspec)

library(PortfolioAnalytics)
simple.moments <- function(R, ...) {
  num_assets = ncol(R)
  out <- list()
  out$mu <- matrix(colMeans(R), ncol = 1)
  out$sigma <- cov(R, use = "pairwise.complete.obs")
  # out$m3 <- PerformanceAnalytics:::M3.MM(R)
  # out$m4 <- PerformanceAnalytics:::M4.MM(R)
  out$m3 <- matrix(0, nrow = num_assets, ncol = num_assets^2)
  out$m4 <- matrix(0, nrow = num_assets, ncol = num_assets^3)
  out
}

num_assets = ncol(returns)
momentargs <- list()
momentargs$mu <- matrix(colMeans(returns), ncol = 1)
momentargs$sigma <- cov(returns, use = "pairwise.complete.obs")
momentargs$m3 <- matrix(0, nrow = num_assets, ncol = num_assets^2)
momentargs$m4 <- matrix(0, nrow = num_assets, ncol = num_assets^3)

pspec <- portfolio.spec(assets = symbols)
pspec <- add.constraint(portfolio=pspec, type = "box", min = 0, max = 1,
min_sum = 0.99, max_sum = 1.01)
pspec <- add.objective(portfolio=pspec, type = "return", name = "mean")
pspec <- add.objective(portfolio=pspec, type = "risk", name = "var")
pspec <- add.constraint(portfolio=pspec, type = "return", return_target =
mean(returns))

opt      <- optimize.portfolio(R = returns, portfolio = pspec,
optimize_method = "ROI")
opt.fun  <- optimize.portfolio(R = returns, portfolio = pspec,
optimize_method = "ROI", momentFUN = "simple.moments")
opt.args <- optimize.portfolio(R = returns, portfolio = pspec,
optimize_method = "ROI", momentargs = momentargs)
data.frame(opt.portf = round(opt$weights, 3),
           opt.portf.fun = round(opt.fun$weights, 3),
           opt.portf.args = round(opt.args$weights, 3),
           portfolio.optim = round(popt$pw, 3),
           parma = round(weights(parm), 3))


On Sun, Jun 7, 2020 at 8:59 PM Brian G. Peterson <brian using braverock.com>
wrote:

> Roger,
>
> If no Return cleaning method is specified, the default portfolio moments
> function will use pairwise complete observations:
>
> cov(tmpR, use = "pairwise.complete.obs")
>
> if you pass momentargs, the internal calculations for mu and sigma will be
> replaced by momentargs$mu and momentargs$sigma
>
> Alexios has already pointed out the return target, which is not specified
> in your objectives for optimize.portfolio.
>
> I also note that you're using DEoptim, which is unecessarily slow (and may
> not always converge to the same result) for a simple mean variance
> optimization.  You probably want optimize.method='ROI', which will use the
> same direct quadratic approach.  DEoptim (or 'random' or 'GEnSA', or 'pso')
> make sense for more complex objectives that aren't amenable to convex
> solvers.
>
> Regards,
>
> Brian
>
>
>
> --
>
> Brian G. Peterson
> ph: +1.773.459.4973
> im: bgpbraverock
>
> On Sun, 2020-06-07 at 20:14 -0400, Roger Bos wrote:
>
> Thank you to everyone for your suggestions, but I am still having trouble.
>
> I see that there are two ways to pass custom moments into optimize
>
> portfolio, a custom function and using momentargs list.  The example code
>
> at the end of this email uses both of those methods, as well as the default
>
> method.  I also compare those to portfolio.optim and parma.
>
>
> I get quite different results for each method.  I know that they will not
>
> be exactly the same, but surely I am doing something wrong given the
>
> results I am getting.  I would hope that all three optimize portfolio
>
> methods would give me the same results.  Here are the results I am getting:
>
>
>              opt.portf opt.portf.fun opt.portf.args portfolio.optim parma
>
> MSFT     0.372         0.190          0.448           0.253 0.000
>
> AAPL     0.008         0.094          0.044           0.208 0.357
>
> AMZN     0.000         0.076          0.000           0.055 0.119
>
> NVDA     0.020         0.000          0.000           0.020 0.169
>
> CSCO     0.000         0.004          0.002           0.000 0.000
>
> ADBE     0.004         0.040          0.002           0.033 0.032
>
> AMGN     0.298         0.348          0.382           0.253 0.000
>
> ORCL     0.068         0.072          0.010           0.002 0.000
>
> QCOM    0.072         0.000          0.000           0.000 0.000
>
> GILD       0.158         0.176          0.112           0.177 0.322
>
>
> opt.portf is optimize.portfolio with internal mu and sigma
>
> opt.portf.fun is optimize.portfolio with mu and sigma provided in momentFUN
>
> opt.portf.args is optimize.portfolio with mu and sigma provided in
>
> momentargs
>
>
> So if optimize portfolio just uses the column means for mu and cov for
>
> sigma, why am I getting different results than when I use a custom function
>
> or pass in the moments?  Obviously I am doing something wrong since I get
>
> different results when using momentFUN and momentargs.  Thanks in advance
>
> for any help, Roger.
>
>
> ###
>
>
> library(tidyquant)
>
> symbols <-
>
> c("MSFT","AAPL","AMZN","NVDA","CSCO","ADBE","AMGN","ORCL","QCOM","GILD")
>
>
> getYahooReturns <- function(symbols, return_column = "Ad") {
>
>   returns <- list()
>
>   for (symbol in symbols) {
>
>     getSymbols(symbol, from = '2000-01-01', adjustOHLC = TRUE, env =
>
> .GlobalEnv, auto.assign = TRUE)
>
>     return <- Return.calculate(Ad(get(symbol)))
>
>     colnames(return) <- gsub("\\.Adjusted", "", colnames(return))
>
>     returns[[symbol]] <- return
>
>   }
>
>   returns <- do.call(cbind, returns)
>
>   return(returns)
>
> }
>
>
> returns <- getYahooReturns(symbols)
>
> returns <- returns[-1, ]
>
> returns[is.na(returns)] <- 0
>
>
> # portfolio.optim from tseries package
>
> library(tseries)
>
> LB <- rep(0, ncol(returns))
>
> UB <- rep(1, ncol(returns))
>
> popt <- portfolio.optim(x = returns, covmat = sigma, reslow = LB, reshigh =
>
> UB)
>
>
> library(parma)
>
> # optimal reward to risk (covariance matrix)
>
> parmspec <- parmaspec(S = cov(returns), risk = "EV", forecast =
>
> colMeans(returns), riskType = "optimal", LB = LB, UB = UB)
>
> parm <- parmasolve(parmspec)
>
>
> library(PortfolioAnalytics)
>
> simple.moments <- function(R, ...) {
>
>   num_assets = ncol(R)
>
>   out <- list()
>
>   out$mu <- matrix(colMeans(R), ncol = 1)
>
>   out$sigma <- cov(R)
>
>   # out$m3 <- PerformanceAnalytics:::M3.MM(R)
>
>   # out$m4 <- PerformanceAnalytics:::M4.MM(R)
>
>   out$m3 <- matrix(0, nrow = num_assets, ncol = num_assets^2)
>
>   out$m4 <- matrix(0, nrow = num_assets, ncol = num_assets^3)
>
>   out
>
> }
>
>
> num_assets = ncol(returns)
>
> momentargs <- list()
>
> momentargs$mu <- matrix(colMeans(returns), ncol = 1)
>
> momentargs$sigma <- cov(returns)
>
> momentargs$m3 <- matrix(0, nrow = num_assets, ncol = num_assets^2)
>
> momentargs$m4 <- matrix(0, nrow = num_assets, ncol = num_assets^3)
>
>
> pspec <- portfolio.spec(assets = symbols)
>
> pspec <- add.constraint(portfolio=pspec, type="box", min = 0, max = 1,
>
> min_sum = 0.99, max_sum = 1.01)
>
> pspec <- add.objective(portfolio=pspec, type="return", name="mean")
>
> pspec <- add.objective(portfolio=pspec, type="risk", name="var")
>
>
> opt      <- optimize.portfolio(R = returns, portfolio = pspec,
>
> optimize_method = "DEoptim")
>
> opt.fun  <- optimize.portfolio(R = returns, portfolio = pspec,
>
> optimize_method = "DEoptim", momentFUN = "simple.moments")
>
> opt.args <- optimize.portfolio(R = returns, portfolio = pspec,
>
> optimize_method = "DEoptim", momentargs = momentargs)
>
> data.frame(opt.portf = opt$weights,
>
>            opt.portf.fun = opt.fun$weights,
>
>            opt.portf.args = opt.args$weights,
>
>            portfolio.optim = round(popt$pw, 3),
>
>            parma = round(weights(parm), 3))
>
>
>
> On Sat, Jun 6, 2020 at 8:38 AM Brian G. Peterson <
>
> brian using braverock.com
>
> >
>
> wrote:
>
>
> On Sat, 2020-06-06 at 14:33 +0200, Enrico Schumann wrote:
>
> On Fri, 05 Jun 2020, Roger Bos writes:
>
>
> All,
>
>
> I am comparing optimize.portfolio from the PortfolioAnalytics
>
> package to
>
> portfolio.optim from the tseries package.  portfolio.optim seems a
>
> bit
>
> easier to use, but I like the set up of optimize.portfolio.  I have
>
> created
>
> a minimal reprex below that compares the output of both in case
>
> that helps
>
> answer my questions.
>
> Here are my two primary questions:
>
>
> 1) What if I wanted to pass a custom covariance matrix to
>
> optimize.portfolio, like from a risk model.  Is that possible?  I
>
> can pass
>
> it to portfolio.optim because covmat is one of the parameters.
>
> 2) What if I wanted to pass forecasted returns to
>
> optimize.portfolio?  How
>
> would that be done.
>
>
> If there is anything that can be improved in this example, that
>
> would be
>
> helpful as well.  Thank you in advance for any assistance, Roger.
>
>
> ###
>
>
> library(PortfolioAnalytics)
>
> library(tidyquant)
>
>
> symbols <-
>
> c("MSFT","AAPL","AMZN","NVDA","CSCO","ADBE","AMGN","ORCL","QCOM","G
>
> ILD")
>
>
> getYahooReturns <- function(symbols, return_column = "Ad") {
>
>   returns <- list()
>
>   for (symbol in symbols) {
>
>     getSymbols(symbol, from = '2000-01-01', adjustOHLC = TRUE, env
>
> =
>
> .GlobalEnv, auto.assign = TRUE)
>
>     return <- Return.calculate(Ad(get(symbol)))
>
>     colnames(return) <- gsub("\\.Adjusted", "", colnames(return))
>
>     returns[[symbol]] <- return
>
>   }
>
>   returns <- do.call(cbind, returns)
>
>   return(returns)
>
> }
>
>
> returns <- getYahooReturns(symbols)
>
> returns <- returns[-1, ]
>
> returns[is.na(returns)] <- 0
>
>
> # portfolio.optim from tseries package
>
> library(tseries)
>
> sigma <- cov(returns)
>
> reslow <- rep(0, ncol(returns))
>
> reshigh <- rep(1, ncol(returns))
>
> popt <- portfolio.optim(x = returns, covmat = sigma, reslow =
>
> reslow,
>
> reshigh = reshigh)
>
> popt$pw
>
>
> pspec <- portfolio.spec(assets = symbols)
>
> pspec <- add.constraint(portfolio=pspec, type="box",
>
>                     min = 0, max = 1, min_sum = 0.99, max_sum =
>
> 1.01)
>
> pspec <- add.objective(portfolio=pspec,
>
>                        type="return",
>
>                        name="mean")
>
> pspec <- add.objective(portfolio=pspec,
>
>                        type="risk",
>
>                        name="var")
>
>
> opt <- optimize.portfolio(R = returns,
>
>                    portfolio = pspec,
>
>                    optimize_method = "DEoptim", )
>
> data.frame(optimize.portfolio = opt$weights, portfolio.optim =
>
> round(popt$pw, 3))
>
>
>
> If all else fails, and supposing that 'PortfolioAnalytics' per
>
> default computes means and covariances in the standard way, you could
>
> create input data (time series) that have exactly the desired
>
> covariances and means:
>
>
>
>
> https://stackoverflow.com/questions/58293991/how-to-use-fportfolio-package-in-r-for-non-time-series-input/58302451#58302451
>
>
>
>
> per default, PortfolioAnalytics uses sample moments as most users would
>
> expect.
>
>
> As I already told the OP, the user may pass mu and sigma and m3 and m4
>
> directly, or may construct custom moment functions to compute the
>
> moments using any method they choose.
>
>
> This is outlined in section 2 of the vignette:
>
>
>
> https://cran.r-project.org/web/packages/PortfolioAnalytics/vignettes/custom_moments_objectives.pdf
>
>
>
>
> and, of course, in the manual.
>
>
>
>
> 	[[alternative HTML version deleted]]
>
>
> _______________________________________________
>
> R-SIG-Finance using r-project.org
>
>  mailing list
>
> https://stat.ethz.ch/mailman/listinfo/r-sig-finance
>
>
> -- Subscriber-posting only. If you want to post, subscribe first.
>
> -- Also note that this is not the r-help list where general R questions should go.
>
>

	[[alternative HTML version deleted]]



More information about the R-SIG-Finance mailing list