As an Amazon Associate I earn from qualifying purchases.
Candlestick patterns can be a great way of deciding if and when we should open or close a trade. For example, if we get a ‘hammer’ candlestick, this is usually a bullish sign. Paired with a moving average, this can be a powerful strategy. Let’s have a look at how we can detect candlestick patterns using TA-Lib and Python with the algorithmic trading bot.
For this tutorial, I will be using the hammer candlestick as an example. A full list of detectable candlestick patterns can be found here.
Adding candlestick patterns as constants
In TA-lib, candlestick patterns are functions that usually take the following form: CANDLESTICK(open, high, low, close). To reference these candlestick functions in our strategy (strategy.json
), I found it best to add all the candlestick functions to a dictionary in constants.py
using lambda expressions
Add the following code to constants.py
:
cs_patterns = {
'hammer' : lambda openP, high, low, close: ta.CDLHAMMER(openP, high, low, close),
'closingMarubozu' : lambda openP, high, low, close: ta.CDLCLOSINGMARUBOZU(openP, high, low, close),
'doji' : lambda openP, high, low, close: ta.CDLDOJI(openP, high, low, close),
'engulfing' : lambda openP, high, low, close: ta.CDLENGULFING(openP, high, low, close),
'hangingMan' : lambda openP, high, low, close: ta.CDLHANGINGMAN(openP, high, low, close),
'hammer' : lambda openP, high, low, close: ta.CDLHAMMER(openP, high, low, close),
'invertedHammer' : lambda openP, high, low, close: ta.CDLINVERTEDHAMMER(openP, high, low, close),
'marubozu' : lambda openP, high, low, close: ta.CDLMARUBOZU(openP, high, low, close),
'beltHold': lambda openP, high, low, close: ta.CDLBELTHOLD(openP, high, low, close),
'breakaway' : lambda openP, high, low, close: ta.CDLBREAKAWAY(openP, high, low, close),
'inNeck' : lambda openP, high, low, close: ta.CDLINNECK(openP, high, low, close),
'kicking': lambda openP, high, low, close: ta.CDLKICKING(openP, high, low, close),
'kickingByLength' : lambda openP, high, low, close: ta.CDLKICKINGBYLENGTH(openP, high, low, close),
'ladderBottom' : lambda openP, high, low, close: ta.CDLLADDERBOTTOM(openP, high, low, close),
'longLeggedDoji' : lambda openP, high, low, close: ta.CDLLONGLEGGEDDOJI(openP, high, low, close),
'longLineCdl' : lambda openP, high, low, close: ta.CDLLONGLINE(openP, high, low, close),
'shortLineCdl' : lambda openP, high, low, close: ta.CDLSHORTLINE(openP, high, low, close),
'rickShawMan' : lambda openP, high, low, close: ta.CDLRICKSHAWMAN(openP, high, low, close),
'spinningTop' : lambda openP, high, low, close: ta.CDLSPINNINGTOP(openP, high, low, close),
'stalled' : lambda openP, high, low, close: ta.CDLSTALLEDPATTERN(openP, high, low, close),
'stickSandwhich' : lambda openP, high, low, close: ta.CDLSTICKSANDWICH(openP, high, low, close),
'takuri' : lambda openP, high, low, close: ta.CDLTAKURI(openP, high, low, close),
'tasukiGap' : lambda openP, high, low, close: ta.CDLTASUKIGAP(openP, high, low, close),
'stalled' : lambda openP, high, low, close: ta.CDLSTALLEDPATTERN(openP, high, low, close),
'thrusting' : lambda openP, high, low, close: ta.CDLTHRUSTING(openP, high, low, close),
}
Using this dictionary, you will now be able to reference and candlestick pattern function by it’s key.
Adding a candlestick pattern to our strategy
In the strategy file, you will want to specify the candlestick pattern key. Add a new key under the movingAverages
key and name it candlestickPattern
. Set the value of this key to hammer
:
{
"accountNumber" : 40461345,
"account_currency" : "USD",
"strategy_name": "myStrategy",
"pairs": [
"EURUSD",
"USDCAD",
"GBPUSD"
],
"risk" : 2,
"maxLosses" : 3,
"takeProfit": 700.0,
"stopLoss": 300.0,
"movingAverages": {
"SMA": {
"val": 10,
"aboveBelow": "below"
},
"EMA": {
"val": 50,
"aboveBelow": "above"
}
},
"candlestickPattern" : "hammer",
"maximumDrawdown" : 0.5,
"initialBalance" : 100000
}
Detecting the candlestick pattern during live trading
The last step is to calculate the current candlestick for the current period and detect if it is the candlestick you are interested in trading. To do this, let’s go back to the check_trades
method in trader.py
. The check_trades
method should look similar to the following:
def check_trades(time_frame, pair_data, strategy):
moving_averages = strategy['movingAverages']
for pair, data in pair_data.items():
for m in moving_averages:
ma_func = constants.movingAveragesFunctions[m]
val = moving_averages [m]['val']
data[m] = ma_func(data['close'], val)
last_row = data.tail(1)
open_positions = positions_get()
current_dt = datetime.now().astimezone(pytz.timezone('Europe/Athens'))
for index, position in open_positions.iterrows():
# Check to see if the trade has exceeded the time limit
trade_open_dt = position['time'].replace(tzinfo = pytz.timezone('Europe/Athens'))
deal_id = position['ticket']
if(current_dt - trade_open_dt >= timedelta(hours = 2)):
close_position(deal_id)
for index, last in last_row.iterrows():
#Exit strategy
if(last['close'] < last['EMA'] and last['close'] > last['SMA']):
close_positon_by_symbol(pair)
lost_trade_count = calc_daily_lost_trades()
if(lost_trade_count > strategy['maxLosses']):
print("Daily losses have been exceeded. Not executing any more trades today")
continue
#Entry strategy
if(last['close'] > last['EMA'] and last['close'] < last['SMA']):
lot_size = calc_position_size(pair, strategy)
open_position(pair, "BUY", lot_size, float (strategy['takeProfit']), float(strategy['stopLoss']))
In the last for loop, you are iterating over the newest tick data for the current period. Just before this loop starts, let’s calculate what kind of candlestick pattern you currently have. Find the corresponding candlestick pattern function by getting the candlestick pattern key defined in your strategy:
candlestick_func = constants.cs_patterns[strategy['candlestickPattern']]
Now, you should call candlestick_func
passing in the open
, high
, low
, close
data from the last_row
data frame and assign the output of this function to last_row['is_cs_pattern']
:
last_row['is_cs_pattern'] = candlestick_func(last_row['open'], last_row['high'], last_row['low'], last_row['close'])
Running the candle stick function will simply give you a boolean TRUE or FALSE if the specified candlestick pattern has been detected or not.
Finally, go to the last loop in the check_trades
method and find this code block:
#Entry strategy
if(last['close'] > last['EMA'] and last['close'] < last['SMA']):
lot_size = calc_position_size(pair, strategy)
open_position(pair, "BUY", lot_size, float (strategy['takeProfit']), float(strategy['stopLoss']))
You will want to modify the if condition to add if the candlestick pattern has been found or not. This can be done as follows:
if(last['close'] > last['EMA'] and last['close'] < last['SMA'] and last['is_cs_pattern']):
Interested in creating your own algo trading bot? Check out my free series on algo trading here: https://www.conorjohanlon.com/category/algotrader/
That’s all for how to Detect candlestick patterns using TA-Lib and Python! As always, if you have any questions or comments please feel free to post them below. Additionally, if you run into any issues please let me know.