Trading strategy optimization is an important aspect and a challenging problem in algorithmic trading. It requires determining a set of optimal solutions with respect to multiple objectives, where the objective functions are often multimodal, non-convex, and non-smooth. Moreover, the objective functions are subject to various constraints of which many are typically non-linear and discontinuous. Conventional methods, such as Nelder-Mead, BFGS, cannot cope with these realistic problem settings. A solution is the stochastic search heuristic called differential evolution. In this blog piece, I will look at the performance issue of applying differential evolution in optimizing a quantitative trading strategy.
Briefly, differential evolution (DE) is a genetic algorithm that searches for a function minimum by maintaining a pool of local searches, and then combining the local searches to try to escape the local minima. When applying differential evolution to optimize a trading strategy, it will need to maintain and simulate a pool of parameter sets. A typical procedure looks like this:
Decide the parameters, x, of an algorithmic trading strategy S(x); Choose an objective function, e.g., Sharpe-ratio, or Omega; Choose a calibration window, L, e.g., most recent 12 months; Choose a calibration frequency, f, e.g., every 3 months; For each f month { Prepare the data set for the last L months; Initialize a pool of different parameter sets; For each DE iteration { Apply the DE operators to generate the next generation parameter sets; For each parameter set { Simulate the strategy; Measure the performance; } Select the best performing parameter sets; } Simulate trading the strategy using the optimized parameters from the DE optimization algorithm; }
There are two, among many, difficulties in running this script in Matlab/R. The first one is coding. My personal opinion is that it requires Herculean effort to simulate non-trivial trading strategies (or any complex systems) in Matlab/R and make sure that the simulation is correct. There is simply no easy process or tool available to systematically and automatically check and test for the correctness of the scripts. Worse, most quants/traders cannot code. They know nothing about software testing. In practice, most quants/traders simply think/assume/fantasy that their code is correct. Actually, many programmers in the financial industry cannot code neither. (The good ones go to GooG, M$FT, AAPL… or startups.)
More importantly, the second difficulty, which this discussion focuses on, is performance. I believe that it is more than obvious that in general, executing Matlab/R scripts is very slow. Matlab/R executes and interprets a script line-by-line. For our algorithmic trading strategy optimization script, the bottlenecks are:
- Each strategy simulation is slow because of looping over times (or dates, or ticks).
- We need to simulate the strategy many times in each DE iteration.
- We run many these DE iterations as in genetic algorithm.
In other words, if you try to code up the above pseudo-code in Matlab/R, it may take days, if at all, to come up with results. If your trading strategy works with tick-by-tick data, then, it is hopeless.
To speed up the process, we can run the differential evolution algorithm in parallel on a grid. Matlab/R does allow you to parallelize your code. However, realistically, I have never seen any quants/traders writing parallel Matlab/R code. Even if they wanted to do it, few, if any, understood multi-threaded concurrent programming to get the code right. In addition, we can simply move away from Matlab/R to some real programming languages, e.g., C++/C#/Java. Complied code always runs faster than scripts. (Please!!! No VBA. Only managers use it…)
Algo Quant addresses the trading strategy optimization problem by
- Enable easy coding of a complex trading strategy in Java. To code a strategy, a quant/trader simply puts together components, e.g., signals, mathematics, event handlers, from the library.
- Optimize a strategy or a portfolio by running the differential evolution optimization algorithm in parallel.
I demonstrate the performance of Algo Quant using a simple moving average crossover strategy. This strategy maintains two moving averages, a fast moving average and a slow moving average. When the fast moving average crosses the slow moving average from below, we enter a long position; when the fast moving average crosses the slow moving average from above, we enter a short position. There are theoretical and empirical evidence to show that both the fast and slow moving window sizes should not be too big. See Haksun’s course note lecture 6.
Most traders choose the fast and slow moving window sizes by 1) guessing, 2) hearsay, 3) backtesting (with a few more or less randomly chosen parameters) in Bloomberg. Some traders recalibrate periodically by updating the parameters.
Let’s first try the hearsay approach. A popular choice is (50, 200). I simulate this strategy trading the S&P 500 futures, VFINX, from 2000/1/1 to 2011/5/31 with the Yahoo data. The source code is here.
Here is the P&L generated using Algo Quant.
We have: pnl = 50.4; sharpe = 0.080829; omega = 1.285375
There is no reason that (50, 200) is the optimal parameter set or that it even works at all. Intuitively, if we periodically update the pair (more flexibility), we could potentially generate a better P&L. For example, I trade this Simple Moving Average Crossover strategy by using the optimal parameters Dynamically calibrated every 3 months using the data in the last 12 months. For the objective function to determine optimality, I use omega. The source code is here.
As expected, this dynamically calibrated strategy does generate (much) better P&L than the statically strategy using randomly guessed parameters.
We have: pnl = 106.65; sharpe = 0.309824; omega = 2.816514
In terms of performance (computing speed), it took 32.5 minutes (1954877 ms) to finish the simulation for 10 and a half years on my workstation (dual E5520 @ 2.27GHz) with 12GB memory. (As a side note, using the other parallel Brute Force algorithm took only 6.6 minutes or 395334 ms.) Our parallel differential evolution algorithm maintains a pool of 16 parameter sets. In each of the 80 iterations, I run 16 simulations in parallel, one in each core. The picture shows that my computer is working hard, utilizing all its resources to search for the historically optimal parameter sets. Redoing this simulation-test-and-pick procedure in Matlab/R might probably take days, if not forever.
As a disclaimer, I do not claim that this dynamically calibrated SMA/2/Crossover strategy generates alpha on the S&P500 future. In fact, I just happened to pick (f = 3, L =12) by chance. My point is to compare Algo Quant’s performance of the parallel differential evolution on strategy optimization to that of Matlab/R.
5 Comments
Shall we optimize instead for “calibration window” and “calibration frequency”?
I’m a quant who is writing parallel Matlab/R code to run my own trading system.
Problem with DE as with any GA as well as brutforce is that you will get an overfitted answer perfectly fit to your data set.
Tripy.
I cannot agree with Tripy. You need enough degrees of freedom in the model to fit ‘perfectly’ the data set. For example, there is no algorithm, DE or GA, that can fit all NYSE data points by ‘optimizing’ only 1 variable.
Looks very interesting approach.
I’d like to see GA one trading models written in Java.
How one can buy your software? Is pricing negotiated case by case?