This Simple Indicator SMASHES “Buy and Hold” Returns!

Have you ever wanted to get better returns from your investment portfolio, but been stuck with a Stock Broker or report that under-performs or buys to hold – suffering through downward periods and Bear Markets?

This simple indicator could give you the power to “time the market”, with only a few minutes needed a year.

Recently an article came across my desk by Chris at Ciovacco Capital that outlined a simple way to time the entire market.  It used the overall index – in his case the S&P 500, and Chris showed that Index’s returns after the signal gave the go-ahead.

Being from ASX Market Watch and living by the principle of #ValidationRules (see the entire Five Principles here), I wanted to see if a regular person could make it work, by buying a basket of 20 stocks once the market gave this signal.  The video below shows you how I got the actual statistics and results, which I based on 1000 different random versions of the trading system I created from this idea (this is more commonly known as Monte Carlo testing).

Here are the Rules:

  • Index (in this case the S&P 500) ROC(12) weekly indicator (Rate of Change) first closes below -8.25.
  • Index ROC(12) weekly indicator then closes above 5.
  • Index is above its 50 Week (250 day) Moving Average
  • Then we buy 20 stocks randomly.

Before you watch the video, you should know: the results are good.  For a very low time commitment, you could out-perform the index by a significant amount.  Check it out below!

Here are the results below!

All tests are from 1000 random variations of the trading system, taking 20 stocks at a time with 5% of our total portfolio in each stock.  Tests were done from 2005 to 2015 on the S&P 500.

But first – here are a NORMAL buy and hold portfolio’s results.  I show you this, so you have something to compare the indicator to.

Normal S&P 500 Buy and Hold (used as a benchmark)

  • 7.5% to 9% per year was the most common return
  • 40% to 60% were the most common maximum drawdowns (the total portfolio loss at one point)

I doubt many people could stomach a 60% drawdown in their portfolio without panicking – especially when the yearly annual return was only around 8%, which is why so many people flail in the markets instead of creating and sticking to solid trading rules.  The RANGE of results (top) and the Annual return versus the max drawdown (bottom) are in the picture below:

Buy and Hold SP 500

ROC Indicator S&P 500 Timing Returns:

  • 13.5% to 14.5% per year were the most common returns
  • 15% to 30% maximum drawdown

Additionally, it only took four signals over 10 years.  A VERY low time constraint for a better reward.

As you can see, the return increased significantly (especially considering the tiny time effort involved), but more importantly the risk reduced significantly as well – to a 15% to 30% drawdown instead of a 50% to 60% loss at some point.

ROC Indicator SP 500

So perhaps it doesn’t take too much to outperform the overall market – and even many fund managers as well!

I hope you have enjoyed this post!  Leave a comment below, and check out the free courses (including the popular Free Amibroker course) at this site.

Happy trending,

– Dave McLachlan

December 5, 2015  Tags: , , , , ,   Posted in: Amibroker, Stock Market Research

11 Responses

  1. MIke S - December 6, 2015

    Very, very interesting!
    Did you generate the charts that you pasted into Excel with Amibroker?
    Thank you,
    Mike

  2. Dave McLachlan - December 6, 2015

    Hey Mike,

    Partially – I coded the system and got the data from Amibroker (the Monte Carlo test / 1000 runs) then exported that to Excel so we could see the Histogram and the Scatter Plot 🙂

    I show how I do this here: http://www.asxmarketwatch.com/2015/11/amibroker-q-a-how-to-do-a-monte-carlo-test-on-all-versions/
    and here: http://www.asxmarketwatch.com/2015/11/amibroker-q-a-visualising-monte-carlo-data-with-histograms-and-scatter-plots/

    Happy trending,

    Dave

  3. MIke S - December 7, 2015

    Thanks for the reply Dave,

    I got your code working last night, very exciting! I couldn’t load the Short Takes blog last night, although it’s up now, so I just typed in your code from the video, I had to use this to see the buy arrow (which I changed to triangles for visibility)
    PlotShapes(Buy * shapeUpTriangle, colorGreen, 0, Low, 0);

    I never did the random selection of stocks from a watch list before, that’s a great technique, thanks!

    I was wondering about adding further filtering to try to remove the low performers. One idea I had was to use other indicators – do you know if it’s possible to use indicators on the randomly selected stock in the “Buy = …” equation? Also I was wondering if there’s a way to run the same MA_ROC approach on each randomly selected stock to see how much it looks similar to, or different from, the S&P 500 Index. I was thinking that if I calculate an error term for each stock – showing the divergence from the S&P behavior – that might be a way to filter out the low performers.
    Obviously I’m just guessing, trying to find a way to apply some statistics to an already great little system.

    Thank you again for the system and some really great programming tricks, much appreciated!
    Mike

  4. Dave McLachlan - December 8, 2015

    Hey Mike – nice one! Great stuff!

    You can definitely add buy criteria to the “Buy=…” . Just be sure, if you’re testing additional rules, to leave a good period (2-3 years for a long term system like this) at the end for Out of Sample data testing.

    I wouldn’t go about deleting stocks from the universe for better results – we’re more likely to curve fit that way. We want something robust enough to work on (or possibly avoid) the stocks/trades that lose (or lose too much).

    The random part will simply select random stock but ONLY if there are more than 20 available at the time of buying. Otherwise, Amibroker chooses them alphabetically.

    Love your work! 🙂

    – Dave

  5. MIke S - December 8, 2015

    Dave,

    I filtered out the 40 s&p500 stocks, see how your numbers look with these:

    ads
    alxn
    amgn
    avgo
    cmg
    dfs
    dltr
    el
    gm
    gmcr
    hog
    hon
    hum
    ilmn
    kmi
    kors
    ksu
    lb
    lyb
    mnk
    mnst
    mpc
    mur
    nflx
    nlsn
    oke
    pcln
    regn
    rost
    sbux
    trip
    tsco
    twc
    twx
    vfc
    wfm
    wmb
    wynn
    xyl
    zts

  6. MIke S - December 8, 2015

    I found 10 companies that perform well with this approach out of the S&P 500:
    cmg, sbux, twc, nflx, ilmn, regn, lyb, pcln, hon, lb

  7. MIke S - December 17, 2015

    This works in a strongly trending market, but it fails badly in a sideways range-bound market.

  8. Dave McLachlan - December 18, 2015

    Ah, the curse of a Trend Following system.

    Got any stats around it – i.e. which years? Was that using the random basket of stocks approach? What was the drawdown like?

    Always good to see. Cheers – Dave

  9. Stuart - January 6, 2016

    Great video.

    Can you please give the breakdowns for both the long and short trades?

  10. David McLachlan - January 6, 2016

    Hey Stuart,

    Thank you! And that is easy – there were no short trades. Only Long. And all completely randomly chosen PROVIDED the Index met that criteria.

    Hope this helps,

    Dave

  11. Marcel - January 22, 2016

    I coded the indicator (copy below) and it seems to work, however my ROC shows up in the same panel as the price. Can anyone tell me how to get the ROC in a separate panel like it shows in the video?

    _SECTION_BEGIN(“2016.01.21 ROC”);
    SetChartOptions(0,chartShowArrows|chartShowDates);
    _N(Title = StrFormat(“{{NAME}} – {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}”, O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
    Plot( C, “Close”, ParamColor(“Color”, colorBlack ), styleNoTitle | ParamStyle(“Style”) | GetPriceStyle() );

    //Buy on ROC > 5, after a ROC < -8.25
    //I've put sell of ROC MA(Index,50);

    Buy=IndexUpper AND indexMA;
    Sell=Indexdowner;

    Buy=ExRem(Buy,Sell);
    Sell=ExRem(Sell,Buy);

    PlotShapes(Sell*shapeDownTriangle,colorRed,0,Indexdowner,0);
    PlotShapes(Buy*shapeUpTriangle,colorGreen,0,IndexUpper,0);
    PlotShapes(Sell*shapeDownArrow,colorYellow,0,High,0);
    PlotShapes(Buy*shapeUpArrow,colorAqua,0,Low,0);
    Plot(MA(C,50),”Moving Av 50 week”,colorGreen,styleLine,0,0,0);
    Plot(ROC( Index, 12 ),”ROC”,colorBlue,styleLine,0,0,0);

    _SECTION_END();

Leave a Reply