Building an Efficient Frontier from Forecast Returns and Covariances
Summary
The document explains how to construct a mean-variance efficient frontier when expected returns and asset volatilities are forecasts rather than a historical return series. It emphasizes that asset volatilities alone are insufficient: portfolio risk also depends on correlations, so the forecasts must be combined with an assumed or estimated correlation matrix to form a covariance matrix.
One suggested workflow uses a portfolio optimization function with forecast means and covariance, allowing limits on holdings and an optional risk-free asset. Constant pairwise correlation is offered as a simple assumption to explore, though the answer cautions that valid correlation inputs require care and that their effect depends on the data. The document also notes that direct optimization is easier to extend with constraints, such as long-only holdings, than an analytical frontier formula. An alternative approach customizes the estimator used by an R portfolio package. The examples are implementation suggestions, not evidence that forecast inputs will be accurate.
Key ideas
- Portfolio volatility depends on both individual asset volatilities and return correlations.
- Forecast volatilities and a correlation matrix can be combined to construct a forecast covariance matrix.
- Mean-variance optimization can generate a frontier from forecast returns and covariance inputs.
- Optimization makes it easier to impose portfolio constraints than a closed-form analytical approach.
- Assumed correlations should be treated carefully because arbitrary matrices may be invalid.
Tags
Full text
# Calculating the efficient frontier from expected returns and SD
# Calculating the efficient frontier from expected returns and SD
I'm trying to calculate the efficient frontier (and the optimal portfolio at the Sharpe ratio) given two vectors for a portfolio: (1) expected returns and (2) historical standard deviations. I would like to be able to calculate this in R. Using the `portfolioFrontier()` function of the `fPortfolio` package in R, I have successfully calculated the efficient frontier and optimal portfolio allocation at the Sharpe ratio using a time series of historical returns. However, the `fPortfolio` package only appears to allow back-testing on a time series. I would like to calculate the efficient frontier and optimal portfolio at the Sharpe ratio for future (i.e., expected) returns. How can I do this?
Ideally this would be implemented with a function in R. The closest resource I could find was from this website using Octave code. I successfully translated the code to R, but the efficient frontier doesn't appear to match (or be as accurate) as the one from the R package.
Here's my attempt in R (translating Octave code from the above website):
```
expectedReturns <- c(4, 2, 13, 10)
covarianceMatrix <- matrix(c(185, 86.5, 80, 20, 86.5, 196, 76, 13.5, 80, 76, 411, -19, 20, 13.5, -19, 25), nrow=4, ncol=4, byrow=TRUE)
# Calculate Efficient Frontier
unity <- rep(1, length(expectedReturns))
A <- unity %*% solve(covarianceMatrix) %*% unity
B <- unity %*% solve(covarianceMatrix) %*% expectedReturns
C <- expectedReturns %*% solve(covarianceMatrix) %*% expectedReturns
D <- A*C-B^2
mu = seq(0, 30, by=.1)
minVar = ((A*mu^2)-2*B*mu+C)/D
minSD = sqrt(minVar)
plot(minSD, mu)
```
## Answer by Enrico Schumann (score 3, accepted)
https://quant.stackexchange.com/a/41182
As indicated in my comment, the function `mvFrontier` in the development version of the NMOF package may help you. (Disclosure: I am the package maintainer.) You may get the latest version from GitHub.
Some remarks, first on correlation: an efficient frontier shows portfolio risk, typically volatility, compared with portfolio return. Portfolio volatility is a function of both the volatilities of the assets and the return-correlation between these assets, so you cannot get rid of correlation.
The variance-covariance matrix may be decomposed into the (matrix) product `S` times `C` times `S`, in which `S` is a diagonal matrix with the standard deviations on its main diagonal and zeros elsewhere, and in which `C` is the correlation matrix.
Assume you have the following forecasts:
```
na <- 4 ## number of assets
vols <- c(0.10, 0.15, 0.20, 0.22) ## forecast vols
m <- c(0.06, 0.12, 0.09, 0.07) ## forecast returns
```
Then a covariance matrix for a constant correlation of 0.5 may be computed in this way:
```
const_cor <- function(rho, na) {
C <- array(rho, dim = c(na, na))
diag(C) <- 1
C
}
var <- diag(vols) %*% const_cor(0.5, na) %*% diag(vols)
```
So you may want to experiment with different assumptions about the correlations: it is difficult to come up with valid arbitrary correlation matrices, but what works is constant positive correlation (i.e. all pairwise correlations are 0.1, or 0.2, ...). Depending on the actual data, the correlation may make little difference to the results (see this note, for instance).
Another remark, on matrix derivations (as in the link you provided): I would prefer to tackle the problem as a optimisation problem instead of following some analytical approach. The advantage is that you may want to introduce restrictions (not allow short shales, say), which becomes more difficult with the analytical approach.
So here would be an example for calling `mvFrontier`:
```
library("NMOF")
wmax <- 1 ## maximum holding size
wmin <- 0.0 ## minimum holding size
rf <- 0.02
## without cash
p1 <- mvFrontier(m, var, wmin = wmin, wmax = wmax, n = 50)
## with cash
p2 <- mvFrontier(m, var, wmin = wmin, wmax = wmax, n = 50, rf = rf)
plot(p1$volatility, p1$return, pch = 19, cex = 0.5, type = "o",
xlab = "Expected volatility",
ylab = "Expected return")
lines(p2$volatility, p2$return, col = grey(0.5))
abline(v = 0, h = rf)
```
## Answer by Ajay Verma (score 0)
https://quant.stackexchange.com/a/42412
The same can be achieved for fPortfolio package using SetEstimator. Example below:
```
expectedReturns <- c(4, 2, 13, 10)
covarianceMatrix <- matrix(c(185, 86.5, 80, 20, 86.5, 196, 76, 13.5, 80, 76, 411, -19, 20, 13.5, -19, 25), nrow=4, ncol=4, byrow=TRUE)
covtEstimator <- function (x,data,spec) {
x.mat = as.matrix(x)
list(mu=expectedReturns,Sigma=covarianceMatrix)
}
# Calculate Efficient Frontier
defaultSpec <- portfolioSpec()
setEstimator(defaultSpec) <- 'covtEstimator'
efficientPortfolio(yourreturndata, defaultSpec, constraints = "LongOnly")
```
Additional reference : Page 293 in this pdfShown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.