The Stochastic of Moving Average Indicator
Creating & Coding the Stochastic of Moving Average Indicator in Python
Fusing indicators together to create new indicators is extremely interesting especially when their utility does not get lost in the fusion. In this article, we will fuse two famous technical indicators, the stochastic oscillator and the moving average. The result is a powerful indicator that helps confirm breakouts.
I have released a new book after the success of my previous one “Trend Following Strategies in Python”. It features advanced contrarian indicators and strategies with a GitHub page dedicated to the continuously updated code. If you feel that this interests you, feel free to visit the below Amazon link (which contains a sample), or if you prefer to buy the PDF version, you could check the link at the end of the article.
Contrarian Trading Strategies in Python
Amazon.com: Contrarian Trading Strategies in Python: 9798434008075: Kaabar, Sofien: Bookswww.amazon.com
The Stochastic Oscillator
This great technique allows us to trap the values between 0 and 1 (or 0 and 100 if we wish to multiply by 100). The concept revolves around subtracting the minimum value in a certain lookback period from the current value and dividing by the maximum value in the same lookback period minus the minimum value (the same in the nominator).
To be able to manipulate the data, we first need to have an OHLC array (not a data frame) and define the following three small manipulation functions:
# The function to add a certain number of columns def adder(Data, times): for i in range(1, times + 1): z = np.zeros((len(Data), 1), dtype = float) Data = np.append(Data, z, axis = 1)
# The function to deleter a certain number of columns def deleter(Data, index, times): for i in range(1, times + 1): Data = np.delete(Data, index, axis = 1) return Data
# The function to delete a certain number of rows from the beginning def jump(Data, jump): Data = Data[jump:, ] return Data
The Stochastic Oscillator seeks to find oversold and overbought zones by incorporating the highs and lows using the normalization formula as shown below:
An overbought level is an area where the market is perceived to be extremely bullish and is bound to consolidate. An oversold level is an area where market is perceived to be extremely bearish and is bound to bounce. Hence, the Stochastic Oscillator is a contrarian indicator that seeks to signal reactions of extreme movements.
We will create the below function that calculates the Stochastic on an OHLC data:
def stochastic(Data, lookback, high, low, close, where): # Adding a column Data = adder(Data, 1) for i in range(len(Data)): try: Data[i, where] = (Data[i, close] - min(Data[i - lookback + 1:i + 1, low])) / (max(Data[i - lookback + 1:i + 1, high]) - min(Data[i - lookback + 1:i + 1, low])) except ValueError: pass Data[:, where] = Data[:, where] * 100 Data = jump(Data, lookback)
The above plot shows the EURUSD values plotted with a 14-period stochastic oscillator. Notice that the indicator will always be bounded between 0 and 100 due to the nature of its normalization function that traps values between the minimum and the maximum.
The Concept of Moving Averages
Moving averages help us confirm and ride the trend. They are the most known technical indicator and this is because of their simplicity and their proven track record of adding value to the analyses. We can use them to find support and resistance levels, stops and targets, and to understand the underlying trend. This versatility makes them an indispensable tool in our trading arsenal.
As the name suggests, this is your plain simple mean 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:
def ma(Data, lookback, close, where): Data = adder(Data, 1) for i in range(len(Data)): try: Data[i, where] = (Data[i - lookback + 1:i + 1, close].mean()) except IndexError: pass # Cleaning Data = jump(Data, lookback) return Data
The below states that the moving average function will be called on the array named my_data for a lookback period of 20, on the column indexed at 3 (closing prices in an OHLC array). The moving average values will then be put in the column indexed at 4 which is the one we have added using the adder function.
my_data = ma(my_data, 20, 3, 4)
Creating the Stochastic of Moving Averages
The idea we are trying to put through is to calculate the Stochastic on the moving average which in itself is calculated on the market price. However, with such smooth moving average data, we will be using the Stochastic in a different way. Here are the steps we are going to follow:
Calculate a 13-period moving average on the highs.
Calculate a 13-period moving average on the lows.
Calculate a 13-period moving average on the market price.
Calculate a 13-period Stochastic Oscillator on the moving average.
lookback = 13
my_data = ma(my_data, lookback, 1, 4) my_data = ma(my_data, lookback, 2, 5) my_data = ma(my_data, lookback, 3, 6)
my_data = stochastic(my_data, lookback, 4, 5, 6, 7)
By setting barriers at 80 and 20, we should have a chart like the below.
Our trading conditions will be the following:
Long (Buy) whenever the indicator turns above 20 after being below it, thus confirming the bullish exit from the oversold zone.
Short (Sell) whenever the indicator turns below 80 after being above it, thus confirming the bearish exit from the overbought zone.
def signal(Data, indicator_col, buy, sell): Data = adder(Data, 5) for i in range(len(Data)): if Data[i, indicator_col] > lower_barrier and Data[i - 1, indicator_col] < lower_barrier and Data[i - 1, buy] == 0 and Data[i - 2, buy] == 0 and Data[i - 3, buy] == 0: Data[i, buy] = 1 elif Data[i, indicator_col] < upper_barrier and Data[i - 1, indicator_col] > upper_barrier and Data[i - 2, sell] == 0 and Data[i - 3, sell] == 0 and Data[i - 4, sell] == 0: Data[i, sell] = -1 return Data
Alternatively, we can use other lookback periods such as 34 on the moving average and 13 on the Stochastic Oscillator. This should give us a chart like the below which is more stable and seems to give less false signals.
The signal chart following the same trading rule is below.
Now, let us see how to use the indicator properly. Imagine you are awaiting for an upside or downside validation because you have a pre-determined bias. You can use the above indicator in tandem with other techniques to validate the new bias. Since the indicator signals long-lived moves, it can be very useful. Also, the fact that it does not signal too many trades makes it less prone to whipsaws.
Of course, with moving averages and the Stochastic Oscillator, the lag effect is almost doubled, but since this is not a timing strategy, that problem is diminished and the focus is more on longer term moves.
If you want to see how to create all sorts of algorithms yourself, feel free to check out Lumiwealth. From algorithmic trading to blockchain and machine learning, they have hands-on detailed courses that I highly recommend.
Learn Algorithmic Trading with Python Lumiwealth
Learn how to create your own trading algorithms for stocks, options, crypto and more from the experts at Lumiwealth. Click to learn more
To sum up, what I am trying to do is to simply contribute to the world of objective technical analysis which is promoting more transparent techniques and strategies that need to be back-tested before being implemented. This way, technical analysis will get rid of the bad reputation of being subjective and scientifically unfounded.
I recommend you always follow the the below steps whenever you come across a trading technique or strategy:
Have a critical mindset and get rid of any emotions.
Back-test it using real life simulation and conditions.
If you find potential, try optimizing it and running a forward test.
Always include transaction costs and any slippage simulation in your tests.
Always include risk management and position sizing in your tests.
Finally, even after making sure of the above, stay careful and monitor the strategy because market dynamics may shift and make the strategy unprofitable.