Fractals & Trading— The Full Guide.
Creating & Evaluating the Fractals Overlay Indicator in Python.
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 just published a new book after the success of my previous one “New Technical Indicators in Python”. It features a more complete description and addition of structured 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.
The Book of Trading Strategies
Amazon.com: The Book of Trading Strategies: 9798532885707: Kaabar, Sofien: Books www.amazon.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 many 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)
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 programs.
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:
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:
New Technical Indicators in Python
Amazon.com: New Technical Indicators in Python: 9798711128861: Kaabar, Mr Sofien: Bookswww.amazon.com
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 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.