问题
Every package that I look at seems to require time series returns for my assets.
For example I like the PortfolioAnalytics package, and I require many of the constraints offered (box constraints, group constraints, etc.). However, as far as I can tell it requires some sort of time series of returns, even if I specify my own moments (I could be wrong).
All I have are the expected returns of each of my 14 assets and the covariance matrix.
How can I do various forms of optimizations with that as my starting point? Ultimately I'd like to build a full efficient frontier as well as be able to maximize return at a given level of risk (standard deviation) given my constraints. If I had a time series this wouldn't be a problem...but alas I do not.
Thanks. I feel like this should be quite easy but I've been running in circles.
Worst case scenario is I could build a fake time series that fits the parameters of the E(R) and covariance matrix..if you think this is my solution can you offer me an easy way to do that...but that is why I am here :)
回答1:
How about this?
library(stockPortfolio)
library(quadprog)
library(ggplot2)
stocks <- c("SPY", "EFA", "IWM", "VWO", "LQD", "HYG")
returns <- getReturns(stocks, freq = "week")
eff.frontier <- function (returns,
short = "no",
max.allocation = NULL,
risk.premium.up = .5,
risk.increment = .005) {
covariance <- cov(returns)
print(covariance)
n <- ncol(covariance)
# Create initial Amat and bvec assuming only equality constraint (short-selling is allowed, no allocation constraints)
Amat <- matrix (1, nrow = n)
bvec <- 1
meq <- 1
# Then modify the Amat and bvec if short-selling is prohibited
if (short == "no") {
Amat <- cbind(1, diag(n))
bvec <- c(bvec, rep(0, n))
}
# And modify Amat and bvec if a max allocation (concentration) is specified
if (!is.null(max.allocation)) {
if (max.allocation > 1 | max.allocation < 0) {
stop("max.allocation must be greater than 0 and less than 1")
}
if (max.allocation * n < 1) {
stop("Need to set max.allocation higher; not enough assets to add to 1")
}
Amat <- cbind(Amat, -diag(n))
bvec <- c(bvec, rep(-max.allocation, n))
}
# Calculate the number of loops based on how high to vary the risk premium and by what increment
loops <- risk.premium.up / risk.increment + 1
loop <- 1
# Initialize a matrix to contain allocation and statistics
# This is not necessary, but speeds up processing and uses less memory
eff <- matrix(nrow = loops, ncol = n + 3)
# Now I need to give the matrix column names
colnames(eff) <-
c(colnames(returns), "Std.Dev", "Exp.Return", "sharpe")
# Loop through the quadratic program solver
for (i in seq(from = 0, to = risk.premium.up, by = risk.increment)) {
dvec <-
colMeans(returns) * i # This moves the solution up along the efficient frontier
sol <-
solve.QP(
covariance,
dvec = dvec,
Amat = Amat,
bvec = bvec,
meq = meq
)
eff[loop, "Std.Dev"] <-
sqrt(sum(sol$solution * colSums((
covariance * sol$solution
))))
eff[loop, "Exp.Return"] <-
as.numeric(sol$solution %*% colMeans(returns))
eff[loop, "sharpe"] <-
eff[loop, "Exp.Return"] / eff[loop, "Std.Dev"]
eff[loop, 1:n] <- sol$solution
loop <- loop + 1
}
return(as.data.frame(eff))
}
eff <-
eff.frontier(
returns = returns$R,
short = "yes",
max.allocation = .45,
risk.premium.up = .5,
risk.increment = .001
)
eff.optimal.point <- eff[eff$sharpe == max(eff$sharpe),]
ealred <- "#7D110C"
ealtan <- "#CDC4B6"
eallighttan <- "#F7F6F0"
ealdark <- "#423C30"
ggplot(eff, aes(x = Std.Dev, y = Exp.Return)) + geom_point(alpha = .1, color =
ealdark) +
geom_point(
data = eff.optimal.point,
aes(x = Std.Dev, y = Exp.Return, label = sharpe),
color = ealred,
size = 5
) +
annotate(
geom = "text",
x = eff.optimal.point$Std.Dev,
y = eff.optimal.point$Exp.Return,
label = paste(
"Risk: ",
round(eff.optimal.point$Std.Dev * 100, digits = 3),
"\nReturn: ",
round(eff.optimal.point$Exp.Return * 100, digits =
4),
"%\nSharpe: ",
round(eff.optimal.point$sharpe * 100, digits = 2),
"%",
sep = ""
),
hjust = 0,
vjust = 1.2
) +
ggtitle("Efficient Frontier\nand Optimal Portfolio") + labs(x = "Risk (standard deviation of portfolio variance)", y =
"Return") +
theme(
panel.background = element_rect(fill = eallighttan),
text = element_text(color = ealdark),
plot.title = element_text(size = 24, color = ealred)
)
This should help as well.
https://www.r-bloggers.com/a-gentle-introduction-to-finance-using-r-efficient-frontier-and-capm-part-1/
回答2:
If you want to use a particular package, and that particular package allows only time-series, then yes, the only way for you to use that particular package is to create time-series that match your means and variance-covariance-matrix. (But you might want to check the way the package computes the means/variance-covariance-matrix from these time-series.) See https://stackoverflow.com/questions/58293991 for how to create such series.
For mean-variance optimisation, requiring time-series
(and not providing an alternative, overriding method) would be a
bad design choice on part of a package. (And I find it hard to believe that PortfolioAnalytics
should not offer such a mechanism.) The input for
mean-variance optimisation is a forecast of the means
and a forecast of the variance-covariance matrix. Such
forecasts may be informed by, or based on, historical
data. But even then there are many different
possibilities to compute such quantities,
e.g. shrinkage.
In any case, the NMOF package, which I maintain, has functions minvar
and mvPortfolio
for computing minimum-variance and mean-variance-efficient portfolios based on mean vectors and variance-covariance matrices. In the development of version of NMOF, those function also allow the specification of group constraints.
来源:https://stackoverflow.com/questions/60199112/portfolio-optimize-in-r-with-only-a-vector-of-mean-returns-and-covariance-matrix