Pattern recognition is the search and identification of recurring patterns with approximately similar outcomes. This means that when we manage to find a pattern, we have an expected outcome that we want to see and act on through our trading. For example, a double top/bottom pattern is a classic technical pattern that signals an imminent trend reversal.
The literature differs on the predictive ability of this famous configuration. In this article, we will discuss an objective pattern that can help find breakouts as opposed to reversals. I say objective because it has clear rules unlike the classic patterns such as the head and shoulders and the double top/bottom.
I have released a new book after the success of my previous one “Trend Following Strategies in Python”. It features a lot of advanced contrarian indicators and strategies with a GitHub page dedicated to the continuously updated code. If you are interested, you could buy the PDF version directly through a PayPal payment of 9.99 EUR.
Please include your email in the note before paying so that you receive it on the right address. Also, once you receive it, make sure to download it through google drive.
Pay Kaabar using PayPal.Me
If you accept cookies, we’ll use them to improve and customize your experience and enable our partners to show you…www.paypal.com
Creating the Fractals
The Fractal pattern is a recurring chart configuration consisting of a minimum of five consecutive price bars. An up fractal is where the middle bar is the highest. This means that the middle bar must have a higher high than the two preceding bars and also the two following bars, while a down fractal is where the middle bar is the lowest. This means that the middle bar must have a lower low than the two preceding bars and also the two following bars.
The perfect fractal pattern looks like a V for a down pattern and an inverted V for a down pattern. While other occurrences may happen, the perfect fractal pattern is the preferred one (illustrated below).
It is obvious that this pattern suffers from clear time bias as we can only notice it after two bars have elapsed. This means that since we set a condition that the two next bars must be higher or lower, the completion of the pattern is after the fractal signal which is generally visible on the middle bar.
Fractals can help us with many systematic and discretionary strategies if they are used in conjunction with other indicators. They are also helpful with Elliot Wave analysis in that they can signal the start of a new wave. The plot below makes the last point clearer.
Remember that according to the Elliot wave theory, the market moves impulsively in 5 waves and then corrects the impulse in 3 waves. The fractal pattern is useful in indicating when a certain wave has ended. Notice how after breaking the down fractal of the first wave, the market has accelerated when making the third wave where it is now awaiting the break of the down fractal to confirm the drop to the fifth wave.
Of course, fractals here only play a secondary role as Elliot Wave analysis can use much more than this simplistic approach.
Coding the Fractal Pattern
Let us try to code the pattern in Python. It is a relatively easy task that follows the idea of recursive thinking. We can follow the below steps:
The algorithm loops through the data and if it finds a high that is lower than the high 2 periods ago and if it finds that the previous high is lower than the high 2 periods ago, it should ensure that the high two periods ago is higher than the highs of the two bars that precede it. In a perfect scenario, this should look like an inverted V.
The algorithm loops through the data and if it finds a low that is higher than the low 2 periods ago and if it finds that the previous low is higher than the low 2 periods ago, it should ensure that the low two periods ago is lower than the lows of the two bars that precede it. In a perfect scenario, this should look like a V.
By using the below function, we are able to generate the fractals:
def fractals(Data, high, low, up, down):
# Fractal Up
for i in range(len(Data)):
if Data[i, high] < Data[i - 2, high] and Data[i - 1, high] < Data[i - 2, high] and Data[i - 2, high] > Data[i - 3, high] and Data[i - 2, high] > Data[i - 4, high]:
Data[i - 2, up] = 1
# Fractal Down
for i in range(len(Data)):
if Data[i, low] > Data[i - 2, low] and Data[i - 1, low] > Data[i - 2, low] and Data[i - 2, low] < Data[i - 3, low] and Data[i - 2, low] < Data[i - 4, low]:
Data[i - 2, down] = -1
return Data
The above chart shows the generated fractals on the hourly values of the USDCHF. The upwards pointing arrows are the down fractals while the downwards pointing arrows are the up fractals. There are manys strategies that can be formed using them. Among these strategies is the following one:
Long (Buy) whenever a down fractal is validated. This means that a buy signal is generated two periods after the down fractal appears.
Sell (Short) whenever an up fractal is validated. This means that a sell signal is generated two periods after the up fractal appears.
def signal(Data):
# Bullish Signal
for i in range(len(Data)):
if Data[i - 2, 5] != 0:
Data[i, 6] = 1
# Bearish Signal
for i in range(len(Data)):
if Data[i - 2, 4] != 0:
Data[i, 7] = -1
return Data
The detailed code to create the signals can be summed up as follows.
def adder(Data, times):
for i in range(1, times + 1):
new = np.zeros((len(Data), 1), dtype = float)
Data = np.append(Data, new, axis = 1)
return Data
def deleter(Data, index, times):
for i in range(1, times + 1):
Data = np.delete(Data, index, axis = 1)
return Data
def jump(Data, jump):
Data = Data[jump:, ]
return Data
# Adding Columns
my_data = adder(my_data, 10)
# Applying Fractals
my_data = fractals(my_data, 1, 2, 4, 5)
# Signal Function
my_data = signal(my_data)
Make sure to focus on the concepts and not the code. You can find the codes of most of my strategies in my books. The most important thing is to comprehend the techniques and strategies.
Check out my weekly market sentiment report to understand the current positioning and to estimate the future direction of several major markets through complex and simple models working side by side. Find out more about the report through this link:
Coalescence Report 1st May — 8th May 2022
This report covers the weekly market sentiment and positioning and any changes that have occurred which might present…coalescence.substack.com
Evaluating the Signals
Having had the signals, we now know when the algorithm would have placed its buy and sell orders, meaning, that we have an approximate replica of the past where can can control our decisions with no hindsight bias. We have to simulate how the strategy would have done given our conditions. This means that we need to calculate the returns and analyze the performance metrics. Let us see a neutral metric that can give us somewhat a clue on the predictability of the indicator or the strategy. For this study, we will use the Signal Quality metric.
The signal quality is a metric that resembles a fixed holding period strategy. It is simply the reaction of the market after a specified time period following the signal. Generally, when trading, we tend to use a variable period where we open the positions and close out when we get a signal on the other direction or when we get stopped out (either positively or negatively).
Sometimes, we close out at random time periods. Therefore, the signal quality is a very simple measure that assumes a fixed holding period and then checks the market level at that time point to compare it with the entry level. In other words, it measures market timing by checking the reaction of the market after a specified time period.
# Choosing a Holding Period for a trend-following strategy
period = 13
def signal_quality(Data, closing, buy, sell, period, where):
Data = adder(Data, 1)
for i in range(len(Data)):
try:
if Data[i, buy] == 1:
Data[i + period, where] = Data[i + period, closing] - Data[i, closing]
if Data[i, sell] == -1:
Data[i + period, where] = Data[i, closing] - Data[i + period, closing]
except IndexError:
pass
return Data
# Applying the Signal Quality Function
my_data = signal_quality(my_data, 3, 6, 7, period, 8)
positives = my_data[my_data[:, 8] > 0]
negatives = my_data[my_data[:, 8] < 0]
# Calculating Signal Quality
signal_quality = len(positives) / (len(negatives) + len(positives))
print('Signal Quality = ', round(signal_quality * 100, 2), '%')
# Output Signal Quality EURUSD = 51.04%
# Output Signal Quality USDCHF = 50.02%
# Output Signal Quality GBPUSD = 50.65%
Am I also as disappointed in the fractal patterns as you are? Yes, but I am also glad to know that with these normal parameters, it does not work, maybe more complex strategies can be formed around it. There is probably no value whatsoever in this pattern which explains why it is available in most charting softwares.
Summary
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 a 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.
Hi,
Great article - thanks! I don't understand this statement " There is probably no value whatsoever in this pattern which explains why it is available in most charting softwares." Are you saying there probably is a value and that's why it is available in the software?