Back to Community
Trading Strategy: Moving Average Mean Reversion

Hi All,

I'd like to share with you a simple mean reversion technique that relies on moving averages. In short, the idea is that the mean-reversion signals can be approximated by intersections of different-length moving averages. This is best made clear by the following illustration:

http://i.imgur.com/5oi3yao.png

In which the data is from a 3,000-day dataset of a stock's closing price. In this model, we generally have one "long" moving average and one "short" moving average (in this case, 90 and 30 days, respectively). We trade when these lines intersect, then choosing to buy or sell based on the direction of the trend (whether the short MA is rising or falling). I note that we don't trade exactly when the lines intersect, but rather when they are sufficiently close (by some user-defined metric). While this is not as statistically strong as mean reversion could be, it's a reasonable approximation with plenty of nice properties because of the lag between the two MAs: a reasonable buy/sell strategy with clear signals that translates into having an effective stop-loss from any peak, except for cases of sudden and severe price crashes.

I've attached a backtest that I ran on some tech stocks between 2008 and 2010, with MA periods of 30 and 10 days.

I'm somewhat new to Quantopian and I didn't have much time to write my algorithm, so I apologize for some of the crude techniques I used in my code, which I intend to fix in future versions. I plan to rewrite the part that decides how much to invest (it's currently mostly hand-tuned with guesstimates), to add a more sophisticated stop-loss, and and to improve the heuristic for determining whether a security is trending negatively or positively. I also need to make my algorithm start shorting stocks. There's generally a great deal of calibration to be done to this algorithm. It would also probably be useful to develop some analyses that determine the best MA periods to use.

Feel free to play around with this algorithm and see if you find anything interesting!

Clone Algorithm
457
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 55097f265125cc733e0b1e5b
There was a runtime error.
9 responses

Pardon the bump, but this is a notebook I made to help visualize like your photo. The variables are accessible as well.

Loading notebook preview...
Notebook previews are currently unavailable.

Hi John,

I spent some time looking over this over, and I have to give it to you: this is a very well calculated and intuitive algorithm.
I was able to make some pretty good improvements to the algorithm's readability and performance.

As far as lines of code goes, I sought out to make some readability improvements by streamlining some of the more rigorous methods using Quantopian builtins. I removed the need for a price database and a 30-day waiting period using the history function. I also used the records as Darrell suggested to track the positions and leverage. In order to ensure the orders went in correctly, I changed those to orders by percentages. After that, I noticed that you had placed a "pass" statement where the algorithm called for a "continue" statement. Without your comments, I definitely would have missed it.

In terms of algorithm logic, I reversed the buy/sell initiations to activate when the price over the last 4 days increases/decreases in order to ride the mean reversion momentum up as opposed to guessing whether it will or not. As an aside, this makes the algorithm more of a hybrid than mean reverting, but I was able to gain some get some good improvements to the sharpe ratio. I also removed a security in your sample that was delisted in 2010 to view the algorithm's performance to date. It performs very well, great job.

Best,
Lotanna Ezenwa

Clone Algorithm
311
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 56d34f36effa380de8480449
There was a runtime error.
Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

It would be helpful to see if this is still profitable without the hand-picked stocks, but rather using some sort of dynamic universe.

Yeah, I'm currently working on editing the logic to encompass some other stocks using pipeline. I tried putting a few in there at random and the performance was lacking.

My hypothesis at the moment is that new securities selected based on fundamentals will do just as well. I'll post the update when I finish.

Same algorithm on a universe of 600 stocks. It might be worth double checking I didn't introduce any bug.

Clone Algorithm
66
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 576bcf40395ae511d92a70d2
There was a runtime error.

and on a universe of 50 stocks

Clone Algorithm
66
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 576bec7aa2eaff11d021547d
There was a runtime error.

How about testing it with a 3X ETF

if 10day.mean > 30day.mean, we long (buy). If 10day.mean < 30day.mean, shall we short-sell ?

@Tory, It's a little bit more involved. It looks for whether the 10day mean is greater than 95% of the 30day mean. What the algo is trying to compensate for is that moving averages are a lagging indicator, so it's fudging the signals so that they trip earlier. It also checks for a 3-day continuous uptrend as a confirmation signal. And visa versa for selling. Also has a 8% stop loss. It all sounds good in theory, but as Luca's posts pointed out, it's not the algorithm that produces those impressive results in the initial backtests -- it was the bias introduced by the hand-selected stocks.

The difficulty with crossovers is that 1. due to the smoothing they're a lagging indicator, and 2. the frequency and amplitude of the price waveform is too variable for fixed-period crossovers to discern between signal and noise -- they don't do a good job of detecting whether a recent price move is establishing new momentum as opposed to a temporary move that will quickly revert. So just as often as not by the time the signal gets triggered the price is already moving in the other direction.