How to identify Japanese candlesticks patterns in Python | by Gianluca Malato | Towards Data Science

Japanese candlesticks are one of the most important tools for a discretionary or quantitative trader. They are the first example of a particular trading style called price action.
Let’s see what they are and how they can be used in Python.
Note from Towards Data Science’s editors: While we allow independent authors to publish articles in accordance with our rules and guidelines, we do not endorse each author’s contribution. You should not rely on an author’s works without seeking professional advice. See our Reader Terms for details.
Japanese candlesticks are a particular chart type. For each time period, they show the maximum, the minimum, the opening and the closing price.
Let’s see an example chart:
Each day is represented by a symbol called candle. Each candle is made by a real body, an upper shadow and a lower shadow.
Candles have a color. They are usually white, green or blue if the close price is greater than the open price (bullish candle). They are black or red if the close price is lower than the open price (bearish candle).
This kind of chart is very useful because it gives us a lot of information in a simple symbol, but the most important use is related to patterns. Patterns are a combination of candles that show a particular graphical shape and they are useful to spot price reversals. Let’s see some of them.
Here follows a list of the most common patterns with the Python code that lets us identify them.
You can find the whole code in my GitHub repository here: https://github.com/gianlucamalato/machinelearning/blob/master/Candlesticks.ipynb
First, we must install yfinance library to download market data.
!pip install yfinance
Then we can import pandas and finance.
import pandas as pdimport yfinance
For this example, we’re going to use S&P 500 daily data of the last 5 months.
ticker = yfinance.Ticker("SPY")df = ticker.history(period = '5mo')
Now we are going to create as many columns as the patterns, each with a boolean value that is True if the pattern occurs and false if it doesn’t.
So, we have to scan among the historical data. We’re going to use a for loop. We calculate the real body width and the candle range.
for i in range(2,df.shape[0]):  current = df.iloc[i,:]  prev = df.iloc[i-1,:]  prev_2 = df.iloc[i-2,:]  realbody = abs(current['Open'] - current['Close'])  candle_range = current['High'] - current['Low']  idx = df.index[i]
Let’s now see some patterns and their code, that must be included inside the for loop.
Bullish swing is a simple 3-candle pattern. The second candle has the lowest low among the three. The color of the candles is irrelevant. It’s a signal that spots a possible bullish rally of the price.
So, the code is, simply:
df.loc[idx,'Bullish swing'] = current['Low'] > prev['Low'] and prev['Low'] < prev_2['Low']
A bearish swing is the opposite of a bullish swing. It’s made of 3 candles and the second candle has the highest high. The color of the candles is irrelevant.
And here’s the code:
df.loc[idx,'Bearish swing'] = current['High'] < prev['High'] and prev['High'] > prev_2['High']
Pin bars are very frequent and powerful patterns. It’s commonly known that a pin bar has a very long shadow and a small real body. It’s very important to point that a pin bar is not only such a candle, but it must protrude from the surrounding price action. So, a bullish pin bar must have a lower low with respect to the previous candle.
We can define a “small” real body as a real body whose width is less than the candle range divided by 3. A bullish pin bar will then have the real body located in the upper half of the candle. The color of the candle is irrelevant.
Here’s the code of the bullish pin bar:
df.loc[idx,'Bullish pinbar'] = realbody <= candle_range/3 and  min(current['Open'], current['Close']) > (current['High'] + current['Low'])/2 and current['Low'] < prev['Low']
The bearish pin bar is just like the bullish pin bar, but the real body is now located in the lower half of the candle and it has a higher high than the previous candle.
Here’s the code:
df.loc[idx,'Bearish pinbar'] = realbody <= candle_range/3 and max(current['Open'] , current['Close']) < (current['High'] + current['Low'])/2 and current['High'] > prev['High']
Inside bar is a pattern made by two candles. The second candle is entirely included in the range of the first candle. The color is irrelevant.
This pattern shows a contraction in volatility that may be a prelude to a strong directional explosion.
Here’s the code:
df.loc[idx,'Inside bar'] = current['High'] < prev['High'] and current['Low'] > prev['Low']
The outside bar is the opposite of the inside bar. The candle range includes the previous candle entirely.
Here’s the code:
df.loc[idx,'Outside bar'] = current['High'] > prev['High'] and current['Low'] < prev['Low']
Bullish engulfing is a strong bullish pattern. It’s an outside bar with a huge, bullish real body. We can define a “huge” as a real body whose width takes more than 80% of the candle range.
Here’s the code:
df.loc[idx,'Bullish engulfing'] = current['High'] > prev['High'] and current['Low'] < prev['Low'] and realbody >= 0.8 * candle_range and current['Close'] > current['Open']
Bearish engulfing is the opposite of bullish engulfing. A huge, bearish candle engulfs the previous candle completely.
Here’s the code:
df.loc[idx,'Bearish engulfing'] = current['High'] > prev['High'] and current['Low'] < prev['Low'] and realbody >= 0.8 * candle_range and current['Close'] < current['Open']
Here follows the complete code. Remember that we have to fill blanks with False.
for i in range(2,df.shape[0]):  current = df.iloc[i,:]  prev = df.iloc[i-1,:]  prev_2 = df.iloc[i-2,:]realbody = abs(current['Open'] - current['Close'])  candle_range = current['High'] - current['Low']idx = df.index[i]    # Bullish swing  df.loc[idx,'Bullish swing'] = current['Low'] > prev['Low'] and prev['Low'] < prev_2['Low']# Bearish swing  df.loc[idx,'Bearish swing'] = current['High'] < prev['High'] and prev['High'] > prev_2['High']# Bullish pinbar  df.loc[idx,'Bullish pinbar'] = realbody <= candle_range/3 and  min(current['Open'], current['Close']) > (current['High'] + current['Low'])/2 and current['Low'] < prev['Low']# Bearish pinbar  df.loc[idx,'Bearish pinbar'] = realbody <= candle_range/3 and max(current['Open'] , current['Close']) < (current['High'] + current['Low'])/2 and current['High'] > prev['High']      # Inside bar  df.loc[idx,'Inside bar'] = current['High'] < prev['High'] and current['Low'] > prev['Low']      # Outside bar  df.loc[idx,'Outside bar'] = current['High'] > prev['High'] and current['Low'] < prev['Low']    # Bullish engulfing  df.loc[idx,'Bullish engulfing'] = current['High'] > prev['High'] and current['Low'] < prev['Low'] and realbody >= 0.8 * candle_range and current['Close'] > current['Open']# Bearish engulfing  df.loc[idx,'Bearish engulfing'] = current['High'] > prev['High'] and current['Low'] < prev['Low'] and realbody >= 0.8 * candle_range and current['Close'] < current['Open']df.fillna(False, inplace=True)
Our data frame will finally look like this:
Filtering the rows according to the value of the columns will make us backtest any trading strategy that uses such patterns.
Japanese candlesticks patterns are very useful for spotting trend reversals. There are many different patterns that have not been described in this article, but here you can find the most important patterns. A Python implementation of such patterns can be very useful to anybody who wants to start the adventure of algorithmic trading.