[R-SIG-Finance] Using optimize.portfolio

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


Vivek,

Originally, I used sigma <- cov(returns), but then I changed it to sigma <-
cov(returns, use = "pairwise.complete.obs") per Brian's suggestion.

Thanks,

Roger


On Mon, Jun 8, 2020 at 10:53 AM Vivek Rao <vivekrao4 using yahoo.com> wrote:

> Thanks for posting your code. When I try to run it I get the error
>
> Error in portfolio.optim.default(x = returns, covmat = sigma, reslow =
> LB,  :
>   covmat is not a matrix
> Calls: portfolio.optim -> portfolio.optim.default
> Execution halted
>
> Could you post to the group the code that computes sigma? Thanks.
>
> Vivek Rao
> Boston, MA
>
>
> On Monday, June 8, 2020, 07:18:37 AM EDT, Roger Bos <roger.bos using gmail.com>
> wrote:
>
>
>
>
>
> 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]]
>
> _______________________________________________
> 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