Adaptive Moving Average in Python. | by Sofien Kaabar, CFA | Towards Data Science

Note from Towards Data Science’s editors: While we allow independent authors to publish articles in accordance with our rules and guidelines, we do not endorse each author’s contribution. You should not rely on an author’s works without seeking professional advice. See our Reader Terms for details.
Moving averages are one of the simplest and most effective tools in detecting changes in trend. They are also used in creating trading strategies based on crossovers. Pretty much every trader uses them and includes them in her decision-making process. In this article, we will skim through the basic known moving averages and then present the slightly more complex Kaufman Adapative Moving Average — KAMA.
I have just published a new book after the success of New Technical Indicators in Python. It features a more complete description and addition of complex trading strategies with a Github page dedicated to the continuously updated code. If you feel that this interests you, feel free to visit the below link, or if you prefer to buy the PDF version, you could contact me on Linkedin.
www.amazon.com
The three most common moving averages are:
Simple moving average.
Exponential moving average.
Smoothed moving average.
We will go through each one, define it, code it, and chart it before we move on to the KAMA.
Simple moving average
As the name suggests, this is your plain simple average that is used everywhere in statistics and basically any other part in our lives. It is simply the total values of the observations divided by the number of observations. Mathematically speaking, it can be written down as:
In python, we can define a function that calculates moving averages as follows:
def ma(Data, period, onwhat, where):        for i in range(len(Data)):            try:                Data[i, where] = (Data[i - period:i + 1, onwhat].mean())                    except IndexError:                pass    return Data
The function takes your data structure represented by the Data variable, the moving average period (20, 60, 200, etc.) represented by the period variable, what do you want to apply it on (on OHLC data structures, choose 3 for close prices because python indexing starts at zero) represented by the onwhat variable, and the where variable is where do you want the moving average column to appear. Note that you must have an array of more than 4 columns for this to work, because it doesn’t automatically create a new column, but simply populate it.
Exponential moving average
As opposed to the simple moving average that gives equal weights to all observations, the exponential moving average gives more weight to the more recent observations. It reacts more than the simple moving average with regards to recent movements. Mathematically speaking, it can be written down as:
The smoothing factor is often 2. Note, that if we increase the smoothing factor (also known as alpha) then, the more recent observations will have more weight. In python language, we can define a function that calculates the EMA as follows:
def ema(Data, alpha, window, what, whereSMA, whereEMA):        # alpha is the smoothing factor    # window is the lookback period    # what is the column that needs to have its average calculated    # where is where to put the exponential moving average        alpha = alpha / (window + 1.0)    beta  = 1 - alpha        # First value is a simple SMA    Data[window - 1, whereSMA] = np.mean(Data[:window - 1, what])        # Calculating first EMA    Data[window, whereEMA] = (Data[window, what] * alpha) + (Data[window - 1, whereSMA] * beta)# Calculating the rest of EMA    for i in range(window + 1, len(Data)):            try:                Data[i, whereEMA] = (Data[i, what] * alpha) + (Data[i - 1, whereEMA] * beta)                    except IndexError:                pass    return Data
The function is self-explanatory as it merely reproduces the EMA function presented above.
If you are also interested by more technical indicators and using Python to create strategies, then my best-selling book on Technical Indicators may interest you:
www.amazon.com
Smoothed moving average
This moving average takes into account the general picture and is less impacted by recent movements. It’s my favourite trend-following indicator. Mathematically speaking, it can be found by simply multiplying the Days variable in the EMA function by 2 and subtract 1. This means that to transform an exponential moving average into a smoothed one, we follow this equation in python language, that transforms the exponential moving average into a smoothed one:
smoothed = (exponential * 2) - 1 # From exponential to smoothed
The KAMA has been created to reduce the noise and whipsaw effects. It works the same as other moving averages do and follows the same intuition. The generation of false trading signals is one of the problems with moving averages and this is due to short-term sudden fluctuations that bias the calculation. The KAMA’s primary objective is to reduce as much noise as possible.
The first concept we should measure is the Efficiency Ratio which is the absolute change of the current close relative to the change in the past 10 periods divided by a type of volatility calculated in a special manner. We can say that the Efficiency Ratio is the change divided by volatility.
Then we calculate a smoothing constant based on the following formula:
Finally, to calculate the KAMA we use the below formula:
The calculation may seem complicated but it is easily automated and you do not have to think about it much. Let us see how to code it in Python and then proceed by seeing some examples.
def kama(Data, what, where, change):        # Change from previous period    for i in range(len(Data)):        Data[i, where] = abs(Data[i, what] - Data[i - 1, what])        Data[0, where] = 0        # Sum of changes    for i in range(len(Data)):        Data[i, where + 1] = (Data[i - change + 1:i + 1, where].sum())               # Volatility        for i in range(len(Data)):        Data[i, where + 2] = abs(Data[i, 3] - Data[i - 10, 3])            Data = Data[11:, ]        # Efficiency Ratio    Data[:, where + 3] = Data[:, where + 2] / Data[:, where + 1]        for i in range(len(Data)):        Data[i, where + 4] = np.square(Data[i, where + 3] * 0.6666666666666666667)            for i in range(len(Data)):        Data[i, where + 5] = Data[i - 1, where + 5] + (Data[i, where + 4] * (Data[i, 3] - Data[i - 1, where + 5]))        Data[11, where + 5] = 0
The below chart illustrates what the above function can give us. Notice the more stable tendency of the KAMA relative to other moving averages. It is an improvement with regards to whipsaws and false breaks.
The KAMA can also be used to detect the start of new trends. For instance, we can plot a long-term KAMA with a short-term KAMA and trade on their crossovers. If the default settings are 10-period, we can try a 30-period KAMA and see what it gives us.
plt.plot(Asset1[-500:, 3], color = 'black', label = 'EURUSD')plt.plot(Asset1[-500:, 4], color = 'blue', label = '10-period KAMA')plt.plot(Asset1[-500:, 5], color = 'purple', label = '30-period KAMA')plt.grid()plt.legend()
Using the above chart, we can say that when the two KAMA’s are flat, the market is ranging and when a trend starts, we should follow their respective crossover such as that when the 30-period KAMA is above the 10-period KAMA, a bearish trend is in progress until a crossover happens. This in turn can be a valuable signal to us. If you are interested in trend-following strategies, you can check out the below article:
medium.com
Now, let us plot a simple moving average and compare it to a same period KAMA. Visibly, the latter provides a better and more accurate picture of what is going on and that is because it takes volatility into account . Now I am not saying you should replace the simple moving average with the KAMA but it may seem like a good idea to include it in the framework.
Being a fan of adaptive and exponential moving averages, I encourage you to experiment with this technique. KAMA provides valuable support and resistance levels that can be used to complement your trading system. It is not meant to be used as a sole contributor to generate trading signals but it is valuable in confirming them.