cft

Innovative Pattern Recognition Using Python — Application on Financial Markets

Applying Market Price Patterns on a New Candlestick Breed.


user

Sofienne Kaabar

3 years ago | 17 min read

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 head and shoulders pattern is a classic technical pattern that signals an imminent trend reversal. We tend to apply the conditions of the patterns on charts. In this article, we will do the same thing but on a different type of charts presented in a previous article, the K’s Candlestick charts.

If you are also interested in more technical indicators and using Python to create strategies, then my latest book may interest you:

Regular Candlesticks

Candlesticks are a quick way to understand OHLC data and detect patterns. It is very straightforward and easy to interpret. A bullish (typically green) candle is when the market closes above its opening price. A bearish (typically red) candle is when the market closes below its opening price.

Let us see a full chart of candlestick to understand more how it is shown. The trend is clearly bullish with some corrections seen around the red candles. Notice the small candles where the opening price is almost the same as the closing price. This is called a Doji and signifies indecision and shows a possible reversal or consolidation.

Example of a candlestick chart on the EURUSD.

def ohlc_plot(Data, window, name):

Chosen = Data[-window:, ]

for i in range(len(Chosen)):

plt.vlines(x = i, ymin = Chosen[i, 2], ymax = Chosen[i, 1], color = 'black', linewidth = 1)

if Chosen[i, 3] > Chosen[i, 0]:
color_chosen = 'green'
plt.vlines(x = i, ymin = Chosen[i, 0], ymax = Chosen[i, 3], color = color_chosen, linewidth = 2) if Chosen[i, 3] < Chosen[i, 0]:
color_chosen = 'red'
plt.vlines(x = i, ymin = Chosen[i, 3], ymax = Chosen[i, 0], color = color_chosen, linewidth = 2)

if Chosen[i, 3] == Chosen[i, 0]:
color_chosen = 'black'
plt.vlines(x = i, ymin = Chosen[i, 3], ymax = Chosen[i, 0], color = color_chosen, linewidth = 2)

plt.grid()
plt.title(name)

The above code plots a candlestick chart as shown. It requires an OHLC data array. The window variable refers to how many observations will be shown in the chart.

If you are interested by market sentiment and how to model the sentiment of institutional traders, feel free to have a look at the below article:

The primal manipulation functions that will be useful for later can be defined as follows:

# 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) return Data# 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

K’s Candlestick Charts

To create the K’s Candlestick chart, we need to transform the prices using the simple moving average formula. The steps are relatively easy:

  • Calculate a 2-period or 3-period Simple Moving Average of the opening price.
  • Calculate a 2-period or 3-period Simple Moving Average of the high price.
  • Calculate a 2-period or 3-period Simple Moving Average of the low price.
  • Calculate a 2-period or 3-period Simple Moving Average of the close price.

Then, we will treat the new four columns as the candlestick data while being careful from using them in trading as they are not real prices, but simple moving averages. We are interested in visually interpreting them and determining candlestick patterns which work better using this technique, particularly, the Doji pattern. The charts below show the difference between the normal candlestick chart and the K’s candlestick chart.

EURUSD: On the above image, the K’s Candlestick chart. On the below image, a normal candlestick chart.

The above charts show the EURUSD charted differently. The period used is 3. We can notice how smoother the K’s candlestick chart is compared to the noisy regular chart. By noisy, the meaning here is on the interpretability of the trend. When successive red or green candles are observed, the trend is easier to be determined.

USDCHF: On the above, the K’s Candlestick chart. On the below, a normal candlestick chart.

The choice of 2 or 3 periods is subjective as I have noticed that they both have good signals. The 2-period is closer to reality and still contain the appropriate number of patterns while keeping the interpretability.

GBPUSD: On the above, the K’s Candlestick chart. On the below, a normal candlestick chart.

It becomes clear that we are interested in two things when analyzing the market using K’s Candlesticks:

  • Interpretability of the trend: Similar to the Heikin-Ashi, the K’s Candlestick chart smoothes out the data in order to remove the short-term noise and to deliver a clearer picture of the current trend.
  • Pattern Recognition: Doji and exhaustion patterns are more prevalent in the K’s candlesticks and therefore add a confirmation factor. They also work better than in regular charts according to my experience.
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 Datadef k_candlesticks(Data, opening, high, low, close, lookback, where):

# Adding the necessary columns
Data = adder(Data, 4)

# Averaging the Open
Data = ma(Data, lookback, opening, where)

# Averaging the High
Data = ma(Data, lookback, high, where + 1)

# Averaging the Low
Data = ma(Data, lookback, low, where + 2)

# Averaging the Close
Data = ma(Data, lookback, close, where + 3)

return Data

Introduction to Pattern Recognition

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 head and shoulders pattern is a classic technical pattern that signals an imminent trend reversal. I encourage you to back-test as much patterns as you can so that you choose the one you are most comfortable. Below, we will take a look at two patterns:

  • Continuation pattern: We will apply the three white soldiers/three black crows candlestick pattern in order to confirm the current trend and ride it.
  • Reversal pattern: We will apply the Fibonacci Timing Pattern on the K’s Candlestick charts. This pattern has been discussed many times in previous articles.

Before we apply them, let us briefly run through their proper definition.

The three white soldiers pattern is a pattern composed of three consecutive bullish candles that typically have their openings within the prior session’s body (and not tails) but this is optional and will be left out as in the currencies market, gaps a less common than in other markets.

The three white soldiers pattern is a bullish continuation based on the pscyhology that the momentum is healthy and strong which signifies the buyers are still in control and that the market is likely to continue higher. Theoretically, we are supposed to buy at the close of the third and last candle to validate the pattern.

The three black crows pattern is a pattern composed of three consecutive bearish candles that typically have their openings within the prior session’s body (and not tails) but this is optional and will be left out as in the currencies market, gaps a less common than in other markets.

The three black crows pattern is a bearish continuation based on the pscyhology that the momentum is healthy and strong which signifies the sellers are still in control and that the market is likely to continue lower. Theoretically, we are supposed to sell short at the close of the third and last candle to validate the pattern.

Our aim is to create an algorithm that detects this pattern. But first, we need to code the intuition of the patterns. Let us review what we will need for the bullish pattern:

  • The three candles must be green (Bullish). Therefore, for each candle, we have to check whether the closing price is greater than the opening price.
  • Each candle must close higher than the previous candle. Therefore, for each candle, we have to check whether the closing price is greater than the previous closing price.
  • Finally, the body of the candle must be big enough to be qualified. Sometimes, we can have a bullish candle but it can be too small to be valid in the pattern. This is done by creating a variable called body where it is the subtraction of the closing price from the opening price. The bigger the body, the less common are the signals but the more the pattern resembles a true pattern. We will choose a body of 5 pips on hourly data.

Similarly, for the bearish three black crows, we need the following conditions:

  • The three candles must be red (Bearish). Therefore, for each candle, we have to check whether the closing price is lower than the opening price.
  • Each candle must close lower than the previous candle. Therefore, for each candle, we have to check whether the closing price is lower than the previous closing price.
  • Finally, the body of the candle must be big enough to be qualified. Sometimes, we can have a bearish candle but it can be too small to be valid in the pattern. This is done by creating a variable called body where it is the subtraction of the closing price from the opening price. The bigger the body, the less common are the signals but the more the pattern resembles a true pattern. We will choose a body of 5 pips on hourly data.
Signal chart that detects the pattern on the USDCHF.
Signal chart that detects the pattern on the USDCHF.
# Defining the minimum width of the candle
body = 0.0005def signal(Data, body):

for i in range(len(Data)):

# Three White Soldiers
if Data[i, 3] > Data[i, 0] and (Data[i, 3] - Data[i, 0]) >= body and Data[i, 3] > Data[i - 1, 3] and Data[i - 1, 3] > Data[i - 1, 0] and (Data[i - 1, 3] - Data[i - 1, 0]) >= body and Data[i - 1, 3] > Data[i - 2, 3] and Data[i - 2, 3] > Data[i - 2, 0] and (Data[i - 2, 3] - Data[i - 2, 0]) >= body and Data[i - 2, 3] > Data[i - 3, 3]:

Data[i, 6] = 1

# Three Black Crows
if Data[i, 3] < Data[i, 0] and (Data[i, 0] - Data[i, 3]) >= body and Data[i, 3] < Data[i - 1, 3] and Data[i - 1, 3] < Data[i - 1, 0] and (Data[i - 1, 0] - Data[i - 1, 3]) >= body and Data[i - 1, 3] < Data[i - 2, 3] and Data[i - 2, 3] < Data[i - 2, 0] and (Data[i - 2, 0] - Data[i - 2, 3]) >= body and Data[i - 2, 3] < Data[i - 3, 3]:

Data[i, 7] = -1

The Fibonacci Timing Pattern combines time, price, and the Fibonacci sequence in order to show whether they provide reversal points or not. Here is the basic intuition:

  • For a bullish Fibonacci Timing Pattern, we need 8 closes where each close is lower than the close 5 periods ago, lower than the close 3 periods ago, and lower than the close 1 period ago. Upon the completion of this pattern, we will have a bullish signal. Any interruption in the sequence will invalidate the pattern.
  • For a bearish Fibonacci Timing Pattern, we need 8 closes where each close is higher than the close 5 periods ago, higher than the close 3 periods ago, and higher than the close 1 period ago. Upon the completion of this pattern, we will have a bearish signal. Any interruption in the sequence will invalidate the pattern.

If you are interested in seeing more technical indicators and back-test, feel free to check out the below article:

GBPUSD signal chart following the identification of the Fibonacci Timing Pattern.
GBPUSD signal chart following the identification of the Fibonacci Timing Pattern.
def fibonacci_timing_pattern(Data, count, step, step_two, step_three, close, buy, sell):

# Bullish Fibonacci Timing Pattern
counter = -1for i in range(len(Data)):
if Data[i, close] < Data[i - step, close] and \
Data[i, close] < Data[i - step_two, close] and \
Data[i, close] < Data[i - step_three, close]:

Data[i, buy] = counter
counter += -1

if counter == -count - 1:
counter = 0
else:
continue

elif Data[i, close] >= Data[i - step, close]:
counter = -1
Data[i, buy] = 0

# Bearish Fibonacci Timing Pattern
counter = 1

for i in range(len(Data)):
if Data[i, close] > Data[i - step, close] and \
Data[i, close] > Data[i - step_two, close] and \
Data[i, close] > Data[i - step_three, close]:

Data[i, sell] = counter
counter += 1
if counter == count + 1:
counter = 0
else:
continue

elif Data[i, close] <= Data[i - step, close]:
counter = 1
Data[i, sell] = 0

return Data# Using the function
count = 8
step = 5
step_two = 3
step_three = 2
my_data = fibonacci_timing_pattern(my_data, count, step, step_two, step_three, 3, 6, 7)

Application of the Patterns on K’s Candlestick Charts

The first way is to try to apply the candlestick pattern on the K’s Candlestick charts. We can assume that the function of the chart has been applied. The next step is to apply the following function of the pattern:

# Defining the minimum width of the candle 
body = 0.0007 # An arbitrary 7 pips for hourly OHLC datadef signal(Data, body): # Assuming index 5 harbors the open price of the K's Candles
# Assuming index 8 harbors the close price of the K's Candles Data = adder(Data, 10)

for i in range(len(Data)):

# Three White Soldiers
if Data[i, 8] > Data[i, 5] and (Data[i, 8] - Data[i, 5]) >= body and Data[i, 8] > Data[i - 1, 8] and Data[i - 1, 8] > Data[i - 1, 5] and (Data[i - 1, 8] - Data[i - 1, 5]) >= body and Data[i - 1, 8] > Data[i - 2, 8] and Data[i - 2, 8] > Data[i - 2, 5] and (Data[i - 2, 8] - Data[i - 2, 5]) >= body and Data[i - 2, 8] > Data[i - 3, 8] \
and Data[i - 1, 9] == 0:

Data[i, 9] = 1

# Three Black Crows
if Data[i, 8] < Data[i, 5] and (Data[i, 5] - Data[i, 8]) >= body and Data[i, 8] < Data[i - 1, 8] and Data[i - 1, 8] < Data[i - 1, 5] and (Data[i - 1, 5] - Data[i - 1, 8]) >= body and Data[i - 1, 8] < Data[i - 2, 8] and Data[i - 2, 8] < Data[i - 2, 5] and (Data[i - 2, 5] - Data[i - 2, 8]) >= body and Data[i - 2, 8] < Data[i - 3, 8] \
and Data[i - 1, 10] == 0:

Data[i, 10] = -1

return Data# Using the function
my_data = signal(my_data, body)
Signal chart on the EURUSD — Three Soldiers & Crows.
Signal chart on the EURUSD — Three Soldiers & Crows.

The second way is to apply the Fibonacci Timing Pattern. The signal charts shown in this section are the K’s candlestick charts but the arrows are placed in the true price area. This means that the arrow is placed on the real price (regular candlestick) but the chart shown is the K’s Candlestick chart which is as shown, a simple transformation using moving averages.

Signal chart on the EURUSD — Fibonacci Timing Pattern.
Signal chart on the EURUSD — Fibonacci Timing Pattern.

The code to do this is simple, we have to basically select the closing price indexed at 8 in the pattern’s function. As a contrarian pattern, it seems deliver better signals than the first continuation patterns. Back-testing is left at the discretion of the reader so that no bias is presented.

Signal chart on the GBPCHF — Fibonacci Timing Pattern.
Signal chart on the GBPCHF — Fibonacci Timing Pattern.

The way to use the pattern is to simply assume that it occurs around corrections or small reactions. It is hard to say that the pattern delivers extreme reversals unless tested using solid statistical tests on a huge number of markets.

Signal chart on the EURCHF — Fibonacci Timing Pattern.
Signal chart on the EURCHF — Fibonacci Timing Pattern.

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. That way you can share with me your better strategy and we will get rich together.

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.

Upvote


user
Created by

Sofienne Kaabar

FX Trader | Author of the Book of The Book of Back-Tests


people
Post

Upvote

Downvote

Comment

Bookmark

Share


Related Articles