How to Identify Engulfing Candles on Coinbase With Python
Coinbase Crypto Trading Bot
Algorithmic trading can be a great way to improve your day-trading outcomes. Many traders have reported that the use of algorithmic decision-making tools/strategies has improved their ability to remove emotion from decisions and identify higher-return outcomes. Note. This is not a guarantee, it is still trading at your own risk 😊
Implementing these analysis techniques can be quite a herculean task. It can be quite daunting! If that’s you, I hope this article helps ❤
About the Series
In this series, I show you how to build your own crypto trading bot to detect a market signal.
The series uses Python 3 to connect to Coinbase, then implements a modified version of the well-known Engulfing Candle Trading Strategy. Throughout the project, I show you how to set up your project in a way that makes it easy to expand with your own ideas and strategies in the future.
All code for the series can be found on the project GitHub. Each episode has working code samples you can copy and paste straight into your own crypto trading bot.
In This Episode
By the end of this episode, you’ll be able to use Coinbase candle data to identify a modified version of Bullish Engulfing and Bearish Engulfing candles. This forms the basis of the Engulfing Candle Strategy.
About Engulfing Candles
Engulfing candles are a two-candle pattern that can be used to identify market reversals. There are two major types of engulfing candle patterns:
- Bullish Engulfing — used to identify a potential upturn in the market
- Bearish Engulfing — used to identify a potential downturn in the market
Identifying a Bullish Engulfing Pattern
The bullish engulfing pattern can be identified when a ‘Red’ candle (downwards) is immediately followed by a ‘Green’ candle (upwards). The body of the Green candle must be larger than that of the Red, and the Green ‘high’ must be greater than the Red ‘high’
Identifying a Bearish Engulfing Pattern
The bearish engulfing pattern is pretty much the opposite. It occurs when a Green candle is immediately followed by a Red candle, where the body of the Red candle is larger than the body of the Green candle, and the Red ‘low’ is lower than the Green ‘low’.
Paired Together
When paired together, these patterns are thought to identify the ‘highs’ and ‘lows’ of market points. In an ideal world, it would mean that you’re able to effectively ‘Buy’ when the market is bullish and ‘Sell’ when the market is bearish.
While real-life trading is never able to guarantee theoretical outcomes, the pattern can often be quite useful.
The 20-EMA Twist
For our crypto trading bot, we’ll be adding an extra market indicator to (hopefully) make our bullish engulfing candle and bearish engulfing candles more valid.
To do this, we’ll add the 20-EMA, or Exponential Moving Average. Using Python and Pandas, we’ll add a dynamic 20-EMA value, then test it against the respective high and low values of the engulfing candles as follows:
- Bullish engulfing: the previous Red close must be above the 20-EMA
- Bearish engulfing: the previous Green close must be below the 20-EMA
So let’s do it.
20-EMA
About the EMA
An EMA is a weighted moving average that provides insight into the dominant trend of a stock over a defined period. EMA’s come in a variety of sizes, with popular choices being the 20-Day EMA, 50-Day EMA, and 200-EMA. Many traders use the EMA to help set parameters around their trade, such as Take Profits, Stop Losses, and many others.
For our crypto trading bot, we’ll use the EMA to confirm an engulfing pattern is moving in the direction indicated.
How to Code
We want to make our code base super extensible. This allows you to build your own custom patterns and identifications on top of what I’ve provided. It also helps your code be simpler to understand.
One way to do this is by making our functions generic first, specialized later.
Given the wide variety of EMA’s used in quantitative analysis, a generalized EMA function would be super helpful! Let’s develop a function that takes a Pandas Dataframe and uses it to calculate an EMA. To do this:
- Navigate to your indicators folder from Episode 1
- Create a file called
ema_calculator
- Insert the following code:
import pandas
# Define function to calculate an arbitrary EMA
def calc_ema(dataframe, ema_size):
# Create column string
ema_name = "ema_" + str(ema_size)
# Create the multiplier
multiplier = 2/(ema_size + 1)
# Calculate the initial value (SMA)
initial_mean = dataframe['close'].head(ema_size).mean()
# Iterate through Dataframe
for i in range(len(dataframe)):
# If i equals the ema_size, substitute the first value (SMA)
if i == ema_size:
dataframe.loc[i, ema_name] = initial_mean
# For subsequent values, use the previous EMA value to calculate the current row EMA
elif i > ema_size:
ema_value = dataframe.loc[i, 'close'] * multiplier + dataframe.loc[i-1, ema_name]*(1-multiplier)
dataframe.loc[i, ema_name] = ema_value
# Input a value of zero
else:
dataframe.loc[i, ema_name] = 0.00
# Once loop completed, return the updated dataframe
return dataframe
Note. The size of the dataframe you pass to this function can drastically impact the compute time/accuracy. In my testing, a dataframe length of 1000 rows takes about 0.25 seconds, whereas 50,000 rows took around 5 minutes. At the same time, the more rows you pass into the function, the more accurate the EMA becomes. My experience is that 1,000 rows are the sweet spot for my calculations, with 300 rows ok for smaller EMAs (<20). Fortunately, Coinbase offers 300 candles as the maximum number of candles provided in a single API request.
Bullish Engulfing Candle
Let’s develop the bullish engulfing detection. You’ll need a function that determines:
- If the previous candle was Red
- If the current candle was Green
- If the body of the Green candle is greater than the Red candle
- If the Green high is greater than the Red high
- (Our secret sauce) If the Red close is below the 20-EMA
As always, we want to generalize the function as much as possible, allowing us to put in any candles, from any exchange, from any timeframe.
To do this:
- Navigate back to the folder indicators
- Add a new file called
bullish_engulfing.py
- Add in the following code:
from indicators import ema_calculator
# Function to calculate bullish engulfing pattern
def calc_bullish_engulfing(dataframe):
"""
Function to calculate if a bullish engulfing candle has been detected
:param dataframe: Pandas dataframe of candle data
:return: Bool
"""
# Extract the most recent candle
len_most_recent = len(dataframe) - 1
most_recent_candle = dataframe.loc[len_most_recent]
# Extract the second most recent candle
len_second_most_recent = len(dataframe) - 2
second_most_recent_candle = dataframe.loc[len_second_most_recent]
# Calculate if second most recent candle Red
if second_most_recent_candle['close'] < second_most_recent_candle['open']:
# Calculate if most recent candle green
if most_recent_candle['close'] > most_recent_candle['open']:
# Check the Green Body > Red Body
# Red Body
red_body = second_most_recent_candle['open'] - second_most_recent_candle['close']
# Green Body
green_body = most_recent_candle['close'] - second_most_recent_candle['open']
# Compare
if green_body > red_body:
# Compare Green High > Red High
if most_recent_candle['high'] > second_most_recent_candle['high']:
# Calculate the 20-EMA
ema_20 = ema_calculator.calc_ema(dataframe=dataframe, ema_size=20)
# Extract the second most recent candle from the new dataframe
ema_count = len(ema_20) - 2
ema_second_most_recent = ema_20.loc[ema_count]
print(ema_second_most_recent)
# Compare the EMA and Red Low
if ema_second_most_recent['close'] < ema_second_most_recent['ema_20']:
return True
return False
Bearish Engulfing Candle
The bearish engulfing candle is pretty much the opposite of the previous function. It determines:
- If the previous candle was Green
- If the current Candle is Red
- If the body of the Red candle > the body of the Green candle
- If the Red low < Green low
- (Our secret sauce) If the Green open > 20-EMA
To do this:
- Add a new file called
bearish_engulfing
in the indicators folder - In this file, add the code below:
from indicators import ema_calculator
# Function to calculate bearish engulfing pattern
def calc_bearish_engulfing(dataframe):
"""
Function to detect a bearish engulfing pattern
:param dataframe: Pandas dataframe of candle data
:return: Bool
"""
# Extract the most recent candle
len_most_recent = len(dataframe) - 1
most_recent_candle = dataframe.loc[len_most_recent]
# Extract the second most recent candle
len_second_most_recent = len(dataframe) - 2
second_most_recent_candle = dataframe.loc[len_second_most_recent]
# Calculate if the second most recent candle is Green
if second_most_recent_candle['close'] > second_most_recent_candle['open']:
# Calculate if most recent candle is Red
if most_recent_candle['close'] < most_recent_candle['open']:
# Check the Red Body > Red Body
# Red Body
red_body = most_recent_candle['open'] - most_recent_candle['close']
# Green Body
green_body = second_most_recent_candle['close'] - second_most_recent_candle['open']
# Compare
if red_body > green_body:
# Compare Red low and Green low
if most_recent_candle['low'] < second_most_recent_candle['low']:
# Calculate the 20-EMA
ema_20 = ema_calculator.calc_ema(dataframe=dataframe, ema_size=20)
# Extract the second most recent candle from the new dataframe
ema_count = len(ema_20) - 2
ema_second_most_recent = ema_20.loc[ema_count]
# Compare 20-EMA and Green Open
if ema_second_most_recent['open'] > ema_second_most_recent['ema_20']:
return True
return False
Run A Check
Lets add these two pattern detections to the __main__
function. To do this, update main as follows (I commented out the account details to speed up execution for this article):
import json
import os
from coinbase_lib import get_account_details, get_candlesticks
from indicators import bullish_engulfing, bearish_engulfing
# Variable for the location of settings.json
import_filepath = "settings.json"
# Function to import settings from settings.json
def get_project_settings(importFilepath):
# Test the filepath to sure it exists
if os.path.exists(importFilepath):
# Open the file
f = open(importFilepath, "r")
# Get the information from file
project_settings = json.load(f)
# Close the file
f.close()
# Return project settings to program
return project_settings
else:
return ImportError
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
# Import project settings
project_settings = get_project_settings(import_filepath)
# Retrieve the account details
# account_details = get_account_details.get_account_details(project_settings=project_settings)
candlestick_data = get_candlesticks.get_candlestick_data("BTC-USDC", "D1")
# Check Bullish Engulfing
bullish_engulfing_check = bullish_engulfing.calc_bullish_engulfing(candlestick_data)
print(f"Bullish Engulfing Check: {bullish_engulfing_check}")
bearish_engulfing_check = bearish_engulfing.calc_bearish_engulfing(candlestick_data)
print(f"Bearish Engulfing Check: {bearish_engulfing_check}")
If you press ‘Play’ on your IDE you should see it print out a True or False for each detection.
Don’t be surprised if both are false — the engulfing pattern occurs infrequently.
What’s Next?
As cool as it is to know that you’re detecting one of the most well-known candle patterns in quantitative analysis, you might wonder: ‘That’s cool, but how do I integrate this into my crypto trading bot? ’
In the next episode, I’ll show you to do just that.
Say Hi!
I love hearing from my readers, so feel free to reach out. It means a ton to me when you clap for my articles or drop a friendly comment — it helps me know that my content is helping.
❤