C/C++ Streaming API
Not yet released
This feature is planned for v0.8.x.
The streaming API is built for live feeds: open a stream once, then feed it one bar at a time. The stream carries its state from bar to bar, so each new bar costs O(1) — and every value is bit-identical to what the batch function (TA_SMA, TA_RSI, …) would return by recomputing over the whole array.
Every TA function gets these calls:
| Call | When | Does |
|---|---|---|
TA_<NAME>_Open | once | validate params, consume warm-up history, return a stream + current value |
TA_<NAME>_Update | once per closed bar | commit one bar, return the new value |
TA_<NAME>_Peek | any time on the forming bar | evaluate a provisional bar without committing state |
TA_<NAME>_Close | once | free the stream |
One more call, OpenAndFill, writes array output instead of a single value — see Array-Fill Open below.
Additional read-only utility functions are available.
Example (SMA)
TA_SMA_Stream *s;
double sma;
int period = 30;
int historyLen = 30; /* must be >= TA_SMA_Lookback(period) + 1 */
/* Seed with warm-up history. */
double history[30] = { /* ...your closing prices... */ };
if( TA_SMA_Open( &s, history, historyLen, period, &sma ) != TA_SUCCESS )
return; /* s is NULL on failure */
/* Each time a bar closes: */
TA_SMA_Update( s, newClose, &sma );
printf( "SMA = %f\n", sma );
/* Intra-bar, on the not-yet-closed bar (repeat as the price ticks): */
TA_SMA_Peek( s, formingClose, &sma ); /* state left unchanged */
TA_SMA_Close( s );Rules
- Warm-up.
Opensucceeds only ifhistoryLen >= TA_<NAME>_Lookback(params) + 1— with fewer bars there is no defined value yet. AfterOpen, the history buffer can be freed — the stream keeps everything it needs. - Closed vs forming bar.
Updatecommits state irreversibly, so use it only for closed bars.Peekreturns the exact valueUpdatewould, but without committing — call it as often as the forming bar ticks. - Parameters are fixed at
Open. Changing a parameter means a new stream. Unstable period and candle settings are first read atOpenand must not change during the stream's life. - Threads. A stream is single-writer: an
UpdateorTA_<NAME>_Advancemust not race with any other call on the same stream. Processing forks are possible by cloning the stream, and each clone becomes fully independent and can be updated concurrently. - Not serializable. To checkpoint, retain the history and re-open — the result is bit-identical by contract.
Multi-input / multi-output
Inputs and outputs mirror the batch function — OHLCV in, one out-pointer per output:
/* Candlestick: OHLC in, one int out */
TA_CDLDOJI_Update( s, open, high, low, close, &outInteger );
/* MACD: one in, three out */
TA_MACD_Update( s, close, &macd, &signal, &hist );Array-Fill Open
Open and Update each write a single value per output. One more call writes a full array instead — the same shape the batch function would produce — while still opening the stream:
| Call | When | Does |
|---|---|---|
TA_<NAME>_OpenAndFill | once, instead of Open | like Open, but returns the output for every history bar |
double out[300]; /* one array per output */
int begIdx, nbElement;
TA_SMA_OpenAndFill( &s, history, historyLen, period,
&begIdx, &nbElement, out );
/* out[0 .. nbElement-1] is the SMA over all of history; then stream on: */
TA_SMA_Update( s, newClose, &sma );Utility Calls
| Call | When | Does |
|---|---|---|
TA_<NAME>_Value | any time | the value(s) at the last bar the stream counted, without recomputing |
TA_<NAME>_Clone | any time | an independent fork of the stream, at the same bar |
TA_<NAME>_OutRange | any time | the bars the stream has an output for — the batch range over the same bars |
TA_<NAME>_Advance | after a bar you will not feed | advances the OutRange without affecting any other internal state of the stream |
double v;
int begIdx, nbElement;
TA_SMA_Stream *fork = NULL;
TA_SMA_Value( s, &v ); /* the value at the last bar s counted */
TA_SMA_Clone( s, &fork ); /* independent from here on */
TA_SMA_OutRange( s, &begIdx, &nbElement ); /* the bars s has an output for */
TA_SMA_Advance( s ); /* a bar you skipped, counted */See Rules for when concurrent reads of these are safe.
Error model
| Call | Returns |
|---|---|
TA_<NAME>_Open / TA_<NAME>_OpenAndFill |
*stream is NULL. |
TA_<NAME>_Update / TA_<NAME>_Peek | TA_BAD_PARAM on NULL arguments, or invalid input such as NaN or ±Inf. A rejection changes nothing at all — no state, no output, and no range — so the next call sees exactly what the last accepted bar left. The exception is an overflow inside the library's own arithmetic, which is undefined in both APIs (see Numerical Stability) — close such a handle rather than feeding it further. To count a rejected bar rather than re-feed it, call TA_<NAME>_Advance (see Utility Calls).TA_<NAME>_Update also reports TA_OUT_OF_RANGE_END_INDEX once the range has reached bar TA_MAX_INDEX, the last index the batch API addresses. That one does not clear: close the handle and open a new one on a shorter history. TA_<NAME>_Peek counts no bar and is not subject to it. |
TA_<NAME>_Close | TA_SUCCESS; TA_<NAME>_Close(NULL) is a no-op |
TA_<NAME>_Value | TA_BAD_PARAM on a NULL stream or a NULL out-pointer for a required output. A declinable output may be NULL, and is then simply not written. |
TA_<NAME>_Clone | TA_BAD_PARAM on a NULL stream or a NULL clone; TA_ALLOC_ERR if any allocation fails. On either, *clone is NULL and the original is untouched. |
TA_<NAME>_OutRange | TA_BAD_PARAM on a NULL argument |
TA_<NAME>_Advance | TA_BAD_PARAM on a NULL argument; TA_OUT_OF_RANGE_END_INDEX once the range has reached bar TA_MAX_INDEX |
Discovering streamable functions
When driving TA-Lib through the abstraction layer, streamable functions carry the TA_FUNC_FLG_STREAM flag in their function info.