25

An Elliott Wave Algorithm in Python

Around 2013 I came across Elliott Wave theory, when a good friend of mine introduced me to the topic. I was hooked on and read the classic Elliott Wave Principle: Key to Market Behavior by Prechter, Frost et al. In these eight years, the topic was sometimes more and sometimes less interesting for me. But since there is no reliable method to find the waves (apart from expensive subscriptions ;-)), the waves have never found their way into my trading (which is essentially a buy and hold strategy over all asset classes).
With the strong increase of Bitcoin in Q1/2021 I got again interest on the topic and tried to find an algorithm / git repo for Python. Unfortunately, there is no out-of-the-box Elliott wave algorithm that worked for me. So I tried one myself.

Basic Elliott Wave Theory

For a detailed introduction to waves you can read the Wikipedia article. If you are here, chances are good, that you know the basics. The key points of Elliott Wave theory are

  • A market develops in waves
  • A wave is always a 5-way impulsive wave (rise, correction, rise, correction, rise).
  • These are counted with numbers 12345: 1 rise, 2 correction, 3 rise, 4 correction, 5 rise
  • Followed by a 3-way correction wave (decline, correction, decline)
  • Counted with letters ABC: A decline, B correction, C decline
  • Once there is a valid count for the 12345 movement, the 5 forms a (1) on a higher time scale.
  • The C forms the (2) on this time scale and so on.
  • This can be continued in both (time-wise) directions: smaller and larger time frames

A valid counting (12345) is present, if certain rules apply. The rules concern length (in value) and duration (in time) of the waves, for example the third Wave must always go over the top of the first, the 2nd wave corrects at least 20% of the 1st wave, etc.

My main problem with waves is the fractal structure of a market: If you remove axes (time and value), you can’t tell if the chart is on an hourly or, say, daily basis. So I put some thoughts into an Elliott Wave algorithm implemented in Python.

Basic Idea of the Algorithm

First, I’d like to introduce a few terms, which I use for the Elliott wave algorithm.

A monowave is the movement from a given point (datetime), where each following candle is forming a new high (or low respectiveliy in a downwards movement).

A wavepattern is the chaining of monowaves, e.g. 5 monowaves for an impulse, 3 for a correction, 2 for a Tietjen pattern (second wave corrects exactly to the .618 Fibonacci level).

A waverule is a set of rules which all have to match, that the wavepattern is recognized as a valid pattern, e.g. Wave 3 is not the shortes, Wave 4 is not going lower than the high of Wave 1 etc.

Core functions next_max() and next_min()

I implemented two core functions which will return, given a starting point (start_idx), the end of the follwing monowave (in time and magnitude / value). The function has an additional argument: skip_n which will skip the next n maxima (or minima respectively). This baisically means, that the monowave can have (smaller) corrections inside. Naturally, the corrections must not exceed the low of the starting point. The function will return a False in this case.

These functions can start via start_idx on arbitrary points. Essentially, calling next_min from a high / end of a wave 1 will find the end of wave 2. Calling next_max() from there will find end of wave 3 etc.

next_max() function at work for different values of the skip argument
Three different options for the next_max() function. The left one finds the next maximum, in the middle we skip the first one (skip=1) and on the right we skip the first two (skip=2) found maxima. N. B. for simplicity the option start_idx is omitted in the image.

Algorithm at work

Given an arbitrary OHLC chart (daily, hourly candles etc.)

  1. Find first monowave, i.e. find the next maximum in the chart and denote with 1. ( equal to calling next_max(start_idx=0, skip=0))
  2. From this one, find the next minimum, i.e. the monowave and denote with 2. (equal to calling next_min(start_idx = end_wave1, skip=0))
  3. Continue up to 5 waves (or the wavepattern you are looking for)
  4. Apply a waverule to this wavepattern

Now, two things can happen:

  1. If the pattern is valid, you have found your first Elliott Wave count. Congratulations!
  2. The pattern is not valid, as there are rule violations found.

I have designed the search algorithm such, that you pass a list of e.g. 5 options if you look for a valid 12345 count (called impulse) for the 5 consecutive next_max() and next_min() calls, i.e. passing [0,0,0,0,0] will result in calling next_max(skip=0), next_min(skip=0), etc. while passing [2,1,2,0,0] will result in calling next_max(skip=2), next_min(skip=1), next_max(skip=2) etc.

In case of an invalid pattern, you now have to change the inputs and test different combinations of skipping local minima and maxima. You can loop over the search part, e.g. with testing all waver patterns found for all combinations between [0,0,0,0,0] and say [5,5,5,5,5].

Example Etherum Daily

In this example I took the Etherum daily candles from 28th February 2021 onwards. A fast and easy way to retrievce historical data can be read in this post. The algorithm is run with the options [1,0,0,0,0] (first found maximum will be skipped) which will result in the following count:

an invalid elliot wave count, as the end of the fourth wave exceeds the end of the first wave
Found pattern for the options [1,0,0,0,0]. The numbers in brackets denote the fibonacci retracements with respect to the previous wave. As I m mostly intersted in trading third waves I only write the numbers for these waves.

Luckily a pattern was found for this options, which is not always the case. For example if your data is representing an overall downwards trend, you may not find a first maximum, as all candles will have lower highs.

However, the found pattern (12345), is not a valid count, as the low of the 4th wave is exceeding the end of the first wave.

Calling the finder with standard options [0,0,0,0,0] results in this pattern:

a valid elliott wave count

You can see, that it looks much healthier for a Elliott Wave count. Indeed, this is a valid count! Wave 2 retraces also nicely near the .618 Fibonacci level.

Final Thoughts on this Elliott Wave Algorithm

Please note, that to have a valid 1, the substructure of the first wave also has to be a valid 12345 impulsive wave. You can see, that you will always have this problem (fractal market structure) and determine if the 1 of this substructure is a 12345 ad infinitum. As I’m by far not a day trader (trader at all), I look for entries and targets (length of waves in time) say in the order a few days up to order of weeks. This ensures no less stress, as I don’t have to check any charts on a daily basis.

As the third wave often is the strongest (value wise) I look especially for a corrective 2 and entry the market somewhere at this point. I use this Elliott Wave Algorithm to count on a fine dataset, say hourly candles and set the wave structure (12345 -> (1) -> ABC -> (2) etc.) on this timeframe, but trade on the larger counts (1)(2)(3), or even (1)(2)(3)(4)(5) -> (I).

The repo

I have everything optimized with numba, full object orientated. Running thousands of combinations takes only a few seconds. You can find the available code on github.

The discussion continues here.

Steven

25 Comments

  1. Great article Steven. I was so convinced that I will never find anything on Python on EW. i got interested quite recently and I find it hard to believe that your article is just from this month. Great job.

    • hi Omar, thanks a lot for your comment. I plan to continue developing and publish on github once the code reaches a somewhat showable status 😉 At the moment I struggle in recognizing an actual wave, i.e. once a few counts 12345 -> (1) -> ABC -> (2) are down etc. I’ll add a new article, once I’m done with more coding in the near future.

      If you are interested in exchange please drop a mail steven (a t) codeopportunity.com

      Have you looked into this repo already, https://github.com/Wkemery/ElliotWaveAnalysis ?

      • This is very interesting. I myself just started learning EW and wanted to code it.

    • hi, I’ll clean up the code and put it on github soon, as its not documented in a way i like to have it.

      I will write another post and explain on an example the next week how it works: At the moment I struggle with finding valid 12345 – ABC patterns (e.g. EUR/USD), where the “wave gurus” see some counts, but they violate specific rules, like subwave is too short, subwave do not reach certain retracements etc.

  2. Great job! Any news / upds are available? Is it possible to look at the code?

  3. Steven,

    This is great. I recently got introduced to EW by my cousin and got interested to use it in my day to day trades. Are you looking for collaborators to push this code forward within your repo ? Or are yo looking for people to fork it ? Is there a way I can look into your code ?

  4. Hey Steven,
    Great to see such a wonderful automation will be available for live markets.

    Hope I can help you theoretically or based on my experience using wave counts.

    Keep up your great work.

  5. Hi Steven,

    It’s still true that there are no easy to find implementations of Elliot Wave Theory in Python that’s available. Have you polished the code base ready to be shared? If so it will be a great start for enthusiasts! Please post it (refinement can happen post the share as well!)

  6. Thank you, Steven. What do you use numba for?
    And going through the code, I do not see how do you implement any validation (or metrics ) for calibrating/benchmarking the identified waves. Any comments on what will be the best approaches? (Are there well established patterns to compare against – may be simulations are a path)

    • hi, thanks for your comment.

      The wave patterns are validated against a set of rules (se waverules.py, where I have linked to the sources). The general ‘wave rules’ are based on the literature from Prechter et al. So they are hard coded (debateable if this is good or not). There are ‘obvious’ rules: top of wave 1 must be lower than top of wave 3, and that top lower than top of wave 5 (for an 12345 impulsive movement upwards). Additional there are more subtle rules, e.g. that wave 3 is shorter than 7x wave 1 (time-wise).

      numba decorator is used in the functions.py, where the highs and lows of the candles are used as numpy arrays to find min/max and build the monowave structure. As the algorithm is not smart, but brut force, we test many wave patterns and need some speed.

      For comparison:

      running the bitcoin example in the repo testing ~ 0.6M combinations takes at my laptop ~41 secs. Removing the @njit decorator and running the code again takes ~66 sec. Not that much of improvement, but for only placing a decorator to a function i ll take it.

  7. Thanks for the explanations, Steven. Sure that’s a significant speedup using numba (that too just with a simple implementation adding a single decorator).

    For the validation, I meant, is there some data that serves as a labelled dataset (like in most ML/DL training-testing-validation kind of loop) A benchmark of well known, elliot wave patterns on some data. If not, any simulated wave patterns would serve as a substitute. Do you know of any of these 2?
    Rules being valid itself is great & thanks for the clarification. Besides those, if we run the code on a dataset known to have the EW patterns (defined by the rules), does it pick them up all the time? Or 90% time etc. Any pointers on this kind of validation/known predefined datasets will be great !

    • hi,
      my biggest problem is/was: there is no tool or free ML algorithm to label a dataset 😮 I have tried a few tool with monthly subscriptions and they work very well and are very fast (think 1000x of the python code or so).

      You can check twitter or other blog and validate some wave counts with respect to the rules. I have noticed that they often violate specific rule and wave counts are continously changed: this is true / or right so to say, as the market evolves and there are more than e.g. a single 12345 pattern.

      It’s not that easy, especially dealing with the fractal wave structure. For example: The first Impulse of a 12345 has to be also an impulsive wave 🙂 How to solve this? My ansatz is, that you use for example 1h data and count the waves on this timeframe to have a 12345, ABC which then form a (1) and (2) on the say 4h / daily time frame. However his iterative solver is not implemented yet and I could need some help. Maybe the repo will find some collabs. regards, Steven

Leave a Reply

Your email address will not be published. Required fields are marked *