C/C++ Core API
C/C++ Core API Documentation
2.0 How to add TA-Lib to your app
3.1 Initialize and Shutdown
3.2 Batch Processing
3.3 Output Size
4.1 Abstraction layer
4.2 Numerical Stability
4.3 Input Type: float vs. double
4.4 High-performance Multi-threading
1.0 Introduction
The Core API provides:
- Lifecycle of the library (TA_Initialize / TA_Shutdown).
- Setting global variables (e.g. TA_SetUnstablePeriod, TA_SetCandleSettings).
- Each TA function for processing a whole array of data at once.
- An abstraction layer for calling these functions dynamically.
To process a live feed one bar at a time instead, see the companion C/C++ Streaming API.
You must first install TA-Lib, which will provide all the shared/static libraries and headers needed to compile with your program.
2.0 How to add TA-Lib to your app
In your source code, add #include "ta_libc.h" and link to the library named "ta-lib".
You may need to add TA-Lib to your compiler's search path. For example, with gcc, you can use the following options:
-I/usr/local/include/ta-lib -lta-libThe paths depend on the method used to install. Typical locations for headers are:
- /usr/local/include/ta-lib
- /usr/include/ta-lib
- /opt/include/ta-lib
Typical locations for the libraries are:
- /usr/lib
- /usr/lib64
- /usr/local/lib
- /usr/local/lib64
- /opt/lib
- /opt/local/lib
For homebrew, use brew --prefix ta-lib to find the paths.
For windows, look into C:\Program Files\TA-Lib for 64-bits and C:\Program Files (x86)\TA-Lib for 32-bits.
3.0 Calling into TA-Lib
All of TA-Lib's public functions are declared in the include/*.h headers.
3.1 Initialize and Shutdown
TA_RetCode TA_Initialize( void ); TA_RetCode TA_Shutdown( void );
TA_Initialize must be called once (and only once), from a single thread, prior to any other API function. After it returns TA_SUCCESS, you can start processing your data in 3 different ways: batch processing, the streaming API or through the abstraction layer.
TA_Shutdown releases the resources acquired by TA_Initialize. Call it single-threaded, typically from the last remaining thread just before your application exits.
3.2 Batch Processing
Every function follows the same simple pattern: it reads its inputs from arrays you pass in and writes its results to buffers you allocate.A function never writes more elements than you request, so the buffers only need to cover the startIdx-to-endIdx range.
As an example, let's walk through TA_MA, a function to calculate a moving average.
TA_RetCode TA_MA( int startIdx, int endIdx, const double inReal[], int optInTimePeriod, int optInMAType, int *outBegIdx, int *outNbElement, double outReal[] )
All TA functions use the same calling pattern, divided into 4 groups:
- The output will be calculated only for the range specified by startIdx and endIdx. These are zero-based indices into the input arrays.
- One or more input arrays are then specified. Typically, these are the "price" data. In this example there is only one input. All input parameter names start with "in".
- Zero or more optional inputs are then specified. In this example there are two optional inputs. These parameters give finer control specific to each function. If you do not care about a particular optIn, just specify TA_INTEGER_DEFAULT or TA_REAL_DEFAULT (depending on the type).
- One or more output arrays come last. In this example there is only one output (outReal). The parameters outBegIdx and outNbElement always come just before the output arrays.
This calling pattern takes some getting used to, but it lets your app spend time and memory only on the data it actually needs.
For example, here is how to calculate a 30-day simple moving average (SMA) of daily closing prices:
TA_Real closePrice[400]; TA_Real out[400]; TA_Integer outBeg; TA_Integer outNbElement;
/* ... initialize your closing price here... */
retCode = TA_MA( 0, 399, &closePrice[0], 30,TA_MAType_SMA, &outBeg, &outNbElement, &out[0] );
/* The output is displayed here */ for( i=0; i < outNbElement; i++ ) printf( "Day %d = %f\n", outBeg+i, out[i] );
After the call, it is important to check the values returned in outBeg and outNbElement. Even though we requested the whole range (0 to 399), a 30-day average is not defined until the 30th day. Consequently, outBeg will be 29 (zero-based) and outNbElement will be 400-29 = 371. In other words, only the first 371 elements of out[] are written, and they correspond to input elements 29 through 399.
As another example, if you had requested only the range 125 to 225, outBeg would be 125 and outNbElement would be 101 (endIdx is inclusive: 225-125+1). The 30-day minimum is not a problem here, because the 125 closing prices before the requested range provide the needed history. As you may have guessed, only the first 101 elements of out[] are written; the rest is left untouched.
Here is another example. This time we calculate a 14-bar exponential moving average for a single price bar (say, the last of 300 bars):
TA_Real closePrice[300]; TA_Real out; TA_Integer outBeg; TA_Integer outNbElement;
/* ... initialize your closing price here... */
retCode = TA_MA( 299, 299, &closePrice[0], 14, TA_MAType_EMA, &outBeg, &outNbElement, &out );
In this example, outBeg will be 299, outNbElement will be 1, and only one value is written into out.
If you do not provide enough data to calculate even one value, outNbElement will be 0 and outBeg should be ignored.
If the input and output of a TA function are of the same type, the caller can reuse the input buffer to store one of the outputs. The following example works:
#define BUFFER_SIZE 100 TA_Real buffer[BUFFER_SIZE]; ... retCode = TA_MA( 0, BUFFER_SIZE-1, &buffer[0], 30, TA_MAType_SMA, &outBeg, &outNbElement, &buffer[0] );
Of course, the input is overwritten, but this avoids allocating a temporary buffer. All TA functions support this.
3.3 Output Size
It is important that the output array is large enough. Here are three ways to determine the allocation size; all of them work for every TA function:
| Method | Description |
|---|---|
| Input Matching | allocationSize = endIdx + 1; Pros: Easy to understand and implement. Cons: Memory allocation unnecessarily large when requesting a small range. |
| Range Matching | allocationSize = endIdx - startIdx + 1; Pros: Easy to implement. Cons: Allocation slightly larger than needed. Example: with startIdx = 0, a 30-period SMA wastes 29 elements because of the lookback. |
| Exact Allocation | lookback = TA_XXXX_Lookback( ... ) ; temp = max( lookback, startIdx ); if( temp > endIdx ) allocationSize = 0; // No output else allocationSize = endIdx - temp + 1; Pros: Allocates exactly what is needed. Cons: Slightly more complex. |
Each TA function has a matching TA_XXXX_Lookback function. Example: for TA_SMA, it is TA_SMA_Lookback.
The lookback is the number of input elements consumed before the first output can be calculated. Example: a simple moving average (SMA) of period 10 has a lookback of 9.
4.0 Advanced Features
4.1 Abstraction Layer
Instead of hard-coding calls to specific TA functions, an app can drive them all dynamically through the interface in ta_abstract.h — looking functions up by name at runtime. It reports which inputs, optional parameters (and their valid ranges), and outputs a function takes — so you can call a function whose signature was unknown at compile time.
This is what you want when the function or its parameters are not fixed in your code. Typical uses:
- Generating glue code or wrappers for higher-level languages.
- Automatically picking up new functions after a TA-Lib upgrade, with no code change.
- "Mutating" the function and its parameters while searching for strategies (e.g. a genetic or neural-network algorithm).
- Populating a charting app: the indicator menu and each settings dialog come straight from the metadata.
If you only need a handful of specific functions, calling them directly — with batch processing or the streaming API — is simpler.
4.2 Numerical Stability
Take one bar and compute an indicator for it twice: once with a year of history before it, once with a decade. Do you get the same value? For many functions, always — they read a fixed number of bars and ignore everything older. Others are recursive, so their earliest values depend on how much history precedes them, converging as more bars are supplied — the Exponential Moving Average is the classic example. A few accumulate from the very first bar and never converge at all.
Each function's documentation specifies which of the four numerical-stability categories applies to it.
See the Unstable Period page for more configurability.
4.3 Input Type: float vs. double
Each TA function has two implementations: one accepts input arrays of double, the other of float. The float version carries the "TA_S_" prefix, e.g. TA_S_MA is the float equivalent of TA_MA.
TA_RetCode TA_MA( int startIdx,
int endIdx,
const double inReal[],
int optInTimePeriod,
TA_MAType optInMAType,
int *outBegIdx,
int *outNbElement,
double outReal[] );
TA_RetCode TA_S_MA( int startIdx,
int endIdx,
const float inReal[],
int optInTimePeriod,
TA_MAType optInMAType,
int *outBegIdx,
int *outNbElement,
double outReal[] );
Internally, both versions do all calculations in double — each float element is converted to double when read. Consequently, both functions produce the same output, bit-for-bit.
Some apps already hold their price data as float. The TA_S_XXXX functions consume such arrays directly (no conversion copy needed) while keeping every intermediate calculation in double.
4.4 High-performance multi-threading
TA-Lib is multi-thread safe where it matters most for performance: calling the TA functions themselves (TA_SMA, TA_RSI, ...).
One important caveat: the "global settings" must first be initialized from a single thread. That includes calls to:
Once these initial calls are done, the application can call the rest of the API from multiple threads (including the ta_abstract.h interface).
The exception is TA_Shutdown(), which must be called single-threaded (typically from the last remaining thread just before your application exits).
Note: TA-Lib assumes it is linked against a thread-safe malloc/free runtime, which is the default on all modern platforms (Linux, Windows, Mac). In other words, any toolchain supporting C11 or newer is safe.