How to Implement the Engulfing Candle Strategy on Coinbase with Python
Coinbase Crypto Trading Bot
Welcome!
I’ve been writing a series on how to use Python to analyze Coinbase data. In previous episodes, I’ve demonstrated how to:
- Set up a project to securely import your Coinbase keys
- Retrieve data from Coinbase
- Detect Bearish Engulfing Patterns and Bullish Engulfing Patterns
In this episode, I’ll show you how to integrate these detections into a cohesive trading strategy.
About the Series
In this series, I show you how to build your own crypto trading bot.
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.
By The End of This Episode
You’ll be generating trading signals based on the Engulfing Pattern!
From Indicator To Automated Trading Strategy
Strategy Construction
A strategy is a combination of two factors:
- An indicator or indicators which identify a predicted price movement
- A predicted trade signal that allows you to maximize the profit from a price movement and minimize the risk if the prediction is incorrect
There are thousands (maybe millions) of different combinations of indicators and predicted trade signals. As you develop expertise in markets and quantitative analysis, you’ll probably develop your own.
Breaking this down into high-level requirements, we could state that our strategy must:
- Automatically detect specified indicator(s)
- Automatically generate trade signals with their associated Take Profit, Stop Loss, and Entry prices
The Engulfing Candle Strategy
In this series, we’ll be implementing the Engulfing Candle Strategy. This is a well-known, well-documented strategy, which states the following:
- If a bullish engulfing pattern is detected, create a trade signal with the following values: Buy Stop = Green Candle High, Stop Loss = Green Candle Low, Take Profit = 1:1 Win
- If a bearish engulfing pattern is detected, create a trade signal with the following values: Sell Stop = Red Candle Low, Stop Loss = Red Candle High, Take Profit = 1:1 Win
- The strategy is most effective at higher timeframes (i.e. Daily)
The series has already covered how to detect our modified bullish engulfing pattern and bearish engulfing pattern, so now we can focus on converting our indicators into signals.
Let’s Code
Let’s convert our requirements and strategy into code.
Create engulfing_candle_strategy.py
I’ll start by creating a file called strategy_one.py
in the folder strategies. This file will respond to detected engulfing patterns and output the trade signal.
In the file, add the following code:
# Function to respond to engulfing candle detections and turn them into a strategy
def engulfing_candle_strategy(high, low, symbol, timeframe, exchange, alert_type, project_settings):
"""
Function to respond to engulfing candle detections and turn them into a strategy
:param high: float
:param low: float
:param symbol: string
:param timeframe: string
:param exchange: string
:param alert_type: string
:param project_settings: json dictionary object
:return:
"""
# Only apply strategy to specified timeframes
if timeframe == "M15" or timeframe == "M30" or timeframe == "H1" or timeframe == "D1":
# Respond to bullish_engulfing
if alert_type == "bullish_engulfing":
# Set the Trade Type
trade_type = "BUY"
# Set the Take Profit
take_profit = high + high - low
# Set the Buy Stop
entry_price = high
# Set the Stop Loss
stop_loss = low
elif alert_type == "bearish_engulfing":
# Set the Trade Type
trade_type = "SELL"
# Set the Take Profit
take_profit = low - high + low
# Set the Sell Stop
entry_price = low
# Set the Stop Loss
stop_loss = high
# Print the result to the screen
print(f"Trade Signal Detected. Symbol: {symbol}, Trade Type: {trade_type}, Take Profit: {take_profit}, "
f"Entry Price: {entry_price}, Stop Loss: {stop_loss}, Exchange: {exchange}")
P.S. if you’re wondering about the exchange
variable in this function, this is to make our code as extensible as possible. This will allow us to use different exchanges in the future, each of which has its own methods of interacting.
Update the Bullish Engulfing Detection
Let’s return to the bullish_engulfing
function from episode 3. The function needs to be updated to pass its results to engulfing_candle_strategy
. Update it as follows:
- Add in the import statement
from strategies import engulfing_candle_strategy
- Add two variables into the function declaration:
exchange
andproject_settings
- Above the line
return True
add this code block:
strategy = engulfing_candle_strategy.engulfing_candle_strategy(
high=most_recent_candle['high'],
low=most_recent_candle['low'],
symbol=most_recent_candle['symbol'],
timeframe=most_recent_candle['timeframe'],
exchange=exchange,
alert_type="bullish_engulfing",
project_settings=project_settings
)
The full code for bullish_engulfing.py
should now look like this:
from indicators import ema_calculator
from strategies import engulfing_candle_strategy
# Function to calculate bullish engulfing pattern
def calc_bullish_engulfing(dataframe, exchange, project_settings):
"""
Function to calculate if a bullish engulfing candle has been detected
:param dataframe: Pandas dataframe of candle data
:param exchange: string
:param project_settings: JSON data object
: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]
# Compare the EMA and Red Low
if ema_second_most_recent['close'] < ema_second_most_recent['ema_20']:
strategy = engulfing_candle_strategy.engulfing_candle_strategy(
high=most_recent_candle['high'],
low=most_recent_candle['low'],
symbol=most_recent_candle['symbol'],
timeframe=most_recent_candle['timeframe'],
exchange=exchange,
alert_type="bullish_engulfing",
project_settings=project_settings
)
return True
return False
Update the Bearish Engulfing Detection
The bearish_engulfing
function also needs updating. Update it as follows:
- Add in the import statement
from strategies import engulfing_candle_strategy
- Add two variables into the function declaration:
exchange
andproject_settings
- Above the line
return True
add this code block:
strategy = engulfing_candle_strategy.engulfing_candle_strategy(
high=most_recent_candle['high'],
low=most_recent_candle['low'],
symbol=most_recent_candle['symbol'],
timeframe=most_recent_candle['timeframe'],
exchange=exchange,
alert_type="bearish_engulfing",
project_settings=project_settings
)
The full code for bearish_engulfing.py
should now look like this:
from indicators import ema_calculator
from strategies import engulfing_candle_strategy
# Function to calculate bearish engulfing pattern
def calc_bearish_engulfing(dataframe, exchange, project_settings):
"""
Function to detect a bearish engulfing pattern
:param dataframe: Pandas dataframe of candle data
:param exchange: string
:param project_settings: JSON data object
: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']:
strategy = engulfing_candle_strategy.engulfing_candle_strategy(
high=most_recent_candle['high'],
low=most_recent_candle['low'],
symbol=most_recent_candle['symbol'],
timeframe=most_recent_candle['timeframe'],
exchange=exchange,
alert_type="bearish_engulfing",
project_settings=project_settings
)
return True
return False
Update main.py
Finally, let’s update main.py
to include the two extra variables we added to each function.
Here’s what it should look like (only update __main__
):
# 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(
dataframe=candlestick_data,
exchange="coinbase",
project_settings=project_settings
)
print(f"Bullish Engulfing Check: {bullish_engulfing_check}")
bearish_engulfing_check = bearish_engulfing.calc_bearish_engulfing(
dataframe=candlestick_data,
exchange="coinbase",
project_settings=project_settings
)
print(f"Bearish Engulfing Check: {bearish_engulfing_check}")
If you press play now, you may see something cool happen. If an engulfing pattern has occurred, you should see your screen update with some recommended trade values!
In Conclusion
Many traders would be happy with the code developed so far. We can successfully retrieve historic price data and analyze it according to our strategy.
Where’s the STOP LOSS and TAKE PROFIT?
More advanced traders will now want to automate the placing and canceling of trades. Unfortunately for us, Coinbase Pro (the retail edition) doesn’t offer some of the features we need for this, including the addition of a STOP LOSS, TAKE PROFIT, or TRAILING STOP.
I’ll keep an eye on the Coinbase Pro API for when these become available.
Ongoing Monitoring
Followers of my other tutorials will know that I typically include methods to detect when new candles arrive. This allows you to set your trading bot into ‘Auto-Mode’.
Unfortunately, Coinbase specifically calls out not using their API to poll for new candles. Therefore, in order to monitor for new candles, we would need to implement a socket.
I’ve made the decision, that along with the lack of STOP LOSS and TAKE PROFIT deficiencies, a separate series will be needed to cover all the items.
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.
❤