What is Differential Evolution (DE)?
Differential Evolution is an optimization technique inspired from biology which uses evolution and mutation of candidate solutions to reach global optima (or get close to global optima), over the course of successive generations of solutions. DE does not require the function we seek to optimize to be continuous and so presents an improvement over optimization methods such as gradient-descent. Therefore it is useful for things like portfolio-optimization where real world applications require multiple constraints and the functions to optimize may often be discontinuous and non-linear. The following abstract from this paper by Krink and Paterlini may explain things best:
Realistic portfolio optimization, in contrast to simplistic mean-variance optimization, is a challenging problem, because it requires to determine a set of optimal solutions with respect to multiple objectives, where the objective functions are often multimodal and non-smooth. Moreover, the objectives are subject to various constraints of which many are typically non-linear and discontinuous. Conventional optimization methods, such as quadratic programming, cannot cope with these realistic problem properties. A valuable alternative are stochastic search heuristics, such as simulated annealing or evolutionary algorithms.
Following on from the previous post, where the paper presented found that optimizing the R-ratio results in superior returns as compared to mean-variance optimization, let’s use DE optimization in R to get portfolio weights for an R-ratio optimized portfolio.
What is the Rachev ratio?
Similar to how the Sharpe ratio is a measure of excess return (expected return over the risk-free rate) per unit of risk (standard deviation), the R-ratio is a measure of return (given by the Expected Tail Return) per unit of risk (given by the Expected Tail Loss).
For a 95% confidence level the Expected Tail Return (ETR) is the average of the right 5% of the distribution of returns and the Expected Tail Loss (ETL) is the average of the left 5% of the distribution of returns, over a given period of time. Read this paper for more information on the VaR, which should help you better understand ETL and ETR.
My understanding of the R-ratio is that it is measuring the risk-return characteristic of large gains compared to large losses (alternatively, tail return per unit tail risk).
So with our portfolio, we are seeking to maximize the possibility of large tail returns and minimize the possibility of large tail losses, or maximize the R-ratio if it is positive and minimize it if it’s negative.
R implementation using DE:
Using DE for this is a bit of an overkill, but it’s good practise for when we need to create portfolios with several other constraints. I used code from these excellent slides posted by Guy Yollin on portfolio optimization.
1-First, we need to get and load the DEoptim package
The function DEoptim() requires that you pass it an objective function to minimize, an upper bound for the parameter values and a lower bound for the parameter values which the objective function works with, and which DEoptim() will optimize.
2-Now we need to write the objective function. The code for this I obtained from the slides posted above.
The parameter ‘w’ is the vector of weights which will be optimized. ‘ret’ is the matrix of log returns for each security to be considered in the portfolio. ‘retu’ is the vector of portfolio returns, given the matrix of security returns, ‘ret’, and the weight on each security
The variable ‘obj’ above is a calculation of the Rachev ratio. ‘retu’ has to be converted into a time series again (hence the as.ts() function) as multiplying the individual security returns by portfolio weights to obtain portfolio returns messes up the time series information. The second line of code above checks whether the R-ratio obtained is negative or positive, as DEoptim() will minimize the objective function. If it is positive, the ifelse() turns it negative so that the absolute value of the R-ratio will be maximized when DEoptim() minimizes the objective function.
The first line of code above adds a penalty to the objective function if the sum of the portfolio weights exceeds or falls below 1. The second line adds a penalty if the weight on any single security falls below 3%. Finally, the last line returns the R-ratio with the penalties added.
3-Now all we need to do is call DEoptim() with the right parameters.
The first argument above is the objective function itself, the second argument is a vector specifying the lower bounds for each of the security weights, the third argument is similarly for the upper bounds and the fourth argument is the return matrix of log normal returns for four securities (which I covered in previous posts). We type this in, hit enter, and wait for our solutions to evolve. I ran this eight times and got the following results:
Iteration: 200 bestvalit: -1.085795 bestmemit: 0.580635 0.000007 0.001226 0.418169
Iteration: 200 bestvalit: -1.085815 bestmemit: 0.580927 0.000006 0.000118 0.419206
Iteration: 200 bestvalit: -1.085842 bestmemit: 0.586597 0.000002 0.000003 0.413373
Iteration: 200 bestvalit: -1.085801 bestmemit: 0.584547 0.000038 0.000201 0.415401
Iteration: 200 bestvalit: -1.085830 bestmemit: 0.587022 0.000003 0.000412 0.412491
Iteration: 200 bestvalit: -1.085809 bestmemit: 0.591487 0.000013 0.000058 0.408194
Iteration: 200 bestvalit: -1.085808 bestmemit: 0.587920 0.000012 0.000090 0.411523
Iteration: 200 bestvalit: -1.085827 bestmemit: 0.588024 0.000002 0.000445 0.411674
The weights stay fairly consistent each time the function is run. You can vary the number of iterations in each function call to get even greater consistency. The weights provided are in order of their listing in the returns matrix passed to the DEoptim() function. In the next post, I will compare the performance of this portfolio with that of the minimum-variance portfolio across different time periods. Should be interesting to see how they perform, especially over the 2008 crisis.