Archive
The Most Diversified or The Least Correlated Efficient Frontier
The “Minimum Correlation Algorithm” is a term I stumbled at the CSS Analytics blog. This is an Interesting Risk Measure that in my interpretation means: minimizing Average Portfolio Correlation with each Asset Class for a given level of return.
One might try to use Correlation instead of Covariance matrix in mean-variance optimization, but this approach, as I will show below, will not produce the least correlated portfolios.
The Average Portfolio Correlation with each Asset Class:
This formula can be easily coded in R:
portfolio.sigma = sqrt( t(weight) %*% assets.cov %*% weight ) mean( ( weight %*% assets.cov ) / ( assets.sigma * portfolio.sigma ) ) # Alternatively portfolio.returns = weight %*% t(assets.hist.returns) mean(cor(assets.hist.returns, portfolio.returns))
I’m not aware of the method to transform this formula in to the linear programming, so I will use a Nonlinear programming solver, Rdonlp2, which is based on donlp2 routine developed and copyright by Prof. Dr. Peter Spellucci. Following code might not properly execute on your computer because Rdonlp2 is only available for R version 2.9 or below.
#-------------------------------------------------------------------------- # Create Efficient Frontier #-------------------------------------------------------------------------- ia = aa.test.create.ia() n = ia$n # 0 <= x.i <= 0.8 constraints = new.constraints(n, lb = 0, ub = 0.8) # SUM x.i = 1 constraints = add.constraints(rep(1, n), 1, type = '=', constraints) # create efficient frontier(s) ef.risk = portopt(ia, constraints, 50, 'Risk') ef.cor.insteadof.cov = portopt(ia, constraints, 50, 'Cor instead of Cov', min.cor.insteadof.cov.portfolio) ef.avgcor = portopt(ia, constraints, 50, 'AvgCor', min.avgcor.portfolio) # Plot multiple Efficient Frontiers layout(1:2) plot.ef(ia, list(ef.risk, ef.avgcor, ef.cor.insteadof.cov), portfolio.risk, F) plot.ef(ia, list(ef.risk, ef.avgcor, ef.cor.insteadof.cov), portfolio.avgcor, F) # Plot multiple Transition Maps layout( matrix(1:4, nrow = 2) ) plot.transition.map(ef.risk) plot.transition.map(ef.avgcor) plot.transition.map(ef.cor.insteadof.cov) # visualize input assumptions plot.ia(ia)
Using Correlation instead of Covariance matrix in mean-variance optimization is a very bad idea to produce the least correlated portfolios. The ‘Cor instead of Cov’ efficient frontier actually increases average portfolio correlation compared to the standard ‘Risk’ efficient frontier.
The portfolio composition of the Average Correlation efficient frontier is split between gold (GLD) and bonds (TLT) at the lower risk levels. This is not surprising because both gold and bonds have positive expected returns and low correlation to the other assets.
To view the complete source code for this example, please have a look at the aa.avg.cor.test() function in aa.test.r at github.
Following is the complete source code for minimizing Average Portfolio Correlation with each Asset Class function:
min.avgcor.portfolio <- function ( ia, # input assumptions constraints # constraints ) { require(Rdonlp2) cov = ia$cov[1:ia$n, 1:ia$n] s = sqrt(diag(cov)) # avgcor fn <- function(x){ sd_x = sqrt( t(x) %*% cov %*% x ) mean( ( x %*% cov ) / ( s * sd_x ) ) } # control structure cntl <- donlp2.control(silent = T, iterma =10000, nstep = 100, epsx = 1e-10) # lower/upper bounds par.l = constraints$lb par.u = constraints$ub # intial guess p = rep(1,n) if(!is.null(constraints$x0)) p = constraints$x0 # linear constraints A = t(constraints$A) lin.l = constraints$b lin.u = constraints$b lin.u[ -c(1:constraints$meq) ] = +Inf # find solution sol = donlp2(p, fn, par.lower=par.l, par.upper=par.u, A=A, lin.u=lin.u, lin.l=lin.l, control=cntl) x = sol$par return( x ) }
Controlling multiple risk measures during construction of efficient frontier
In the last few posts I introduced Maximum Loss, Mean-Absolute Deviation, and Expected shortfall (CVaR) and Conditional Drawdown at Risk (CDaR) risk measures. These risk measures can be formulated as linear constraints and thus can be combined with each other to control multiple risk measures during construction of efficient frontier.
Let’s examine efficient frontiers computed under different risk measures using historical input assumptions presented in the Introduction to Asset Allocation post:
# load Systematic Investor Toolbox setInternet2(TRUE) source(gzcon(url('https://github.com/systematicinvestor/SIT/raw/master/sit.gz', 'rb'))) #-------------------------------------------------------------------------- # Create Efficient Frontier #-------------------------------------------------------------------------- ia = aa.test.create.ia() n = ia$n # 0 <= x.i <= 0.8 constraints = new.constraints(n, lb = 0, ub = 0.8) # SUM x.i = 1 constraints = add.constraints(rep(1, n), 1, type = '=', constraints) # create efficient frontier(s) ef.risk = portopt(ia, constraints, 50, 'Risk') ef.maxloss = portopt(ia, constraints, 50, 'MaxLoss', min.maxloss.portfolio) # Plot multiple Efficient Frontiers layout( matrix(1:4, nrow = 2) ) plot.ef(ia, list(ef.risk, ef.maxloss), portfolio.risk, F) plot.ef(ia, list(ef.risk, ef.maxloss), portfolio.maxloss, F) plot.transition.map(ef.risk) plot.transition.map(ef.maxloss)
To construct a new mean-variance efficient frontier that only contains portfolios with Max Loss less than 12%
#-------------------------------------------------------------------------- # Add MaxLoss <= 12 constraint #-------------------------------------------------------------------------- constraints = add.constraint.maxloss(ia, 12/100, '<=', constraints) ef.risk.maxloss = portopt(ia, constraints, 50, 'Risk+MaxLoss') ef.risk.maxloss$weight = ef.risk.maxloss$weight[, 1:n] # Plot multiple Efficient Frontiers layout( matrix(1:4, nrow = 2) ) plot.ef(ia, list(ef.risk.maxloss, ef.risk, ef.maxloss), portfolio.risk, F) plot.ef(ia, list(ef.risk.maxloss, ef.risk, ef.maxloss), portfolio.maxloss, F) plot.transition.map(ef.risk) plot.transition.map(ef.risk.maxloss)
The new efficient frontier, labeled ‘Risk+MaxLoss’, is located between ‘Risk’ and ‘MaxLoss’ efficient frontiers in both Risk, measure by Standard Deviation, and Maximum Loss plots. The main difference between original ‘Risk’ and new ‘Risk+MaxLoss’ portfolios can be seen for their Transition Maps. To control Maximum Loss during mean-variance optimization, the ‘Risk+MaxLoss’ portfolios do not have allocation to Emerging Markets (EEM – highlighted with green).
To view the complete source code for this example and other examples, please have a look at the aa.multiple.risk.measures.test() function in aa.test.r at github.
Expected shortfall (CVaR) and Conditional Drawdown at Risk (CDaR) risk measures
In the Maximum Loss and Mean-Absolute Deviation risk measures post I started the discussion about alternative risk measures we can use to construct efficient frontier. Another alternative risk measures I want to discuss are Expected shortfall (CVaR) and Conditional Drawdown at Risk (CDaR). I will use methods presented in Comparative Analysis of Linear Portfolio Rebalancing Strategies: An Application to Hedge Funds by Krokhmal, P., S. Uryasev, and G. Zrazhevsky (2001) and Portfolio Optimization Using Conditional Value-At-Risk and Conditional Drawdown-At-Risk by Enn Kuutanpapers to construct optimal portfolios.
Let x.i, i= 1,…,n be weights of instruments in the portfolio. We suppose that j= 1,…,T scenarios of returns with equal probabilities are available. I will use historical assets returns as scenarios. Let us denote by r.ij the return of i-th asset in the scenario j. The portfolio’s Conditional Value at Risk (CVaR) (page 30-32) can be written as
It can be formulated as a linear programming problem
This linear programming problem can be easily implemented
min.cvar.portfolio <- function ( ia, # input assumptions constraints # constraints ) { n = ia$n nt = nrow(ia$hist.returns) alpha = ia$parameters.alpha # objective : Conditional Value at Risk (CVaR) # E + 1/(1-a) * 1/T * [ SUM w.j ] f.obj = c( rep(0, n), (1/(1-alpha))* (1/nt) * rep(1, nt), 1 ) # adjust constraints, add w.j, E constraints = add.variables(nt + 1, constraints, lb = c(rep(0,nt),-Inf)) # -E - [ SUM <over i> r.ij * x.i ] < w.j, for each j = 1,...,T a = rbind( matrix(0, n, nt), diag(nt), 1) a[1 : n, ] = t(ia$hist.returns) constraints = add.constraints(a, rep(0, nt), '>=', constraints) # setup linear programming f.con = constraints$A f.dir = c(rep('=', constraints$meq), rep('>=', len(constraints$b) - constraints$meq)) f.rhs = constraints$b # find optimal solution x = NA sol = try(solve.LP.bounds('min', f.obj, t(f.con), f.dir, f.rhs, lb = constraints$lb, ub = constraints$ub), TRUE) if(!inherits(sol, 'try-error')) { x = sol$solution[1:n] } return( x ) }
The portfolio’s Conditional Drawdown at Risk (CDaR) (page 32-33) concept is very similar to CVaR. Instead of using portfolio returns to determine shortfall, we use portfolio drawdowns. The Conditional Drawdown at Risk (CDaR) can be written as
It can be formulated as a linear programming problem
min.cdar.portfolio <- function ( ia, # input assumptions constraints # constraints ) { n = ia$n nt = nrow(ia$hist.returns) alpha = ia$parameters.alpha # objective : Conditional Drawdown at Risk (CDaR) # E + 1/(1-a) * 1/T * [ SUM w.j ] f.obj = c( rep(0, n), (1/(1-alpha))* (1/nt) * rep(1, nt), 1, rep(0, nt) ) # adjust constraints, add w.j, E, u.j constraints = add.variables(2*nt + 1, constraints, lb = c(rep(0,nt), rep(-Inf,nt+1))) # u.j - [ SUM <over i> [ SUM <over j> r.ij ] * x.i ] - E < w.j, for each j = 1,...,T a = rbind( matrix(0, n, nt), diag(nt), 1, -diag(nt)) a[1 : n, ] = t(apply( t(ia$hist.returns), 1, cumsum)) constraints = add.constraints(a, rep(0, nt), '>=', constraints) # [ SUM <over i> [ SUM <over j> r.ij ] * x.i ] < u.j, for each j = 1,...,T a = rbind( matrix(0, n, nt), 0*diag(nt), 0, diag(nt)) a[1 : n, ] = -t(apply( t(ia$hist.returns), 1, cumsum)) constraints = add.constraints(a, rep(0, nt), '>=', constraints) # u.j-1 < u.j, for each j = 1,...,T - portfolio high water mark is increasing temp = diag(nt); temp[-nt,-1]=-diag((nt-1)) diag(temp) = 1 a = rbind( matrix(0, n, nt), 0*diag(nt), 0, temp) a = a[,-1] constraints = add.constraints(a, rep(0, (nt-1)), '>=', constraints) # setup linear programming f.con = constraints$A f.dir = c(rep('=', constraints$meq), rep('>=', len(constraints$b) - constraints$meq)) f.rhs = constraints$b # find optimal solution x = NA sol = try(solve.LP.bounds('min', f.obj, t(f.con), f.dir, f.rhs, lb = constraints$lb, ub = constraints$ub), TRUE) if(!inherits(sol, 'try-error')) { x = sol$solution[1:n] } return( x ) }
Let’s examine efficient frontiers computed under different risk measures using historical input assumptions presented in the Introduction to Asset Allocation post:
# load Systematic Investor Toolbox setInternet2(TRUE) source(gzcon(url('https://github.com/systematicinvestor/SIT/raw/master/sit.gz', 'rb'))) #-------------------------------------------------------------------------- # Create Efficient Frontier #-------------------------------------------------------------------------- ia = aa.test.create.ia() n = ia$n # 0 <= x.i <= 0.8 constraints = new.constraints(n, lb = 0, ub = 0.8) # SUM x.i = 1 constraints = add.constraints(rep(1, n), 1, type = '=', constraints) # Alpha for used for CVaR and CDaR # http://www.investopedia.com/articles/04/092904.asp ia$parameters.alpha = 0.95 # create efficient frontier(s) ef.risk = portopt(ia, constraints, 50, 'Risk') ef.cvar = portopt(ia, constraints, 50, 'CVaR', min.cvar.portfolio) ef.cdar = portopt(ia, constraints, 50, 'CDaR', min.cdar.portfolio) # Plot multiple Efficient Frontiers layout( matrix(1:4, nrow = 2) ) plot.ef(ia, list(ef.risk, ef.cvar, ef.cdar), portfolio.risk, F) plot.ef(ia, list(ef.risk, ef.cvar, ef.cdar), portfolio.cvar, F) plot.ef(ia, list(ef.risk, ef.cvar, ef.cdar), portfolio.cdar, F) # Plot multiple Transition Maps layout( matrix(1:4, nrow = 2) ) plot.transition.map(ef.risk) plot.transition.map(ef.cvar) plot.transition.map(ef.cdar)
The efficient frontiers constructed under Expected shortfall (CVaR) and Standard Deviation risk measures look similar. The efficient frontier constructed under Conditional Drawdown at Risk (CDaR) is superior to the other risk measures in controlling drawdowns.
In the next post, I will discuss how to combine multiple risk measures during construction of efficient frontier.
To view the complete source code for this example, please have a look at the aa.cvar.test() function in aa.test.r at github.
Minimum Investment and Number of Assets Portfolio Cardinality Constraints
The Minimum Investment and Number of Assets Portfolio Cardinality Constraints are practical constraints that are not easily incorporated in the standard mean-variance optimization framework. To help us impose these real life constraints, I will introduce extra binary variables and will use mixed binary linear and quadratic programming solvers.
Let’s continue with our discussion from Introduction to Asset Allocation post and examine range of portfolio weights and number of assets for each portfolio on the efficient frontier.
# load Systematic Investor Toolbox setInternet2(TRUE) source(gzcon(url('https://github.com/systematicinvestor/SIT/raw/master/sit.gz', 'rb'))) #-------------------------------------------------------------------------- # Create Efficient Frontier #-------------------------------------------------------------------------- ia = aa.test.create.ia() n = ia$n # 0 <= x.i <= 0.8 constraints = new.constraints(n, lb = 0, ub = 0.8) # SUM x.i = 1 constraints = add.constraints(rep(1, n), 1, type = '=', constraints) # create efficient frontier(s) ef.risk = portopt(ia, constraints, 50, 'Risk') ef.mad = portopt(ia, constraints, 50, 'MAD', min.mad.portfolio) # Plot range of portfolio weights and number of assets in each portfolio on efficient frontier layout(1:2) par(mar = c(4,4,2,1), cex = 0.8) y = iif(ef.risk$weight > 0.000001, ef.risk$weight, NA) plot(as.vector(sort(100 * y)), pch=20, xaxt='n', ylim = c(0, 80), xlab='', ylab='Weight', main='Portfolio Weights') abline(h=0, col = 'red') abline(h=10, col = 'red') plot(100* ef.risk$risk, rowSums(!is.na(y), na.rm = T), pch=20, type='b', xlab='Risk', ylab='# Assets', main='Number of Assets') # Plot multiple Efficient Frontiers & Transition Maps layout( matrix(1:4, nrow = 2) ) plot.ef(ia, list(ef.risk, ef.mad), portfolio.risk, F) plot.ef(ia, list(ef.risk, ef.mad), portfolio.mad, F) plot.transition.map(ef.risk) plot.transition.map(ef.mad)
The portfolio weights range from 0% to 80%, and the number of assets range from 2 to 4 assets. First, let’s consider a minimum investment constraint. Suppose that if I decide to allocate to an asset class, I want to allocate at least 10%. This statement can be incorporated as a constraint using binary [0/1] variables:
#-------------------------------------------------------------------------- # Minimum Investment Constraint is 10% # Add binary[0/1] variables # 0.1 * b.i <= x.i <= 0.8 * b.i #-------------------------------------------------------------------------- # SUM x.i = 1 constraints = new.constraints(n, rep(1, n), 1, type = '=') # New add binary constraint # adjust prior constraints: add b.i constraints = add.variables(n, constraints) # index of binary variables b.i constraints$binary.index = (n+1):(2*n) # 0.1 * b <= x.i <= 0.8 * b # x.i >= 0.1 * b constraints = add.constraints(rbind(diag(n), -0.1 * diag(n)), rep(0, n), type = '>=', constraints) # x.i <= 0.8 * b constraints = add.constraints(rbind(diag(n), -0.8 * diag(n)), rep(0, n), type = '<=', constraints) # create efficient frontier(s) ef.risk = portopt(ia, constraints, 50, 'Risk') ef.risk$weight = ef.risk$weight[, 1:n] ef.mad = portopt(ia, constraints, 50, 'MAD', min.mad.portfolio) ef.mad$weight = ef.mad$weight[, 1:n]
As expected, the portfolio weights range from 10% to 80%, and there is no allocation less than 10%.
To tackle number of assets constraint, I will also use binary [0/1] variables. Let’s say I want all portfolios on the efficient frontier to have allocation to exactly 3 assets, here are the additional constraints (note that for this example, I assumed that the smallest allocation to any asset class is 0.001%) :
#-------------------------------------------------------------------------- # Limit number of assets to 3 # Add binary[0/1] variables # 0.00001 * b <= x.i <= 0.8 * b # SUM b.i = 3 #-------------------------------------------------------------------------- # SUM x.i = 1 constraints = new.constraints(n, rep(1, n), 1, type = '=') # New add binary constraint # adjust prior constraints: add b.i constraints = add.variables(n, constraints) # index of binary variables b.i constraints$binary.index = (n+1):(2*n) # 0.00001 * b <= x.i <= 0.8 * b # x.i >= 0.00001 * b constraints = add.constraints(rbind(diag(n), -0.00001 * diag(n)), rep(0, n), type = '>=', constraints) # x.i <= 0.8 * b constraints = add.constraints(rbind(diag(n), -0.8 * diag(n)), rep(0, n), type = '<=', constraints) # SUM b.i = 3 constraints = add.constraints(c(rep(0,n), rep(1,n)), 3, type = '=', constraints) # create efficient frontier(s) ef.risk = portopt(ia, constraints, 50, 'Risk') ef.risk$weight = ef.risk$weight[, 1:n] ef.mad = portopt(ia, constraints, 50, 'MAD', min.mad.portfolio) ef.mad$weight = ef.mad$weight[, 1:n]
As expected, all portfolios on the efficient frontier have exactly allocation to 3 assets.
Please let me know what other real-life portfolio construction constraints you want me to discuss.
To view the complete source code for this example, please have a look at the aa.cardinality.test() function in aa.test.r at github.
130/30 Portfolio Construction
The 130/30 funds were getting lots of attention a few years ago. The 130/30 fund is a long/short portfolio that for each $100 dollars invested allocates $130 dollars to longs and $30 dollars to shorts. From portfolio construction perspective this simple idea is no so simple to implement.
Let’s continue with our discussion from Introduction to Asset Allocation post and examine effects of allowing short positions on efficient frontier.
# load Systematic Investor Toolbox setInternet2(TRUE) source(gzcon(url('https://github.com/systematicinvestor/SIT/raw/master/sit.gz', 'rb'))) #-------------------------------------------------------------------------- # Create Efficient Frontier #-------------------------------------------------------------------------- ia = aa.test.create.ia() n = ia$n # -0.5 <= x.i <= 0.8 constraints = new.constraints(n, lb = -0.5, ub = 0.8) # SUM x.i = 1 constraints = add.constraints(rep(1, n), 1, type = '=', constraints) # create efficient frontier(s) ef.risk = portopt(ia, constraints, 50, 'Risk') ef.mad = portopt(ia, constraints, 50, 'MAD', min.mad.portfolio) # Plot multiple Efficient Frontiers & Transition Maps layout( matrix(1:4, nrow = 2) ) plot.ef(ia, list(ef.risk, ef.mad), portfolio.risk, F) plot.ef(ia, list(ef.risk, ef.mad), portfolio.mad, F) plot.transition.map(ef.risk) plot.transition.map(ef.mad)
Looking at the Transition Maps, the use of leverage increases as the portfolio’s risk and return increase. At the lower risk, the optimizer wants to allocate 150% to longs and 50% to shorts, and at the higher risk the optimizer wants to allocate 300% to longs and 200% to shorts.
This is a good starting point, but for our purposes we want all portfolios on the efficient frontier to have 130% allocation to longs and 30% allocation to shorts. One solution to this problem was mentioned in Asset Allocation and Risk Assessment with Gross Exposure Constraints for Vast Portfolios by J. Fan, Zhang J., Yu K. (2008) ( Note 3 on Page 8 )
The first method to construct 130/30 portfolio is to note that
If inequality constraints are bounding than and total portfolio weight is equal to 1.6 (1.3 contribution from long allocation and 0.3 contribution from short allocation)
#-------------------------------------------------------------------------- # Create 130:30 # -v.i <= x.i <= v.i, v.i>0, SUM(v.i) = 1.6 #-------------------------------------------------------------------------- # -0.5 <= x.i <= 0.8 constraints = new.constraints(n, lb = -0.5, ub = 0.8) # SUM x.i = 1 constraints = add.constraints(rep(1, n), 1, type = '=', constraints) # adjust prior constraints, add v.i constraints = add.variables(n, constraints) # -v.i <= x.i <= v.i # x.i + v.i >= 0 constraints = add.constraints(rbind(diag(n), diag(n)), rep(0, n), type = '>=', constraints) # x.i - v.i <= 0 constraints = add.constraints(rbind(diag(n), -diag(n)), rep(0, n), type = '<=', constraints) # SUM(v.i) = 1.6 constraints = add.constraints(c(rep(0, n), rep(1, n)), 1.6, type = '=', constraints) # create efficient frontier(s) ef.risk = portopt(ia, constraints, 50, 'Risk') # keep only portfolio weights ef.risk$weight = ef.risk$weight[,(1:n)] ef.mad = portopt(ia, constraints, 50, 'MAD', min.mad.portfolio) ef.mad$weight = ef.mad$weight[,(1:n)] # Plot multiple Efficient Frontiers & Transition Maps layout( matrix(1:4, nrow = 2) ) plot.ef(ia, list(ef.risk, ef.mad), portfolio.risk, F) plot.ef(ia, list(ef.risk, ef.mad), portfolio.mad, F) plot.transition.map(ef.risk) plot.transition.map(ef.mad)
Looking at the Transition Maps, the use of leverage is constant for all portfolios on the efficient frontier at 130% allocation to longs and 30% allocation to shorts.
Another method to construct 130/30 portfolio is to split
and add constraint. If
are mutually exclusive (only one of them is greater then 0 for each i) than total portfolio weight is equal to 1.6 (1.3 contribution from long allocation and 0.3 contribution from short allocation)
#-------------------------------------------------------------------------- # Create 130:30 # Split x into x.long and x.short, x.long and x.short >= 0 # SUM(x.long) - SUM(x.short) = 1.6 #-------------------------------------------------------------------------- # Split Input Assumptions for x into x.long and x.short ia.ls = aa.test.ia.add.short(ia) # x.long and x.short >= 0 # x.long <= 0.8 # x.short <= 0.5 constraints = new.constraints(2*n, lb = 0, ub = c(rep(0.8,n),rep(0.5,n))) # SUM (x.long - x.short) = 1 constraints = add.constraints(c(rep(1,n), -rep(1,n)), 1, type = '=', constraints) # SUM (x.long + x.short) = 1.6 constraints = add.constraints(c(rep(1,n), rep(1,n)), 1.6, type = '=', constraints) # create efficient frontier(s) ef.risk = portopt(ia.ls, constraints, 50, 'Risk') # compute x ef.risk$weight = ef.risk$weight[, 1:n] - ef.risk$weight[, (n+1):(2*n)] ef.mad = portopt(ia.ls, constraints, 50, 'MAD', min.mad.portfolio) ef.mad$weight = ef.mad$weight[, 1:n] - ef.mad$weight[, (n+1):(2*n)] # Plot multiple Efficient Frontiers & Transition Maps layout( matrix(1:4, nrow = 2) ) plot.ef(ia, list(ef.risk, ef.mad), portfolio.risk, F) plot.ef(ia, list(ef.risk, ef.mad), portfolio.mad, F) plot.transition.map(ef.risk) plot.transition.map(ef.mad)
Looking at the Transition Maps, the use of leverage is constant for all portfolios on the efficient frontier at 130% allocation to longs and 30% allocation to shorts.
However, it is important to note that above two methods only work when there is sufficient volatility in the covariance matrix and optimizer uses additional leverage to generate optimal portfolios. To demonstrate this point, let’s imagine we want to construct 200/100 portfolio : 200% allocation to longs and 100% allocation to shorts. The only change required to create a new efficient frontier is to substitute 1.6 constraint above with 3 ( 3 = 200% allocation to longs plus 100% allocation to shorts)
Looking at the Transition Maps, in this scenario the optimizer does not use all the leverage at the lower risk region because optimal portfolios exist at the lower leverage levels. If we look at the at the lower risk region, they are not mutually exclusive, both
are grater than 0.
To enforce that be mutually exclusive (only one of them is greater then 0 for each i), I will add binary variables. Binary variables
can only take 0 or 1 values. Here is the additional constraint:
#-------------------------------------------------------------------------- # Create 200:100 using binary[0/1] variables and Branch and Bound algorithm # Split x into x.long and x.short, x.long and x.short >= 0 # SUM(x.long) - SUM(x.short) = 3 # # Solve using branch and bound: add a binary var b.i, x.long.i < b.i, x.short.i < (1-b.i) #-------------------------------------------------------------------------- # x.long and x.short >= 0 # x.long <= 0.8 # x.short <= 0.5 constraints = new.constraints(2*n, lb = 0, ub = c(rep(0.8,n),rep(0.5,n))) # SUM (x.long - x.short) = 1 constraints = add.constraints(c(rep(1,n), -rep(1,n)), 1, type = '=', constraints) # SUM (x.long + x.short) = 3 constraints = add.constraints(c(rep(1,n), rep(1,n)), 3, type = '=', constraints) # NEW add binary constraint # adjust prior constraints: add b.i constraints = add.variables(n, constraints) # index of binary variables b.i constraints$binary.index = (2*n+1):(3*n) # binary variable b.i, x.long.i < b.i, x.short.i < (1-b.i) # x.long.i < b.i constraints = add.constraints(rbind(diag(n), 0*diag(n), -diag(n)), rep(0, n), type = '<=', constraints) # x.short.i < (1-b.i) constraints = add.constraints(rbind(0*diag(n), diag(n), diag(n)), rep(1, n), type = '<=', constraints) # create efficient frontier(s) ef.risk = portopt(ia.ls, constraints, 50, 'Risk') # compute x ef.risk$weight = ef.risk$weight[, 1:n] - ef.risk$weight[, (n+1):(2*n)] ef.mad = portopt(ia.ls, constraints, 50, 'MAD', min.mad.portfolio) ef.mad$weight = ef.mad$weight[, 1:n] - ef.mad$weight[, (n+1):(2*n)] # Plot multiple Efficient Frontiers & Transition Maps layout( matrix(1:4, nrow = 2) ) plot.ef(ia, list(ef.risk, ef.mad), portfolio.risk, F) plot.ef(ia, list(ef.risk, ef.mad), portfolio.mad, F) plot.transition.map(ef.risk) plot.transition.map(ef.mad)
Finally, looking at the Transition Maps, the use of leverage is constant for all portfolios on efficient frontier at 200% allocation to longs and 100% allocation to shorts.
A technical note about binary variable. The linear solver from lpSolve library implements binary variables internally. The quadratic solver from quadprog library does not handle binary variables. To add binary variables to quadratic solver I adapted binary branch and bound algorithm from Matlab function for solving Mixed Integer Quadratic Programs by Alberto Bemporad, Domenico Mignone
To view the complete source code for this example, please have a look at the aa.long.short.test() function in aa.test.r at github.