Using TA-Lib for detecting candle stick patterns in stock-prices

Tobi Lux
8 min readJul 5, 2024

--

Candlesticks are a well-established tool for trading stocks and commodities. In this blog, I aim to show how TA-Lib, a widely recognized library for technical indicators, can be utilized to identify stock patterns. Given that TA-Lib is entirely written in C/C++ and requires in-depth knowledge of these languages to modify, this blog will primarily focus on demonstrating how one might gain at least an understanding of the pattern detection methodology implemented in TA-Lib.

In a forthcoming blog, I will share my findings on the predictive power of candlestick patterns, a contentious topic in the realm of trading.

As usual the code is Available at my GitHub.

Generated with AI support

1. Opening Remarks

I will not detail the workings of candlestick patterns. Should a reader be unfamiliar with the subject, I recommend visiting the pertinent sections of Investopedia, following this (link) for an introduction.

1. Installation of TA-Lib and importing

I use Google Colab as my development environment. Unfortunately, TA-Lib cannot be installed with the usual !pip install talib command. For more details on this topic, please refer to the provided link. The code block below is necessary to install, import and use TA-Lib in the current Colab environment (that is based on Python 3.10) Once Colab’s Environment is updated (e.g. by introducing a higher version of Python), this may change. However, it appears that some contributors regularly update the content of the link, according to recent Colab-updates.

# importing TA-Lib
url = 'https://anaconda.org/conda-forge/libta-lib/0.4.0/download/linux-64/libta-lib-0.4.0-h166bdaf_1.tar.bz2'
!curl -L $url | tar xj -C /usr/lib/x86_64-linux-gnu/ lib --strip-components=1
url = 'https://anaconda.org/conda-forge/ta-lib/0.4.19/download/linux-64/ta-lib-0.4.19-py310hde88566_4.tar.bz2'
!curl -L $url | tar xj -C /usr/local/lib/python3.10/dist-packages/ lib/python3.10/site-packages/talib --strip-components=3
import talib

2. Example of using TA-Lib in candlestick pattern detection

We will use the price data from the German DAX-Index. The prices are downloaded, using the well-known yfinance-library:

# download of data
start, end = '2019-01-01', '2024-07-05'
prices = yf.download('^GDAXI', start=start, end=end)

Once the TA-Lib library is installed, the code below will give you the complete list of candlestick patterns available in TA-Lib:

# showing all availble candle sticks
candle_names = talib.get_function_groups()['Pattern Recognition']
print(candle_names)
print(len(candle_names))

When executed, the snippet yields a list of 61 distinct patterns.

All the TA-Lib-candlestick patterns are also listed in the link.

TA-Lib signals either 100 for a bullish pattern or -100 for a bearish pattern once a specific pattern is recognized. Occasionally, a pattern may return +80, +200, -80, or -200. However, signals other than -100/100 are exceptions, and we will not delve into further details. The key point is:

  • a 0 return: indicates no pattern detected
  • a return of a positive value: indicates a bullish pattern (go LONG or cover SHORT is recommended)
  • a return of a negative value: indicates a bearish pattern (exit LONG or go SHORT.

Taking the HARAMI pattern as an example, the subsequent code will produce TA-Lib signals for the HARAMI pattern and store them in two separate pandas Series, one for bullish and one for bearish signals.

# pattern detction
harami = talib.CDLHARAMI(prices['Open'], prices['High'], prices['Low'], prices['Close'])

# data preparation for plotting
bull_harami_plot = np.where(harami>0, prices.Close,np.nan)
bear_harami_plot = np.where(harami<0, prices.Close,np.nan)

First, we call the CDLHARAMI-function with the OHLC-data in prices as arguments. Next, we filter the results for positive or negative values.

Finally, we plot the DAX chart together with the two series of signals:

# PLotting of Data
title = f'DAX between {start} to {end}'

# plotting
fig = go.Figure()
fig.add_trace(go.Candlestick(x=prices.index, open=prices['Open'], high=prices['High'],
low=prices['Low'], close=prices['Close']))
fig.add_trace(go.Scatter(x=prices.index, y=bull_harami_plot, mode='markers',
name='bull_harami', marker_symbol='triangle-up', marker_color='yellow', marker_size=15))
fig.add_trace(go.Scatter(x=prices.index, y=bear_harami_plot, mode='markers',
name='bear_harami', marker_symbol='triangle-down', marker_color='lightskyblue', marker_size=15))

fig.update_layout(template='plotly_dark', autosize=False, width=1200, height=600)
fig.update_layout(title=title, xaxis_title='date', yaxis_title='prices')
fig.update_layout(xaxis_rangeslider_visible=False)
fig.show()
Fig.1: DAX candlestick with HARAMI patter signals (bullish and bearish)

Our topic is the use of TA-Lib, and thus we plot all signals as generated by the module. In practice, traders will filter these signals before using them in a trading system. Therefore, a bullish signal like our bullish HARAMI should be confirmed by other indicators such as MACD, among others.

4. TA-Lib, a black box?

Some authors label TA-Lib as a “Black Box,” which is only partially correct. TA-Lib is written in C/C++ and is not modifiable within the Python ecosystem. Nevertheless, the source code is accessible for thorough examination. As a result, you can understand precisely what is happening, although, to be fair, altering it is not an option unless you are skilled in C/C++. Hence, TA-Lib cannot be considered a traditional black box.

TA-Lib is open source, and the source code is fully available. Best, you start at the following page: https://sourceforge.net/p/ta-lib/code/HEAD/tree/trunk/

This will access the main directory for the code blocks. You should then navigate deeper into the directory system to:

https://sourceforge.net/p/ta-lib/code/HEAD/tree/trunk/ta-lib/c/src/ta_func/

This directory contains all the C/C++ modules with coded TA-Lib indicator functions. The names of the pattern modules always start with the letters ‘CDL’. By opening a module file with a text editor, the code is made available for inspection.

Let’s examine a practical example. We will inspect the code of the well-known HARAMI pattern. On Investopedia, you will find the corresponding figure for a bearish HARAMI:

Fig. 2: Bearish HARAMI pattern

Also on Investopedia, you will find the following explanations for bearish and bullish HARAMI patterns:

  • A bearish harami is a two bar Japanese candlestick pattern that suggests prices may soon reverse to the downside. The pattern consists of a long white candle followed by a small black candle. The opening and closing prices of the second candle must be contained within the body of the first candle. An uptrend precedes the formation of a bearish harami.
  • The bullish harami indicator is charted as a long candlestick followed by a smaller body, referred to as a doji, that is completely contained within the vertical range of the previous body. To some, a line drawn around this pattern resembles a pregnant woman. The word harami comes from an old Japanese word meaning pregnant.

The code for the HARAMI indicator can be found in a file named CDLHARAMI.c. When you open this file, you will be able to review the source code.

Fig. 3: Source Code (first lines) for the candlestick pattern HARAMI

Further down the file, a brief description of the logic behind the programmed code can be found:

Fig. 4.: Comments within the program code for HARAMI pattern (detailed description of the calculation logic)

This is followed by the code for the HARAMI pattern:

Fig.5: C/C++ Code of the HARAMI pattern

This is level of detail, also availale for the other candlestick pattens.

Just for better readability I have exported the last snippet:

if( TA_REALBODY(i-1) > TA_CANDLEAVERAGE( BodyLong, BodyLongPeriodTotal, i-1 ) &&             // 1st: long
TA_REALBODY(i) <= TA_CANDLEAVERAGE( BodyShort, BodyShortPeriodTotal, i ) // 2nd: short
)
if ( max( inClose[i], inOpen[i] ) < max( inClose[i-1], inOpen[i-1] ) && // 2nd is engulfed by 1st
min( inClose[i], inOpen[i] ) > min( inClose[i-1], inOpen[i-1] )
)
outInteger[outIdx++] = -TA_CANDLECOLOR(i-1) * 100;
else
if ( max( inClose[i], inOpen[i] ) <= max( inClose[i-1], inOpen[i-1] ) && // 2nd is engulfed by 1st
min( inClose[i], inOpen[i] ) >= min( inClose[i-1], inOpen[i-1] ) // (one end of real body can match;
) // engulfing guaranteed by "long" and "short")
outInteger[outIdx++] = -TA_CANDLECOLOR(i-1) * 80;

The Code for HARAM is straightforward (as all the other as well). As described in the comments, the following steps are executed (at todays Close):

  1. Check if yesterday's candle has a “Long Body” (Body is the part of the candle between opening and close price).
  2. Check if today’s candle has a “Short Body”
  3. Check if today's candle body is fully contained within the body of yesterday's candle.
  4. If 1.-3 is true, then a HARAMI-pattern is detected
  5. Check the Color of today's candle, if white, a bullish HARAMI is detected and a signal of 100 is returned, if black a bearish pattern is detected and a signal of -100 is returned.

NOTE: The code accounts for the unlikely scenario where the upper or lower values of the bodies of yesterday’s and today’s candlesticks match exactly. In such a case, 80/-80 is returned instead of 100/-100, a situation that is very rare in reality.

Candlestick patterns are identified by verifying the fulfillment of specific criteria. There are two main types of criteria observed:

  • “objective” criteria: These are purely based on the relations between the Open, Close, Low and High prices of the candles in a pattern. Those criteria are “objective” and are reproducible.
  • “Subjective” criteria: Other characteristics (parameters) of candlestick patterns, such as LONG-BODY and SHORT UPPER-SHADOW, are not standardized and remain rather ambiguous. The outcome of pattern detection is highly reliant on the method used to calculate these subjective criteria.

Because the calculation methods for the a.m. subjective criteria (= parameters) are not standardized, the outcomes of candlestick pattern analyses will invariably vary to some extent from one author to another. So a LONG-BODY is sometimes defined as a percentage of the candles total span, sometimes in relation to the averaged body-size, observed during an assessment period, sometimes it is expressed in total prices.

See also the following statement in the comment section of the code: The meaning of “short” and “long” is specified with TA_SetCandleSettings.

These candle settings are defined in the code module ta_global.c in the directory: https://sourceforge.net/p/ta-lib/code/HEAD/tree/trunk/ta-lib/c/src/ta_common/. A screenshot with a small part of code is given below:

Fig. 6: TA_Candle_Settings

Additional functions are programmed in separate modules, such as ta_utility.h.

Key takeaway: While every aspect of the calculations is open for inspection and assessment, modifying the calculations is not straightforward unless one possesses strong expertise in C/C++.

5. Summary

Overall, TA-Lib serves as a solid foundation for analyzing candlestick patterns. The code is stable and tested, with functions that are ready for use and can be easily integrated into Python programs.

However, there are some drawbacks:

  1. TA-Lib is a closed ecosystem. You’re confined to candlestick patterns that were programmed approximately 15 years ago. Despite having 61 patterns in the library, it does not reflect recent publications and discussions on newly identified patterns.
  2. Moreover, while the methods for calculating pattern parameters are open for review, they cannot be altered. As a result, the signals from TA-Lib may differ from those of other systems.
  3. Given that the library is written in C/C++, a typically skilled Python programmer would not have the opportunity to modify it. Due to my complete lack of C/C++ knowledge, it is difficult for me to evaluate how challenging it might be for an experienced C/C++ programmer to alter the code and make it operational again. All in all, modifications are not straightforward at all.

Thank you for your attention. I trust this has offered further understanding for those utilizing TA-Lib in candlestick pattern detection.

In upcoming posts, I intend to reveal my observations on the predictive strength of signals derived from unfiltered candlestick-pattern-signals, followed by the outcomes when applying signal filtering technologies.

--

--