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 at 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]]