One of the most famous indicators out there is the Moving Average Convergence Divergence — MACD. It is a heavily followed oscillator that can be used in trend-following systems or in contrarian strategies. This article discusses the special divergence technique, another way of trading divergences.
I have just released a new book after the success of my previous one “The Book of Trading Strategies”. It features advanced trend-following indicators and strategies with a GitHub page dedicated to the continuously updated code. Also, this book features the original colors after having optimized for printing costs. If you feel that this interests you, feel free to visit the below Amazon link, or if you prefer to buy the PDF version, you could contact me on LinkedIn.
The MACD Oscillator
The MACD is probably the second most known oscillator after the RSI. One that is heavily followed by traders. It stands for moving average convergence divergence and it is used mainly for divergences and flips. Many people also consider it a trend-following indicator but others use graphical analysis on it to find reversal points, making the MACD a versatile indicator.
Before we start building this oscillator, we must understand what moving averages are and how do we code them. 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:
The code for the moving average can be written down as the following:
# The function to add a number of columns inside an array
def adder(Data, times):
for i in range(1, times + 1):
new_col = np.zeros((len(Data), 1), dtype = float)
Data = np.append(Data, new_col, axis = 1)
return Data
# The function to delete a number of columns starting from an index
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 number of rows from the beginning
def jump(Data, jump):
Data = Data[jump:, ]
return Data
# Example of adding 3 empty columns to an array
my_ohlc_array = adder(my_ohlc_array, 3)
# Example of deleting the 2 columns after the column indexed at 3
my_ohlc_array = deleter(my_ohlc_array, 3, 2)
# Example of deleting the first 20 rows
my_ohlc_array = jump(my_ohlc_array, 20)
# Remember, OHLC is an abbreviation of Open, High, Low, and Close and it refers to the standard historical data file
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
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 200, 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, 200, 3, 4)
An exponential moving average is a special type that gives more weight to the recent values. To spare you the boring details, here is the code.
def ema(data, alpha, lookback, what, where):
alpha = alpha / (lookback + 1.0)
beta = 1 - alpha
data = ma(data, lookback, what, where)
data[lookback + 1, where] = (data[lookback + 1, what] * alpha) + (data[lookback, where] * beta)
for i in range(lookback + 2, len(data)):
try:
data[i, where] = (data[i, what] * alpha) + (data[i - 1, where] * beta)
except IndexError:
pass
return data
How is the MACD calculated? It is the difference between the 26-period exponential moving average applied to the closing price and the 12-period exponential moving average also applied to the closing price. The value found after taking the difference is called the MACD line. The 9-period exponential moving average of that calculation is called the MACD signal.
def macd(Data, what, long_ema, short_ema, signal_ema, where):
Data = adder(Data, 1)
Data = ema(Data, 2, long_ema, what, where)
Data = ema(Data, 2, short_ema, what, where + 1)
Data[:, where + 2] = Data[:, where + 1] - Data[:, where]
Data = jump(Data, long_ema)
Data = ema(Data, 2, signal_ema, where + 2, where + 3)
Data = deleter(Data, where, 2)
Data = jump(Data, signal_ema)
return Data
Creating the Special Divergence
The special divergence technique uses the signal line on the MACD to validate the divergence. Before we talk about the special divergence, let us review what regular divergences are.
Naturally, when prices are rising and making new tops while a price-based indicator is making lower tops, a weakening is occurring and a possibility to change the bias from long to short can present itself. That is what we call a normal divergence. We know that:
When prices are making higher highs while the indicator is making lower highs, it is called a bearish divergence, and the market might stall.
When prices are making lower lows while the indicator is making higher lows, it is called a bullish divergence, and the market might show some upside potential.
The special divergence uses a different approach, here is how:
While below zero, whenever the MACD surpasses its signal line, breaks it while remaining higher than the first trough, and then surpasses it, a special bullish divergence has been seen. Of course, we must not forget the most important condition, which is the market price making lower prices between the two troughs.
While above zero, whenever the MACD breaks its signal line, surpasses it while remaining lower than the first top, and then breaks it, a special bearish divergence has been seen. Of course, we must not forget the most important condition, which is the market price making higher prices between the two tops.
my_data = macd(my_data, 3, 26, 12, 9, 4)
The above graph shows the S&P500 hourly data with the MACD. We will be creating the special divergence function that is tasked with finding these divergences.
The idea is to generate a signal on the close bar whenever the divergence is validated. It is known that it can be an early trend exhaustion detector but of course, no measure is perfect.
width = 40
def special_divergence(data, macd_line, macd_signal, width, buy, sell):
data = adder(data, 2)
for i in range(len(data)):
try:
if data[i, macd_line] < data[i, macd_signal] and data[i, macd_signal] < 0:
for a in range(i + 1, i + width):
if data[a, macd_line] > data[a, macd_signal]:
for r in range(a + 1, a + width):
if data[r, macd_line] < data[r, macd_signal] and \
data[r, macd_line] > data[i, macd_line] and data[r, 3] < data[i, 3]:
for s in range(r + 1, r + width):
if data[s, macd_line] > data[s, macd_signal]:
data[s, buy] = 1
break
else:
break
else:
break
else:
break
else:
break
except IndexError:
pass
for i in range(len(data)):
try:
if data[i, macd_line] > data[i, macd_signal] and data[i, macd_signal] > 0:
for a in range(i + 1, i + width):
if data[a, macd_line] < data[a, macd_signal]:
for r in range(a + 1, a + width):
if data[r, macd_line] > data[r, macd_signal] and \
data[r, macd_line] < data[i, macd_line] and data[r, 3] > data[i, 3]:
for s in range(r + 1, r + width):
if data[s, macd_line] < data[s, macd_signal]:
data[s, sell] = -1
break
else:
break
else:
break
else:
break
else:
break
except IndexError:
pass
return data
So there it is, the special divergence deals with the relative position of the indicator to its moving average rather than upper and lower barriers.
If you are also interested by more technical indicators and strategies, then my book might interest you:
Conclusion
Remember to always do your back-tests. You should always believe that other people are wrong. My indicators and style of trading may work for me but maybe not for you.
I am a firm believer of not spoon-feeding. I have learnt by doing and not by copying. You should get the idea, the function, the intuition, the conditions of the strategy, and then elaborate (an even better) one yourself so that you back-test and improve it before deciding to take it live or to eliminate it. My choice of not providing specific Back-testing results should lead the reader to explore more herself the strategy and work on it more.
To sum up, are the strategies I provide realistic? Yes, but only by optimizing the environment (robust algorithm, low costs, honest broker, proper risk management, and order management). Are the strategies provided only for the sole use of trading? No, it is to stimulate brainstorming and getting more trading ideas as we are all sick of hearing about an oversold RSI as a reason to go short or a resistance being surpassed as a reason to go long. I am trying to introduce a new field called Objective Technical Analysis where we use hard data to judge our techniques rather than rely on outdated classical methods.
One Last Word
I have recently started an NFT collection that aims to support different humanitarian and medical causes. The Society of Light is a set of limited collectibles which will help make the world slightly better as each sale will see a percentage of it sent directly to the charity attributed to the avatar. As I always say, nothing better than a bullet list to outline the benefits of buying these NFT’s:
High-potential gain: By concentrating the remaining sales proceedings on marketing and promoting The Society of Light, I am aiming to maximize their value as much as possible in the secondary market. Remember that trading in the secondary market also means that a portion of royalties will be donated to the same charity.
Art collection and portfolio diversification: Having a collection of avatars that symbolize good deeds is truly satisfying. Investing does not need to only have selfish needs even though there is nothing wrong with investing to make money. But what about investing to make money, help others, and collect art?
Donating to your preferred cause(s): This is a flexible way of allocating different funds to your charities.
A free copy of my book in PDF: Any buyer of any NFT will receive a free copy of my latest book shown in the link of the article.