# 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)

• Maybe this could help you: quant.stackexchange.com/questions/21464/… – PrinzvonK Aug 7 '18 at 1:08
• You say you want to input only standard deviations; but what about correlations? – Enrico Schumann Aug 7 '18 at 5:45
• Perhaps the function mvFrontier, in the devel version of package NMOF, does what you want: github.com/enricoschumann/NMOF/blob/master/R/… As for inputs, m are the expected returns and var is the covariance matrix. – Enrico Schumann Aug 7 '18 at 5:48
• Is a covariance matrix necessary? If so, I wouldn't be able to produce good estimates of expected covariances apart from using historical ones. But if it's necessary, feel free to provide a solution that has the following inputs: 1) vector of expected returns, and 2) a covariance matrix (which subsumes the vector of variances). Thanks! – itpetersen Aug 7 '18 at 13:57
• I do not think there is anything wrong with your code, it uses the well known formulas for A, B, C, D, etc that are in every textbook, as well as in the link you posted. Why do you say that the results are not accurate? – Alex C Aug 10 '18 at 6:39

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)


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 pdf