A Better ZigZag

There are a lot of “winning” strategies for bull markets floating around. “Buy the pullbacks” is certainly one of them. Does this sound simple enough to implement to you? While I am no Sheldon Cooper (although I have a favorite couch seat), I still like to live in a somewhat well defined world, a world in which, there is much more information attached to a tip like “Buy the pullbacks”. Let’s start with a chart of the recent history of the S&P 500 ETF:


The indicator on the chart is the ZigZag indicator. It’s certainly one way to look for the proverbial pullbacks. One can use an absolute dollar amount, or a percentage to define the minimum amount the price needs to travel in the opposite direction to constitute a correction. I used a setting of 2% in the above chart. Notice, we won’t enter at the bottoms, most likely the position is taken as soon as the pullback is “registered”. Using our 2% setup, we enter the pullback as soon as the market is down 2% from the most recent peak. The rest of the road to the actual bottom is the pain we are going to suffer. 🙂

The chart indicates that over the last one year, there were 4 points to enter a position. That’s somewhat low if we think of buying each pullback and then closing the trade (these are not buy and hold entries).

Pretty easy you say – go to 1.5%, or even 1%, pullback. Well, before we do that, let’s look at the same chart just over a different period in time:


To me it seems that we actually have way too many “corrections” (a.k.a. pullbacks) during the 2011 turbulence.

By now it’s pretty clear what I am getting at – the pullbacks shouldn’t be a hard number, neither a total amount, nor a percentage. It seems a better approach to get volatility involved.

To address these issues, I modified the ZigZag to actually use volatility to measure the pullbacks. With this improvement, the charts look somewhat different.

SPY 2014,

Notice, we have a few more “corrections” generated by the modified ZigZag (the red line in the charts) in the low-volatility environment. Similarly, keeping the settings the same, there are a few less “corrections” generated by the volatility ZigZag in the high-volatility environment.

SPY 2011

How useful is all this? Frankly, I don’t know yet, but it doesn’t really matter, in a way. I consider the first goal achieved – I have a simple indicator, with a single setting, to model what my strategy would consider as a pullback. In the process, I have added a few useful features to my ZigZag. My R implementation is, in an amusing way, totally the opposite from the TTR’s ZigZag. The TTR’s ZigZag simply returns the indicator line, thus, one can easily plot it, but it’s hard to tell from the line when was the move “registered” (in other words, when was the 2% pullback first hit). My implementation on the other hand (available from the btutils package), does not compute the lines connecting the extremes (thus, one cannot draw it at all), but it computes three other columns which can be easily used to implement a trading strategy based on the modified ZigZag (the “age” column is 0 at the inflection points). I guess we all have different goals. 🙂 Here is how to call the btutils version:

spy = getSymbols("SPY", from="1900-01-01", auto.assign=F)
spy.zz = zig.zag(Cl(spy), 2*runSD(ROC(Cl(spy),type="discrete"),10), percent=T)

Last, the btutils package currently cannot be installed on Windows directly from R-Forge. You still can download the source code (the easiest way is to create a new project in RStudio and select from source control etc) and build the package.


  1. P Verghese says:

    The problem with the zigzag indicator is it can’t be used for real trading because the indicator is recalculated for past prices at every new price bar. So a previous high or low indicated by the zigzag might not remain a previous high or low going forward.

    1. quintuitive says:

      Yes, in general you are right. However, can’t it be used to buy the dips without a forward looking bias? The answer is yes. Think of a top, as soon as we reach 2% off the top, we know that the top is in place, and that we have started a new downward trend, right? (assuming 2% is the threshold). Thus, I see no problem going long at this point – buying the dip.

  2. Lionel says:

    Could you please add a backtest ?

    1. quintuitive says:

      A meaningful backtest would reveal too much – this cannot be traded on its own. You need at least some measure of a long term trend, and as with any other mean-reverter – there must be a firm stop loss, and likely a good profit target.

  3. Roman says:

    Hello !

    Isn’t the ZigZag non causal ? I.e., adding new data changes the past values of this indicator ?



    1. quintuitive says:

      Yes, to connect the points, it has a forward looking bias. Think of a top, as soon as we reach 2% off the top, we know that we have a new downward trend, right? (assuming 2% is the threshold). Thus, I see no problem going long at this point – buying the dip.

  4. Samuel says:

    Thanks for this interesting post. Question: which charting library are you using?

    1. quintuitive says:

      This is a png export from Ninja Trader.

  5. Todd says:

    I get an error–Zig.zag is not defined. Is that because I have an older version of btutils?

    1. quintuitive says:

      Haven’t touched the package in a while, but it’s zig.zag – all lower case.

  6. Brad A Jantz says:

    I just ran across this article. I have been interested in the zig zag concept for some time. I am also pretty new to R and was excited to see this. I’m not experienced enough to code this myself. I was able to install the btutils package and test the function. I am getting some strange results and wondered if you have any documentation on the function to make sure I understand what is being calculated in each column (primarily “targets” & “corrections”)? Your code works fine, but if I change the 2nd argument to hard code a % change it gives some strange output. Thanks for any info you can provide.

    1. quintuitive says:

      Hi, it has been a while since I looked at it. In general, the “targets” columns is the level the indicator is looking for to change direction. For example, if currently the indicator is in an uptrend, and targets shows 1%, it means that the uptrend will be broken when a 1% correction is reached. “corrections” I think shows the current correction off the last peak.

Leave a Reply