Using optimize.portfolio
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 at 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 at 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 at 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 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:
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:
and, of course, in the manual.
[[alternative HTML version deleted]]
_______________________________________________ R-SIG-Finance at 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 at 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.