Detecting Market Reversals Using a New Technique
Creating a New Strategy to Detect Market Reversals in Python
Combining indicators can be a powerful way to improve performance and to enhance the signals. This article discusses a discretionary strategy which deals with the Bollinger bands and the MACD to generate contrarian signals.
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 Bollinger Bands
Volatility bands are generally composed of two envelopes that cover the market’s price where dynamic support and resistance levels are formed. Generally, volatility bands work well in ranging (Sideways) markets because of the mean-reversion properties. The most famous volatility bands are the Bollinger bands which have paved the way for other variation which have been discussed in previous articles.
The below figure shows an example with a standard Bollinger bands applied onto it. Let us interpret what we see.
The bands are created following these steps:
We need to calculate a 20-period simple moving average on the market price.
We then calculate a 20-period standard deviation of the market price.
To calculate the bands, we multiply the standard deviation values by a multiplier that is generally 2. Finally, we add and subtract the latter calculation to and from the 20-period moving average.
The Bollinger bands are based on the statistical property that states that normally distributed variables should have defined deviations from their mean. Even though financial prices are not normally distributed, we can list the following properties:
About 68% of the data falls within 1 standard deviation of the mean.
About 95% of the data falls within 2 standard deviations of the mean.
About 99% of the data falls within 3 standard deviations of the mean.
The idea of the Bollinger Bands is to form two barriers calculated from a constant multiplied by the rolling Standard Deviation. They are in essence barriers that give out a probability that the market price should be contained within them. The lower Bollinger Band can be considered as a dynamic support while the upper Bollinger Band can be considered as a dynamic resistance. Hence, the Bollinger bands are simple a combination of a moving average that follows prices and a moving standard deviation(s) band that moves alongside the price and the moving average.
To create the Bollinger Bands in Python, we need to define the moving average function, the standard deviation function, and then the Bollinger Bands function which will use the former two functions. Consider an array containing OHLC data. We should define the following primal functions first and then we can code the Bollinger function
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
def volatility(Data, lookback, what, where):
# Adding an extra column
Data = adder(Data, 1)
for i in range(len(Data)):
try:
Data[i, where] = (Data[i - lookback + 1:i + 1, what].std())
except IndexError:
pass
# Cleaning
Data = jump(Data, lookback)
return Data
def bollinger_bands(data, boll_lookback, standard_distance, what, where):
# Adding a few columns
data = adder(data, 2)
# Calculating means
data = ma(data, boll_lookback, what, where)
data = volatility(data, boll_lookback, what, where + 1)
data[:, where + 2] = data[:, where] + (standard_distance * data[:, where + 1])
data[:, where + 3] = data[:, where] - (standard_distance * data[:, where + 1])
data = jump(data, boll_lookback)
data = deleter(data, where, 2)
return data
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.
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.
As a reminder, the MACD line is the difference between the two exponential moving averages which is plotted as histograms in green and red. The MACD signal is simply the 9-period exponential moving average of the MACD line.
def ema(Data, alpha, lookback, what, where):
alpha = alpha / (lookback + 1.0)
beta = 1 - alpha
# First value is a simple SMA
Data = ma(Data, lookback, what, where)
# Calculating first EMA
Data[lookback + 1, where] = (Data[lookback + 1, what] * alpha) + (Data[lookback, where] * beta)
# Calculating the rest of EMA
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
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
If you are also interested by more technical indicators and strategies, then my book might interest you:
Developing the Strategy
The strategy uses a double confirmation factor from both indicators. It may have rare signals depending on the market, but we generally need the following conditions for a trigger:
A long (Buy) signal is generated whenever the MACD line surpasses the signal line while the market’s low is at or below the lower 80-period Bollinger band.
A short (Sell) signal is generated whenever the MACD line breaks the signal line while the market’s high is at or above the upper 80-period Bollinger band.
def signal(data, close, boll_upper, boll_lower, macd_line, signal_line, buy_column, sell_column):
data = adder(data, 2)
for i in range(len(data)):
if data[i, 2] < data[i, boll_lower] and data[i, macd_line] > data[i, signal_line] and \
data[i - 1, macd_line] < data[i - 1, signal_line]:
data[i, buy_column] = 1
elif data[i, 1] > data[i, boll_upper] and data[i, macd_line] < data[i, signal_line] and \
data[i - 1, macd_line] > data[i - 1, signal_line]:
data[i, sell_column] = -1
return data
The signals are because the odds of a market close to its Bollinger extreme while already confirmed the reversal on the MACD are slim. However, this may filter out bad signals.
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.