Computes the optimal portfolio allocation using the Enhanced Portfolio Optimization (EPO) method of Pedersen, Babu, and Levine (2021).
Usage
epo(
x,
signal,
lambda,
method = c("simple", "anchored"),
w,
anchor = NULL,
normalize = TRUE,
endogenous = TRUE
)
# Default S3 method
epo(
x,
signal,
lambda,
method = c("simple", "anchored"),
w,
anchor = NULL,
normalize = TRUE,
endogenous = TRUE
)
# S3 method for class 'tbl'
epo(
x,
signal,
lambda,
method = c("simple", "anchored"),
w,
anchor = NULL,
normalize = TRUE,
endogenous = TRUE
)
# S3 method for class 'xts'
epo(
x,
signal,
lambda,
method = c("simple", "anchored"),
w,
anchor = NULL,
normalize = TRUE,
endogenous = TRUE
)
# S3 method for class 'matrix'
epo(
x,
signal,
lambda,
method = c("simple", "anchored"),
w,
anchor = NULL,
normalize = TRUE,
endogenous = TRUE
)Arguments
- x
A data-set with asset returns. It should be a
tibble, axtsor amatrix.- signal
A
doublevector with the investor's beliefs about expected returns (signals, forecasts) for each asset inx.- lambda
A
doublewith the investor's (absolute) risk-aversion coefficient, as in the paper's notation. Formethod = "simple", the resulting portfolio's Sharpe ratio does not depend onlambda, so any positive value works whennormalize = TRUE. Formethod = "anchored"withendogenous = TRUE, this argument is ignored because the risk-aversion coefficient is calibrated internally.- method
A
character. One of:"simple"or"anchored".- w
A
doublebetween0and1. The EPO shrinkage parameter:0yields standard mean-variance optimization (no shrinkage) and1yields maximum shrinkage (the anchor portfolio, formethod = "anchored", or an unoptimized portfolio, formethod = "simple"). In practice,wis often chosen empirically, e.g. by picking the value that would have maximized the realized Sharpe ratio using only past (out-of-sample) data.- anchor
A
doublevector with the anchor (benchmark) portfolio that the allocation should not deviate too much from (e.g. a strategic asset allocation, a market-cap benchmark, or the 1/N portfolio). Only used whenmethod = "anchored".- normalize
A
booleanindicating whether the allocation should be normalized to sum1(full-investment constraint). The default isnormalize = TRUE.- endogenous
A
booleanindicating whether the risk-aversion parameter should be calibrated endogenously from theanchorandsignal(paper's footnote 13), rather than taken fromlambda. Only used whenmethod = "anchored". The default isendogenous = TRUE.
Details
Standard mean-variance optimization (MVO) is highly sensitive to
estimation error in the correlation matrix and in expected returns. This
error is concentrated in the least important principal components of the
correlation matrix (the "problem portfolios"), whose risk tends to be
underestimated and whose expected return tends to be overestimated. EPO
fixes this by shrinking the off-diagonal correlations toward zero by a
factor w before running MVO, which increases the estimated volatility
(and lowers the implied Sharpe ratio) of exactly the problem portfolios.
Two flavors of EPO are implemented, both governed by a single shrinkage
parameter, w, between 0 (no shrinkage, i.e. standard MVO) and 1
(maximum shrinkage):
method = "simple"implements the "Simple EPO" (paper's equation 16). The allocation is given by \(x = \frac{1}{\lambda} \Sigma_w^{-1} s\), where \(\Sigma_w\) is the variance-covariance matrix rebuilt from the shrunk correlation matrix \(\Omega_w = (1 - w) \Omega + w I\). Atw = 1all correlations are set to zero, which is equivalent (up to scaling) to not optimizing at all.method = "anchored"implements the "Anchored EPO" (paper's equation 17), which pulls the solution toward a reference/benchmark portfolio, theanchor. Atw = 0the solution is standard MVO; atw = 1the solution collapses onto theanchor; values in between produce Black-Litterman-style portfolios in whichwcontrols the confidence placed in the anchor relative to thesignal. Unlike Black-Litterman, the anchor need not be the market portfolio.
References
Pedersen, L. H., Babu, A., and Levine, A. (2021). Enhanced Portfolio Optimization. Financial Analysts Journal, 77(2), 124-151. doi:10.1080/0015198X.2020.1854543
Examples
x <- diff(log(EuStockMarkets)) # stock returns
s <- colMeans(x) # it could be any signal
##################
### Simple EPO ###
##################
# Traditional Mean-Variance Analysis
epo(x = x, signal = s, lambda = 10, method = "simple", w = 0)
#> [1] 0.1914569 0.9894828 -0.3681779 0.1872382
# 100% Shrinkage
epo(x = x, signal = s, lambda = 10, method = "simple", w = 1)
#> [1] 0.2352863 0.3659986 0.1375249 0.2611902
# 50% Classical MVO and 50% Shrinkage
epo(x = x, signal = s, lambda = 10, method = "simple", w = 0.5)
#> [1] 0.223281853 0.564005906 -0.009868083 0.222580324
####################
### Anchored EPO ###
####################
benchmark <- rep(0.25, 4) # 1/N Portfolio
# Traditional Mean-Variance Analysis
epo(x = x, signal = s, lambda = 10, method = "anchored", w = 0.0, anchor = benchmark)
#> [1] 0.1914569 0.9894828 -0.3681779 0.1872382
# 100% on the Anchor portfolio
epo(x = x, signal = s, lambda = 10, method = "anchored", w = 1.0, anchor = benchmark)
#> [1] 0.25 0.25 0.25 0.25
# Somewhere between the two worlds
epo(x = x, signal = s, lambda = 10, method = "anchored", w = 0.5, anchor = benchmark)
#> [1] 0.2374674 0.4557503 0.1004711 0.2063111