# TA-Lib.org > Open-Source library for technical analysis of time series and trading data ## Key facts TA-Lib computes technical-analysis indicators and recognizes candlestick patterns over price series. This documentation is built from the main branch and can be ahead of the newest release, so any installed version, the newest included, can lack what is described here or compute different values. The [changelog](https://github.com/TA-Lib/ta-lib/blob/main/CHANGELOG.md) records each release's changes, and its "Not Released Yet" section lists changes no release has yet. Pin the exact version when results must reproduce. - **C is the reference.** Open source under the BSD license, in use since 2001. Each function has a page with its inputs, outputs, parameters (type, default, accepted values) and numerical stability, at `https://ta-lib.org/functions/.md` with the name in lowercase (e.g. [RSI](https://ta-lib.org/functions/rsi.md)); the [function index](https://ta-lib.org/functions/index.md) lists them by group. - **Native Rust, Java and C#.** Each is a port, not a binding (no FFI, JNI or P/Invoke), generated together with the C library from [one definition per function](https://ta-lib.org/contribute/index.md): [Rust](https://ta-lib.org/api/rust/index.md), [Java](https://ta-lib.org/api/java/index.md), [C#](https://ta-lib.org/api/csharp/index.md). Each is bit-identical to C over the same inputs, except that a Java or C# result computed through a transcendental math function (such as `exp` or `log`) can differ: the difference starts in the last bit and can grow through the function's arithmetic, and HT_* outputs can differ outright ([determinism](https://ta-lib.org/spec/versions/index.md)). Whether a port's package is published, and how to add it, is in the "Add it to your project" section of its API page; the C library's install methods are on the [C install page](https://ta-lib.org/install/c/index.md). - **Wrappers.** Python ([ta-lib-python](https://github.com/ta-lib/ta-lib-python)), R and other languages call the C library through [community wrappers](https://ta-lib.org/wrappers/index.md), each with its own conventions. - **Batch API: defined values only.** A call computes the inclusive, zero-based `startIdx` to `endIdx` range and writes only the bars where the function is defined, from the start of the output buffer: `out[0]` is input bar `outBegIdx`, and `outNBElement` values follow in [C](https://ta-lib.org/api/index.md); Rust, Java and C# return the same pair as an `OutRange` (begin index and count). Nothing is padded, and too little data is a success with an empty range. - **Errors.** An indicator call, batch or stream, reports a rejected argument as a non-zero `TA_RetCode` in C, an `Err(RetCode)` in Rust, and an exception carrying its `RetCode` in Java and C#. Other calls differ: a lookback answers -1 for an out-of-range parameter in C, Java and C# (`Err(BadParam)` in Rust), and in Java and C# the `Core` builder's setters and a misused metadata `ParamHolder` throw the platform's own exceptions (such as `IllegalArgumentException` or `ArgumentOutOfRangeException`), with no `RetCode`. - **Lookback.** `TA__Lookback(params)`, and its equivalent in each port, is the number of bars consumed before the first output, including any unstable period set that applies ([exceptions](https://ta-lib.org/spec/lookback/index.md)); output starts at `max(startIdx, lookback)`, so the exact output length is `endIdx - max(startIdx, lookback) + 1`, or 0 when that is not positive. - **NaN padding is ta-lib-python's convention.** It returns arrays as long as the input. Over the warm-up bars a real output holds NaN and an integer output holds 0, which on a `CDL*` output looks the same as no pattern. The C, Rust, Java and C# APIs never pad, so code ported from Python must re-align outputs by the begin index. - **NaN in the input.** A NaN or ±Inf inside a batch input series, or in the history a stream opens on, is not detected, and nothing is promised about the output: it can affect every later value, since some functions carry it forward and some recover. Clean or split the series before calling. A stream's update and peek reject such a bar and leave the stream unchanged. - **Streaming.** Every function also streams: open it on history, update it once per closed bar, and peek at the forming bar without changing state. Every value is bit-identical to the batch call over the same bars, except that a zero can differ in sign ([H1](https://ta-lib.org/spec/streaming/index.md)). Each language's streaming page: [C](https://ta-lib.org/api/stream/index.md), [Rust](https://ta-lib.org/api/rust/stream/index.md), [Java](https://ta-lib.org/api/java/stream/index.md), [C#](https://ta-lib.org/api/csharp/stream/index.md). - **Numerical stability.** Each function page says whether a bar's value depends on where the series begins: [start-independent, initial unstable period, path-dependent, or depends on the MA type](https://ta-lib.org/functions/stability.md). A recursive function converges as history grows; a path-dependent one, such as AD, OBV or SAR, never does. - **Stability at run time.** In the metadata, `TA_FUNC_FLG_PATH_DEP` marks every path-dependent function and `TA_FUNC_FLG_UNST_PER` every function with its own unstable-period setting, with the same bits in Rust, Java and C#. A function unstable only through a callee, such as DEMA or MACD through EMA, carries neither flag, so the function page is the complete classification. - **Unstable period.** [Setting it](https://ta-lib.org/api/unstable-period/index.md) for a recursive function such as EMA, RSI or ADX drops that many more leading outputs, the ones its seed still distorts; the default, 0, drops nothing. It follows the function wherever it runs, so EMA's setting also moves MACD and DEMA. - **Metadata API.** Enumerate every function at run time, with its group, inputs, parameters (type, range, default), outputs and flags, then call it by name: the "Abstraction Layer" section of the [C](https://ta-lib.org/api/index.md), [Rust](https://ta-lib.org/api/rust/index.md), [Java](https://ta-lib.org/api/java/index.md) and [C#](https://ta-lib.org/api/csharp/index.md) API pages. - **Candlestick settings.** The `CDL*` pattern functions judge bodies, shadows and distances against [tunable thresholds](https://ta-lib.org/api/candle-settings/index.md). - **Settings and threads.** In C, call `TA_Initialize` once, then set the unstable period and candle settings, which are process-wide, from one thread; after that the TA functions are safe to call from any number of threads (the "High-performance Multi-threading" section of the [C API page](https://ta-lib.org/api/index.md)). In Rust, Java and C#, settings live in an immutable `Core` built with a builder, so differently configured instances coexist and one instance is shared across threads freely. The exceptions are a stream handle, which has one writer (an update must not race with any other call on it; clone it to fork), and two objects to confine to one thread: a parameter holder of the abstraction layer and, in Java and C#, a `Core` builder ([T6](https://ta-lib.org/spec/settings-threads/index.md)). --- --- url: 'https://ta-lib.org/spec/index.md' description: >- The exhaustive contract of TA-Lib's C, Rust, Java and C# APIs, for precise AI-agent-driven integration: how a failure reaches the caller, how names fold, and one page per topic. --- # Specification **These are TA-Lib's exhaustive specifications, intended for precise AI-agent-driven integration with TA-Lib, to minimize errors.** They cover the four native APIs (C, Rust, Java, C#). Each rule has one home page, states what the code does, and is written in C's spelling. This page maps that shared vocabulary onto Rust, Java and C#; a rule that introduces a language-specific name gives all four spellings itself. For a first contact, start with the Core API page of your language: [C/C++](/api/), [Rust](/api/rust/), [Java](/api/java/), [C#](/api/csharp/). ## Scope {#scope} * The four native APIs: batch, lookback, streams, settings, and the abstraction layer, which is specified only in part ([M1](/spec/errors/#m1)). * A wrapper keeps its own conventions. ta-lib-python aligns outputs to the input and fills the warm-up with NaN; the native APIs do not ([N2](/spec/inputs-outputs/#n2)). * Published packages and their versions: [Install](/install/). * Owned by other pages: [Unstable Period](/api/unstable-period/), [Candlestick Settings](/api/candle-settings/) (model and defaults), streaming in [C](/api/stream/), [Rust](/api/rust/stream/), [Java](/api/java/stream/) and [C#](/api/csharp/stream/), [Numerical Stability](/functions/stability), and the [function pages](/functions/): inputs, outputs in order, parameters (type, default, accepted values), stability category, flags. * Every page except the per-function pages in one file: [/llms-full.txt](/llms-full.txt), whose [function index](/functions/) lists and links each function's page; [/llms.txt](/llms.txt) indexes them all. Each page has a Markdown twin, `/spec/index.md` for this one. ## Rule pages {#reading} | Page | Covers | Ids | |---|---|---| | [Errors](/spec/errors/) | return codes, evaluation order, batch tier, messages, abstraction layer | R1 to R5, B1 to B8, B6a, M1, M2 | | [Inputs and Outputs](/spec/inputs-outputs/) | index range, inputs, parameters, outputs, aliasing | I1 to I6, O1 to O7, N1 to N4, N8 | | [Lookback](/spec/lookback/) | lookback call, unstable period, candle averaging, period 1, start dependence | L1 to L9 | | [Streaming](/spec/streaming/) | bit-identity with batch, every stream call, lifetime | S1 to S7, S6a, U1 to U4, U6a, X1, H1 to H10, N7 | | [Settings and Threads](/spec/settings-threads/) | C lifecycle, `Core`, setting validation, threads, settings under a live stream | G1 to G7, T1 to T7, N5, N6 | | [Versions and Determinism](/spec/versions/) | bit-identity across languages and machines; releases | D1 to D4, V1 to V4 | * `` stands for a function's canonical name: `TA__Open` is `TA_SMA_Open`. * An id's anchor is the id in lower case: [/spec/errors/#b5](/spec/errors/#b5). Its number is not its evaluation order (U4 precedes U2): [R2](/spec/errors/#r2). Its meaning is not promised to stay the same across releases. * **Current behaviour** marks what today's code does, verified, where no rule is decided. It promises nothing. ## Names in each language {#names} A function's canonical name is its name on [/functions/](/functions/). A fold changes only case and `_`; it adds no word boundary inside a segment: | Fold | Rule | SMA | HT_TRENDLINE | CDL3BLACKCROWS | |---|---|---|---|---| | C | `TA_` + canonical | `TA_SMA` | `TA_HT_TRENDLINE` | `TA_CDL3BLACKCROWS` | | snake | lower case | `sma` | `ht_trendline` | `cdl3blackcrows` | | UpperCamel | lower case, upper-case each `_` segment's first letter, drop `_` | `Sma` | `HtTrendline` | `Cdl3blackcrows` | | lowerCamel | UpperCamel, first letter lower case | `sma` | `htTrendline` | `cdl3blackcrows` | Rust uses snake for functions, UpperCamel for types; Java lowerCamel for methods, UpperCamel for types; C# UpperCamel. Messages and the abstraction layer use the canonical name. Indicator parameters keep C's names everywhere (`startIdx`, `inReal`, `optInTimePeriod`, `outReal`). Every function has this surface; in Rust, Java and C# the calls are methods of a `Core`: | Surface | C | Rust | Java | C# | |---|---|---|---|---| | batch | `TA_SMA` | `sma` | `sma` | `Sma` | | lookback | `int TA_SMA_Lookback` | `sma_lookback` returns `Result` | `int smaLookback` | `int SmaLookback` | | open, open and fill | `TA_SMA_Open`, `TA_SMA_OpenAndFill` | `sma_open`, `sma_open_and_fill` | `smaOpen`, `smaOpenAndFill` | `SmaOpen`, `SmaOpenAndFill` | | handle | `TA_SMA_Stream *` | `SmaStream` | `Core.SmaStream` | `Core.SmaStream` | | handle calls | `TA_SMA_Update`, `_Peek`, `_Value`, `_OutRange`, `_Advance`, `_Clone`, `_Close` | `update`, `peek`, `value`, `out_range`, `advance`, `clone`; drop to release | `update`, `peek`, `value`, `outRange`, `advance`, `clone` | `Update`, `Peek`, `Advance`, `Clone`; properties `Value`, `OutRange` | | one bar of MACD | three out-pointers | `(f64, f64, f64)` | caller-owned `Core.MacdOut` sink | returned `Core.MacdValue` | | Argument | C | Rust | Java | C# | |---|---|---|---|---| | index | `int` | `usize` | `int` | `int` | | real input, output | `const double[]`, `double[]` | `&[f64]`, `&mut [f64]` | `double[]` | `ReadOnlySpan`, `Span` | | integer output | `int[]` | `&mut [i32]` | `int[]` | `Span` | | integer, real parameter | `int`, `double` | `i32`, `f64` | `int`, `double` | `int`, `double` | | MA-type parameter | `TA_MAType` | `MAType` | `MAType` | `MAType` | | absent ([B4](/spec/errors/#b4)) | `NULL` | not expressible | `null` | a `null` array becomes an empty span | | Type | C | Rust | Java | C# | |---|---|---|---|---| | import | `ta_libc.h` | crate `ta_lib` | `io.github.talib` | `TALib` | | settings: default, builder | process globals ([T2](/spec/settings-threads/#t2)) | `Core::new()`, `Core::builder()` | `Core.DEFAULT`, `Core.builder()` | `Core.Default`, `Core.Builder()` | | output range | `outBegIdx`, `outNBElement` | `OutRange { beg_idx, count }`, `EMPTY`, `is_empty()` | `OutRange(begIdx, count)`, `EMPTY`, `isEmpty()` | `OutRange(BegIdx, Count)`, `Empty`, `IsEmpty` | Setters per language: [Unstable Period](/api/unstable-period/), [Candlestick Settings](/api/candle-settings/). C has no public candle-setting type: a setting is the four arguments of `TA_SetCandleSettings`. Enum types drop C's `TA_`. Members: | Enum | C | Rust, C# | Java | |---|---|---|---| | `RetCode` | `TA_BAD_PARAM` | `BadParam` | `BAD_PARAM` | | `CandleSettingType` | `TA_BodyLong` | `BodyLong` | `BODY_LONG` | | `RangeType` | `TA_RangeType_RealBody` | `RealBody` | `REAL_BODY` | | `MAType` | `TA_MAType_SMA` | `SMA` | `SMA` | | `FuncUnstId` | `TA_FUNC_UNST_HT_DCPERIOD` | `HT_DCPERIOD` | `HT_DCPERIOD` | Constants: C prefixes `TA_` (`TA_INDEX_MAX`); Rust, Java and C# hold them on `Core`, C# in UpperCamel (`Core.IndexMax`). | Constant | Value | |---|---| | `INDEX_MAX` | 100000000, the largest index | | `REAL_DEFAULT` | -4e37, selects a real parameter's default ([N3](/spec/inputs-outputs/#n3)) | | `INTEGER_DEFAULT` | `INT_MIN`, selects an integer parameter's default | | `REAL_MIN`, `REAL_MAX` | -3e37, 3e37 ([I4](/spec/inputs-outputs/#i4)) | ### Abstraction layer {#abstraction} It describes every function at run time (inputs, outputs, each optional parameter's default and range, flags) and runs its double-precision batch call. Its flags do not give the stability category: [Lookback](/spec/lookback/#start). | | C `ta_abstract.h` | Rust `ta_lib::abstract_api` | Java `io.github.talib.metadata` | C# `TALib.Metadata` | |---|---|---|---|---| | look up, enumerate | `TA_GetFuncHandle`, `TA_ForEachFunc` | `get_func_handle`, `FUNCS` | `Functions.byName`, `Functions.all()` | `FunctionCatalog.Default[name]`, `FunctionCatalog.Default` | | call | `TA_ParamHolderAlloc`, `TA_CallFunc` | `FuncId::new_call`, `call` | `FuncInfo.newCall`, `call` | `FuncInfo.CreateCall`, `Call`, `TryCall` | | all as one XML document | `TA_FunctionDescriptionXML()` | `function_description_xml()` | `FunctionDescription.xml()` | `FunctionDescription.Xml` | ## How a failure reaches the caller {#failures} | Success | C, returning `TA_SUCCESS` | Rust | Java | C# | |---|---|---|---|---| | batch | range in `*outBegIdx`, `*outNBElement` | `Ok(OutRange)` | `OutRange` | `OutRange` | | open | handle in `*stream`, last value in the out-pointers | `Ok((handle, value))` | handle | handle | | open and fill | handle and range in out-pointers | `Ok((handle, OutRange))` | handle; range from `outRange()` | handle; range from `OutRange` | | update, peek | value in the out-pointers | `Ok(value)` | value, or written into the sink | value | | Failure | C | Rust | Java | C# | |---|---|---|---|---| | carrier, code (messages: [R5](/spec/errors/#r5)) | returned `TA_RetCode` | `Err(RetCode)` | an exception implementing `TALibFailure`; `retCode()` | an exception implementing `ITALibFailure`; `RetCode` | | C's number | the value | `as_c_int()` | `asCInt()` | `(int)` cast | | lookback ([L1](/spec/lookback/#l1)) | `-1` | `Err(RetCode::BadParam)` | `-1` | `-1` | One row per function-tier code; `A : B` means `A` extends the platform type `B`, so a `catch` of `B` works. | Code | Rust | Java | C# | |---|---|---|---| | `TA_BAD_PARAM` (2) | `BadParam` | `TALibArgumentException : IllegalArgumentException` | `TALibArgumentException : ArgumentException` | | `TA_OUT_OF_RANGE_START_INDEX` (12) | `OutOfRangeStartIndex` | `TALibIndexException : IndexOutOfBoundsException` | `TALibArgumentOutOfRangeException : ArgumentOutOfRangeException` | | `TA_OUT_OF_RANGE_END_INDEX` (13) | `OutOfRangeEndIndex` | `TALibIndexException` | `TALibArgumentOutOfRangeException`; `TALibArgumentException` from `Update`, `Advance` ([U4](/spec/streaming/#u4)) | | `TA_INSUFFICIENT_HISTORY` (17) | `InsufficientHistory` | `InsufficientHistoryException : TALibArgumentException` | `InsufficientHistoryException : TALibArgumentException` | | `TA_INTERNAL_ERROR` (5000, [B8](/spec/errors/#b8)) | `InternalError` | `TALibStateException : IllegalStateException` | `TALibInvalidOperationException : InvalidOperationException` | | `TA_ALLOC_ERR` (3) | `AllocErr`, never returned ([B7](/spec/errors/#b7)) | never thrown | never thrown | C# sets `ParamName` of an index exception to `startIdx` or `endIdx` in batch, and to the first input series in an opener. Rust's and Java's `RetCode` hold exactly `TA_SUCCESS` and these codes; C#'s also holds `InputNotAllInitialize` (10) and `OutputNotAllInitialize` (11). Numbering: [V2](/spec/versions/#v2). Refusals outside the function tier: | Refusal | C | Rust | Java | C# | |---|---|---|---|---| | setter ([G1](/spec/settings-threads/#g1)) | returns `TA_BAD_PARAM` | `build()` returns `Err(RetCode::BadParam)` ([G7](/spec/settings-threads/#g7)) | throws `IllegalArgumentException` (`NullPointerException` on null), no code | throws `ArgumentOutOfRangeException`, no code | | getter ([G3](/spec/settings-threads/#g3)) | cannot refuse | returns `Err(RetCode::BadParam)` | as the setter | as the setter | | abstraction layer's own, current behaviour | a returned [code](/spec/errors/#return-codes) | `Err(RetCode::BadParam)`; lookup returns `None` | `IllegalArgumentException`, no code; lookup returns `null` | .NET exceptions, no code; `TryCall` returns a code instead | --- --- url: 'https://ta-lib.org/spec/errors/index.md' description: >- Every TA-Lib return code, the order a rejected call is evaluated in, and the batch tier's conditions, for the C, Rust, Java and C# APIs. --- # Errors *Part of TA-Lib's exhaustive [specifications](/spec/), intended for precise AI-agent-driven integration with TA-Lib, to minimize errors.* A rejected call reports one condition, the first in its tier's order, and leaves the caller's buffers as it found them. This page owns the return codes, the general rules R1 to R5, the batch tier B1 to B8 and the abstraction layer's M1 and M2, in C's spelling; how each code reaches a Rust, Java or C# caller is on the [hub](/spec/#failures). ## Return codes | Code | `TA_RetCode` | Returned by | |---:|---|---| | 0 | `TA_SUCCESS` | Every call that succeeds, including a batch range that ends before the lookback (count 0, [N1](/spec/inputs-outputs/#n1)). | | 1 | `TA_LIB_NOT_INITIALIZE` | `TA_Shutdown`, called when the library is not initialized ([T1](/spec/settings-threads/#t1)). | | 2 | `TA_BAD_PARAM` | B3 to B6a, S3 to S6a, U1 to U3, U6a; the checks before [S1](/spec/streaming/#s1) and the stream [accessors](/spec/streaming/#accessors); Rust's lookback ([L1](/spec/lookback/#l1)); the settings refusals G1 to G6 in C and Rust, except C's getter ([G3](/spec/settings-threads/#g3)); the abstraction layer. | | 3 | `TA_ALLOC_ERR` | Any C call that allocates, when the allocation fails ([B7](/spec/errors/#b7)). | | 4 | `TA_GROUP_NOT_FOUND` | `TA_FuncTableAlloc`, an unknown group. | | 5 | `TA_FUNC_NOT_FOUND` | `TA_GetFuncHandle`, an unknown function. | | 6 | `TA_INVALID_HANDLE` | An invalid function handle. | | 7 | `TA_INVALID_PARAM_HOLDER` | An invalid parameter holder. | | 8 | `TA_INVALID_PARAM_HOLDER_TYPE` | A holder setter whose type does not match the parameter. | | 9 | `TA_INVALID_PARAM_FUNCTION` | Nothing. | | 10 | `TA_INPUT_NOT_ALL_INITIALIZE` | `TA_CallFunc` (and C#'s `ParamHolder.TryCall`), an input left unbound. | | 11 | `TA_OUTPUT_NOT_ALL_INITIALIZE` | `TA_CallFunc` (and C#'s `ParamHolder.TryCall`), an output left unbound. | | 12 | `TA_OUT_OF_RANGE_START_INDEX` | B1, S1. | | 13 | `TA_OUT_OF_RANGE_END_INDEX` | B2, S2, U4. | | 14 | `TA_INVALID_LIST_TYPE` | Nothing. | | 15 | `TA_BAD_OBJECT` | `TA_FuncTableFree` or `TA_GroupTableFree`, an invalid table. | | 16 | `TA_NOT_SUPPORTED` | Nothing. | | 17 | `TA_INSUFFICIENT_HISTORY` | Stream openers only ([S7](/spec/streaming/#s7)). A batch call never returns it. | | 5000 to 5999 | `TA_INTERNAL_ERROR` + id | [B8](/spec/errors/#b8). | | 65535 | `TA_UNKNOWN_ERR` | Nothing. | Who returns codes 1, 4 to 11, 14 to 16 and 65535 is current behaviour, and so is the abstraction layer's own `TA_BAD_PARAM` ([abstraction layer](/spec/errors/#abstraction-layer)). `TA_SetRetCodeInfo` names and describes any value: 5000 to 5999 as `TA_INTERNAL_ERROR`, one it does not know as `TA_UNKNOWN_ERR`. ## General rules **R1** One condition per call: a rejected call reports exactly one code (in Java and C#, one exception) and stops. **R2** The first listed condition wins: a rejected call reports the code of the first condition it violates, in its tier's table order. Conditions that share a code may be checked in any order, and a Java or C# message, or a C# `ParamName`, may name any of them ([R5](/spec/errors/#r5)). **R3** One code across backends. In the batch and stream tiers, a call that two or more backends can express and detect gets the same code from each; the one known exception is in [B6](/spec/errors/#b6). Lookback: [L3](/spec/lookback/#l3). Settings refusals and the abstraction layer's own are outside R3 ([hub](/spec/#failures)). **R4** Checks precede writes. A call rejected under any rule of this specification leaves every caller-owned buffer, and C's range out-parameters, as it found them, except for C's writes stated with [S7](/spec/streaming/#s7) (`OpenAndFill`'s range) and with its handle out-parameters ([lifetime](/spec/streaming/#lifetime)). Current behaviour: C's MAVP and FRAMA set the range out-parameters to 0 before rejecting a value [I3](/spec/inputs-outputs/#i3) names. Nothing is promised after [B7](/spec/errors/#b7) or [B8](/spec/errors/#b8). ## Batch tier A batch call accepts `0 <= startIdx <= endIdx <= TA_INDEX_MAX`; B1 and B2 are the only statement of that bound ([`TA_INDEX_MAX`](/spec/#names), [I1](/spec/inputs-outputs/#i1)). Rows are in evaluation order (R2). | Rule | Condition | Code | Not expressible in | |---|---|---|---| | **B1** | `startIdx` is below 0 or above `TA_INDEX_MAX`. | `TA_OUT_OF_RANGE_START_INDEX` | Rust, below 0 (`usize`) | | **B2** | `endIdx` is below 0, above `TA_INDEX_MAX`, or below `startIdx`. | `TA_OUT_OF_RANGE_END_INDEX` | Rust, below 0 | | **B3** | An optional parameter is outside its accepted values, or the parameters form a combination the function rejects ([I3](/spec/inputs-outputs/#i3)). | `TA_BAD_PARAM` | none | | **B4** | A required argument is absent: an input, an output, or a range out-parameter. | `TA_BAD_PARAM` | Rust, C# | | **B5** | A buffer is too short: an input does not reach `endIdx` ([I2](/spec/inputs-outputs/#i2)), or an output cannot hold the count the call produces ([O2](/spec/inputs-outputs/#o2)). | `TA_BAD_PARAM` | none; C cannot detect it | | **B6** | Two outputs are the same buffer. | `TA_BAD_PARAM` | Rust (safe code) | | **B6a** | An output is omitted that the function does not let a caller decline ([O5](/spec/inputs-outputs/#o5)). | `TA_BAD_PARAM` | Rust: cannot decline. C#: no check of its own, [B5](/spec/errors/#b5) applies (current behaviour) | | **B7** | A memory allocation failed. | `TA_ALLOC_ERR` (C only) | none | | **B8** | The library found an inconsistency in its own state. | `TA_INTERNAL_ERROR` + id | none | **B4, B6a.** An omitted output that reaches the call as null ([names](/spec/#names)) is reported by B4, which comes first. An empty output, in every language that checks lengths, is held to B5 alone: rejected when the call produces values, accepted when it produces none (current behaviour). **B5.** C is handed bare pointers and cannot check: a short buffer is read or written past its end, which is undefined. **B6.** Identity only: partial overlap is [N8](/spec/inputs-outputs/#n8), and an input reused whole as an output is legal ([N4](/spec/inputs-outputs/#n4)). Two distinct empty outputs never collide. Current behaviour, and R3's exception: C and Java reject one buffer passed as two outputs whatever its length; C# never treats an empty output as aliased, so on a range that produces no values one zero-length array passed as two outputs is `TA_BAD_PARAM` in Java and a success in C#. C and C# also compare an integer output with a real one. **B7.** Fatal in every tier: nothing after it is defined (outputs, range, stream handle), so stop. Rust aborts the process, and Java and C# raise their runtime's out-of-memory error. **B8.** A bug in TA-Lib, not in the call: report it. C returns a value from 5000 to 5999, `TA_INTERNAL_ERROR` plus an id, so test the band, never `== TA_INTERNAL_ERROR`. In the function tier the id names the guard that fired ([V4](/spec/versions/#v4)). Rust, Java and C# report `TA_INTERNAL_ERROR` without an id. ## Messages **R5** In Java and C#, a batch-tier exception's message starts with `: ` (`SMA: `) and a stream-tier one with ` : `, where `` is the stream call (`open`, `openAndFill`, `update`, `peek`, `advance`, and Java's `value`). Only the prefix is specified: branch on the code, not the text. A composed function may report a function it calls: a caller of `MACDEXT` can see `MA: `. Rust's `Err(RetCode)` carries no message. ## Abstraction layer {#abstraction-layer} **M1** A call through the abstraction layer ([per language](/spec/#abstraction)) whose arguments are all bound and accepted by their setters runs the function's public entry point, so B1 to B8 hold with the same codes. The exception is C, whose setters take bare pointers and no length: a bound series shorter than the range goes undetected there, as in B5. **M2** A rejected setter leaves the parameter holder as it found it, so a rejected re-bind cannot leave the next call to succeed, silently, over a mix of old and new arguments. The layer's own surface (lookup, binding, unbound or mistyped arguments) is not specified. Current behaviour: * Java's `setOptInput` refuses an MA-type value outside the enum, which C, Rust and C# accept and the call answers under B3. Java and C# refuse a null series at the setter. Neither refusal carries a code. * An unbound input or output is reported before B1 in C, Java and C#, and after B2 in Rust ([hub](/spec/#failures)). ## Rules on other pages | Tier | Rules | |---|---| | Lookback | [L1](/spec/lookback/#l1) rejection signal, [L2](/spec/lookback/#l2) agrees with batch, [L3](/spec/lookback/#l3) agrees with C, [L4](/spec/lookback/#l4) nothing else fails | | Stream opening | [S1](/spec/streaming/#s1) empty history, [S2](/spec/streaming/#s2) too long, [S3](/spec/streaming/#s3) parameter, [S4](/spec/streaming/#s4) absent, [S5](/spec/streaming/#s5) length, [S6](/spec/streaming/#s6) aliasing, [S6a](/spec/streaming/#s6a) declined output, [S7](/spec/streaming/#s7) short history | | Stream advancing | [U1](/spec/streaming/#u1) absent handle, [U4](/spec/streaming/#u4) index ceiling, [U2](/spec/streaming/#u2) absent output, [U6a](/spec/streaming/#u6a) declined output, [U3](/spec/streaming/#u3) non-finite bar | | Stream release | [X1](/spec/streaming/#x1) `Close(NULL)` succeeds | | Settings | [G1](/spec/settings-threads/#g1) target, [G2](/spec/settings-threads/#g2) unstable period, [G3](/spec/settings-threads/#g3) reading, [G4](/spec/settings-threads/#g4) range type, [G5](/spec/settings-threads/#g5) average, [G6](/spec/settings-threads/#g6) NaN factor, [G7](/spec/settings-threads/#g7) no change on refusal | ## What is not detected None of these is promised to be reported. The caller avoids them, or treats what follows as undefined. * [I4](/spec/inputs-outputs/#i4): a real input outside plus or minus 3e37. * [I5](/spec/inputs-outputs/#i5): NaN or infinity inside an input array or an opener's history. * [O7](/spec/inputs-outputs/#o7): intermediate overflow on finite input. * [B5](/spec/errors/#b5): a buffer too short, in C. * [N8](/spec/inputs-outputs/#n8): shared memory other than identity, such as partial overlap (C# rejects some; not to be relied on). * [B7](/spec/errors/#b7): the state after an allocation failure. * [G3](/spec/settings-threads/#g3): C's unstable-period getter given a wildcard or unknown id, which returns 0. * [T1](/spec/settings-threads/#t1): C used before `TA_Initialize` or after `TA_Shutdown`. * [T7](/spec/settings-threads/#t7): a C candle setting changed while a stream is open. --- --- url: 'https://ta-lib.org/spec/inputs-outputs/index.md' description: >- What a TA-Lib call accepts and writes: index range, input lengths, optional parameters, value domain, non-finite values, output range and size, argument order, integer and declinable outputs, and aliasing. --- # Inputs and Outputs *Part of TA-Lib's exhaustive [specifications](/spec/), intended for precise AI-agent-driven integration with TA-Lib, to minimize errors.* The contract a correct call meets, and what a successful call writes. Rules use C's spelling; [the hub](/spec/#names) maps it onto Rust, Java and C#. Each rule links or states what happens when a call breaks it; the codes are on the [errors page](/spec/errors/). ## Index range **I1** `startIdx` and `endIdx` are zero-based, inclusive indices into the input series passed. They select the bars to produce output for; bars before `startIdx` are read as history when the lookback needs them. In C# they index the span passed, not the array behind it: a slice holds no bars before its first element, so its lookback comes from inside the slice. Bounds and codes: [B1](/spec/errors/#b1), [B2](/spec/errors/#b2). ## Input series **I2** Every input series a function declares holds at least `endIdx + 1` elements, including one it never reads ([CDLENGULFING](/functions/cdlengulfing) declares `inHigh` and `inLow` and reads neither) and including a range that produces no output. A stream opener's inputs all have the history's length (in C, each holds `historyLen` elements). Checked under [B5](/spec/errors/#b5) and [S5](/spec/streaming/#s5); C cannot check. ## Optional parameters **I3** Each optional parameter's default and accepted values are per function: the Parameters table of its [function page](/functions/), and the same data through the abstraction layer (in C, `TA_GetOptInputParameterInfo`). A NaN or infinite value is outside every real parameter's accepted values, and in Java so is a null `MAType`. A function may also reject a single value inside the listed range, which its page's Notes state: current behaviour, [FRAMA](/functions/frama) rejects an odd `optInTimePeriod`. And a function may reject a combination of values that are each accepted: current behaviour, [MAVP](/functions/mavp) alone does, rejecting `optInMinPeriod > optInMaxPeriod`. Rejections: [B3](/spec/errors/#b3), [S3](/spec/streaming/#s3), [L1](/spec/lookback/#l1). An MA-type parameter accepts every `MAType` member, and a release may add members ([V3](/spec/versions/#v3)). To check a raw integer, use the enum your code was built with, never a fixed list: in C the range `TA_MATYPE_MIN` to `TA_MATYPE_MAX`, in Rust `MAType::try_from`, in Java `MAType.values()`, in C# `Enum.IsDefined`. **N3** A default sentinel selects the function's documented default: `TA_INTEGER_DEFAULT` for an integer parameter, `TA_REAL_DEFAULT` for a real one, the `DEFAULT` member for an MA type (in C, `TA_INTEGER_DEFAULT` works there too). The call is then bit-identical to one passing the default explicitly. A default MA type is not always SMA: APO's is EMA. Spellings per language: [the hub](/spec/#names). ## Values **I4** Every real input value is expected within `TA_REAL_MIN` to `TA_REAL_MAX` (±3e37). Nothing checks the bound: a finite value outside it is accepted everywhere, by `Update` and `Peek` too, and outside it nothing is defined. Non-finite values: [I5](/spec/inputs-outputs/#i5). The bound limits the domain only; it is not an accuracy promise. **I5** A non-finite value (NaN, ±Inf) is handled by where it arrives: | Arrives as | Result | |---|---| | an element of an input series, or of an opener's history | Undefined. Not detected; nothing is promised about the output, or about a handle opened from it. | | a bar passed to Update or Peek | Rejected: [U3](/spec/streaming/#u3), [H4](/spec/streaming/#h4) | | a real optional parameter | Rejected ([I3](/spec/inputs-outputs/#i3)): [B3](/spec/errors/#b3), [S3](/spec/streaming/#s3), [L1](/spec/lookback/#l1) | | a candle setting's factor | The setter's rule: [G6](/spec/settings-threads/#g6) | **I6** Float inputs: C's `TA_S_` functions, and the `float[]` (Java) and `ReadOnlySpan` (C#) overloads, widen each element to double when they read it and compute in double. Their outputs, still `double` or `int`, are bit-identical to the double call on the same values widened. Rust has no float form, and streams take double only. Storing a series as float rounds it, so a float call can differ from a double call on the original values. ## Output range **O1** A successful call reports `begIdx` and `count` (C's `*outBegIdx` and `*outNBElement`). When `count` is above 0, `begIdx` is `max(startIdx, lookback)` ([L5](/spec/lookback/#l5)) and the range ends at `endIdx`: `count = endIdx - begIdx + 1`. Each output is written from index 0, not aligned to the input: `out[i]` is the value for input bar `begIdx + i`, every `i` from 0 to `count - 1` is written, and `out[count - 1]` is the value for `endIdx`. **N1** A valid range that ends before the lookback (`endIdx < lookback`) succeeds with `count` 0: no error, no values. Test `count`; `begIdx` then carries nothing (current behaviour: 0). **N2** Nothing in an output past `count` is written, except where that output is also an input ([N4](/spec/inputs-outputs/#n4)). No native API pads the warm-up with NaN or any other fill value. **O2** Each output needs `count` elements: `endIdx - max(startIdx, lookback) + 1` when that is positive, none otherwise; `endIdx - startIdx + 1` always suffices. `lookback` is the function's lookback for the same parameters and settings ([L5](/spec/lookback/#l5)). Sizing methods: [Output Size and Lookback](/api/#output_size). A shorter output: [B5](/spec/errors/#b5). ## Argument order and several outputs **O3** A batch call takes its arguments in the same order in every language: `startIdx`, `endIdx`, the inputs in the order of the Inputs list on its [function page](/functions/), the optional parameters in the order of its Parameters table, in C `outBegIdx` and `outNBElement`, then the outputs in the order of its Outputs list. Each output is a buffer the caller owns. A function with several outputs reports one range, shared by all of them. How a stream hands back one bar's outputs in each language: [the hub](/spec/#names). ## Integer outputs **O4** What an integer output holds: * **Candlestick patterns** (`CDL*`): 0 means no pattern on that bar. The sign is the pattern's direction (+ bullish, - bearish) or, for some, only the candle's color (+ white, - black); a pattern with neither, such as [CDLDOJI](/functions/cdldoji), reports +100. Current behaviour: every value is 0, ±80, ±100 or ±200. Which values a pattern emits, and what each means, is in the Output Values table on its function page. * **Index outputs** ([MININDEX](/functions/minindex), [MAXINDEX](/functions/maxindex), [MINMAXINDEX](/functions/minmaxindex)): the position of a bar in the input passed (in C#, the span), not relative to `startIdx` or `begIdx`. Which of several tied bars it names is unspecified. In a stream: [H9](/spec/streaming/#h9). * **Other integer outputs** (for example [HT_TRENDMODE](/functions/ht_trendmode)): as their function page says. ## Declinable outputs **O5** An output whose metadata flags include `TA_OUT_NULLABLE` (Rust `OutputFlags::NULLABLE`, Java `OutputFlags.NULLABLE`, C# `OutputFlags.Nullable`) may be declined. Current behaviour: MAMA's `outFAMA` is the only one; read the flag rather than rely on that. Decline it with `NULL` in C, `None` in Rust (the parameter is an `Option`), `null` in Java, an empty span in C#. It is still computed: every other output is bit-identical to the same call with it supplied, and a stream opened that way still reports its value. Any other output cannot be declined; what passing it null or empty does: [B6a](/spec/errors/#b6a), [S6a](/spec/streaming/#s6a), [U6a](/spec/streaming/#u6a). ## Non-finite outputs **O6** A function whose flags include `TA_FUNC_FLG_NAN_INF_OUT` (Rust `FuncFlags::NAN_INF_OUTPUT`, Java `FuncFlags.NAN_INF_OUTPUT`, C# `FuncFlags.NanInfOutput`; "Can Output NaN or ±Inf" on its function page) can write NaN or ±Inf in a successful call on ordinary finite input. The Notes on its function page say when. Current behaviour: the test suite holds every function without the flag to finite output on its datasets. **O7** Intermediate overflow: a running sum, a smoothed value or a ratio against a nearly flat window can leave the range of a double on bars that are each finite. Past that point nothing is defined: not the output, not the return code, not a stream handle's state. Treat such a handle as spent and open a new one. No flag marks this. ## Aliasing **N4** In the batch tier, an output may be the very buffer of an input of the same element type: whole buffer, the same start, and in C# the same span. The outputs are bit-identical to a call with separate buffers, and afterwards the buffer holds the output in `[0, count)`. Past `count` it is not promised to keep the input: current behaviour, [STOCH](/functions/stoch), [STOCHF](/functions/stochf) and [KDJ](/functions/kdj) leave intermediate values there when their first output is in place. Two outputs on one buffer: [B6](/spec/errors/#b6). `OpenAndFill` takes no output on an input or on another output: the identical buffer is rejected ([S6](/spec/streaming/#s6)), and a partial overlap there is [N8](/spec/inputs-outputs/#n8). **N8** Any other shared memory is unspecified: buffers that partially overlap (the same memory from a different start, or in C# a different length), or an output laid over an input of another element type, such as a `TA_S_` call's double output over its float input. Detection stops at identity ([B6](/spec/errors/#b6)); in C such a call can return `TA_SUCCESS` with wrong values. Current behaviour, not to be relied on: C# rejects as `TA_BAD_PARAM` any overlap between two outputs, any overlap between an output and an input other than N4's case, and any overlap across element types. | | C | Rust | Java | C# | |---|---|---|---|---| | "The same buffer" means | the same pointer | not expressible in safe code | the same array | equal spans: same start and length | | Output on an input (N4) | allowed | not expressible | allowed | allowed | | N8's cases expressible | yes | no, in safe code | no | yes | | N8's cases detected | no | n/a | n/a | yes (current behaviour) | --- --- url: 'https://ta-lib.org/spec/lookback/index.md' description: >- How the lookback is defined and queried, how the unstable period, candle averaging and a period of 1 enter it, and how to tell from metadata whether the start of the series matters. --- # Lookback *Part of TA-Lib's exhaustive [specifications](/spec/), intended for precise AI-agent-driven integration with TA-Lib, to minimize errors.* The lookback is how many input bars a function consumes before its first output, set by the optional parameters and the settings in effect, never by the input values. This page owns the lookback call, how the unstable period, candle averaging and a period of 1 enter it, and how to tell whether a value depends on where the series starts. ## Definition {#definition} **L5** The lookback is the number of input bars a function consumes before its first output: over a long enough series read from bar 0, the first output is at bar `lookback` (SMA at period 10 has lookback 9). Where a batch call's output starts, and how many values it writes: [O1](/spec/inputs-outputs/#o1), [N1](/spec/inputs-outputs/#n1), [O2](/spec/inputs-outputs/#o2). How much history a stream needs: [S7](/spec/streaming/#s7). ## Lookback calls {#calls} Every function has a lookback call. It takes exactly the batch call's optional parameters, in the same order, and no input series. A default sentinel selects the default, as in the batch call ([N3](/spec/inputs-outputs/#n3)). Its name and return type in each language: [names](/spec/#names). | Rule | Statement | |---|---| | **L1** | An optional parameter outside its accepted values, or a combination of parameters the function rejects ([I3](/spec/inputs-outputs/#i3)), returns the lookback rejection signal ([per language](/spec/#failures)). | | **L2** | The signal is returned exactly when the batch call, `Open` or `OpenAndFill` would reject the same parameters (batch [B3](/spec/errors/#b3), streams [S3](/spec/streaming/#s3)). | | **L3** | Rust, Java and C# reach the same accept or reject decision as C for the same parameters and settings, and wherever both accept, return the same lookback. Whether their outputs match C's: [D1](/spec/versions/#d1) (Rust), [D2](/spec/versions/#d2) (Java, C#). | | **L4** | Nothing else in this tier fails. | **[Current behaviour](/spec/#reading)**: Java's lookback calls break L1, L2 and L4 for a null MA type. They return a lookback when every null-typed stage runs at period 1 and throw `NullPointerException` otherwise; the batch call rejects every such call under [B3](/spec/errors/#b3). **L6** A lookback depends only on the optional parameters and on the settings in effect at the call: the unstable periods ([L7](/spec/lookback/#l7)) and the candle averaging periods ([L8](/spec/lookback/#l8)). C reads them from the process globals ([T2](/spec/settings-threads/#t2)); Rust, Java and C# from the `Core` the call is made on ([T3](/spec/settings-threads/#t3)). It never depends on an input value. **Current behaviour**: a lookback other than the rejection signal is in `[0, INT_MAX]`, settings at `TA_INDEX_MAX` included. One above `TA_INDEX_MAX` leaves no call able to produce a value. ## Unstable period {#unstable-period} **L7** An unstable period enters the lookback of the function that owns its id, adding exactly that many bars; MINUS_DI, MINUS_DM, PLUS_DI and PLUS_DM at period 1 are the exception, with a lookback of 1 whatever their unstable period. It also enters the lookback of every function computed through the owner, directly or through an MA type the caller selects. There it can count more than once (through EMA, DEMA counts it twice and TEMA three times), or count only where its path is the longest (KC takes the longer of its EMA and ATR paths). No unstable period enters through an MA-type stage at period 1, which copies its input whatever the type (MA itself at period 1, STOCH's slow stages at period 1), nor through the `DISABLED` type, a copy at any period. Its bound is [G2](/spec/settings-threads/#g2). One changed while a stream is open: [T7](/spec/settings-threads/#t7). **Current behaviour** (every function, default parameters), for a batch call reading from bar 0 (`startIdx` at most the lookback before the raise): raising an id's unstable period removes leading outputs from the owner and leaves every value it still reports unchanged, bit for bit. A function computed through the owner can also change the values it still reports (DEMA, MACD, KC), because each inner stage then starts later. The functions that own an id, and how to set one: [Unstable Period](/api/unstable-period/). An inheriting function names its source in the Numerical Stability line of its [function page](/functions/). ## Candle averaging {#candle-averaging} **L8** A candle setting's `avgPeriod` enters the lookback of every CDL function that reads that setting. CDL functions carry `TA_FUNC_FLG_CANDLESTICK` (Rust `FuncFlags::CANDLESTICK`, Java `FuncFlags.CANDLESTICK`, C# `FuncFlags.Candlestick`). Its bound is [G5](/spec/settings-threads/#g5). The model and the defaults: [Candlestick Settings](/api/candle-settings/). A C setting changed while a stream is open: [T7](/spec/settings-threads/#t7). **Current behaviour**: a CDL function's lookback moves with the `avgPeriod` of exactly the settings it reads, never with a range type or a factor; no other function's lookback reads a candle setting. Raising one setting's `avgPeriod` above every other moves a pattern's lookback exactly when the pattern reads that setting. ## Period-1 identity {#period-1-identity} **L9** A function flagged `TA_FUNC_FLG_PERIOD1_IDENTITY` (Rust `FuncFlags::PERIOD1_IDENTITY`, Java `FuncFlags.PERIOD1_IDENTITY`, C# `FuncFlags.Period1Identity`), called with `optInTimePeriod` at 1, writes every output value as a bit-for-bit copy of its input at the same bar (VWMA copies the close). When no unstable period reaches it, its lookback at period 1 is 0. Which functions carry the flag: the "Identity at Period 1" row of each [function page](/functions/) (its tooltip omits the unstable-period case; L9 governs). **Current behaviour**: an unstable period that reaches the function still enters its lookback at period 1, and the values stay copies. With every unstable period at 7, EMA's lookback at period 1 is 7, DEMA's 14 and TEMA's 21. MA at period 1: [L7](/spec/lookback/#l7). ## Start of the series {#start} Whether the value at a bar depends on where the series starts is a function's numerical stability: the categories are on [Numerical Stability](/functions/stability), and each [function page](/functions/) names its own. **Current behaviour** (every function, default parameters): * A batch call reads no bar before `max(startIdx, lookback) - lookback`: changing an earlier bar changes no output. That bar is where the call's series starts, so for a function that is not start-independent, a call with a later `startIdx` is not a slice of a call from 0. * A start-independent function gives the same value at a bar for any `startIdx` only up to rounding error, as much as about 1e-10 of `max(|value|, 1)` (LINEARREG_ANGLE). Never compare such values bit for bit. Detecting each property from metadata: | Property | C | Rust | Java | C# | |---|---|---|---|---| | Owns an unstable-period id | `TA_FUNC_FLG_UNST_PER` | `FuncFlags::UNSTABLE_PERIOD` | `FuncFlags.UNSTABLE_PERIOD` | `FuncFlags.UnstablePeriod` | | Path-dependent | `TA_FUNC_FLG_PATH_DEP` | `FuncFlags::PATH_DEPENDENT` | `FuncFlags.PATH_DEPENDENT` | `FuncFlags.PathDependent` | * **Depends on the MA type**: an optional parameter whose name ends in `MAType`. The abstraction layer describes it as an integer list of the MA types. * **Inherits an unstable period**: no flag marks it (DEMA through EMA). For one call, compare its lookback with every id at 0 and with every id set above that first lookback (the `ALL` wildcard): an unstable period reaches the call, through its own id, a function it computes through or the MA type selected, exactly when the two differ. A stream opened later in a series raises the same question: [H2](/spec/streaming/#h2). --- --- url: 'https://ta-lib.org/spec/streaming/index.md' description: >- The streaming contract in C, Rust, Java and C#: bit-identity with batch, opening and its errors, Update, Peek and Advance, the accessors, and handle lifetime. --- # Streaming *Part of TA-Lib's exhaustive [specifications](/spec/), intended for precise AI-agent-driven integration with TA-Lib, to minimize errors.* A stream is defined as the batch call over every bar fed to it: the same values, bit for bit up to the sign of a zero, and the same range ([H1](/spec/streaming/#h1)); a bar counted with [Advance](/spec/streaming/#h5) enters the range only. This page owns that definition and the error rules of the stream calls. How to call each language's stream API is on that language's streaming page. ## Calls Every function streams ([H10](/spec/streaming/#h10)): `Open` or `OpenAndFill` once, then `Update` per closed bar and `Peek` per forming bar; `Value`, `OutRange`, `Advance` and `Clone` at any time; `Close` in C only. Calls, examples and per-language shapes: [C/C++](/api/stream/), [Rust](/api/rust/stream/), [Java](/api/java/stream/), [C#](/api/csharp/stream/). Rules use C's verbs (`TA__Open` and so on); each language's spelling is in [names](/spec/#names), and how each code reaches the caller in [failures](/spec/#failures). ## Definition **H1** Open a stream on bars 0 to k, then `Update` it with bars k+1 to t, with no `Advance`. At every bar the stream reported (Open's value for bar k, each Update's for its bar), the value is bit-identical to what `batch(0, t)` writes for that bar, and `OutRange` equals the range `batch(0, t)` reports. This holds under the same parameters and settings, with no setting changed since `Open` ([T7](/spec/settings-threads/#t7)). One exception: a zero output may differ in sign, `+0.0` against `-0.0`, which compare equal (current behaviour: seen in functions that take a rolling maximum or minimum, such as MAX, MIN and MIDPOINT). **H2** The history given to `Open` defines bar 0. State is carried forward from bar to bar and never re-seeded, so a stream opened on a later start equals the batch call over that shorter series. Which functions' values depend on the start: [/functions/stability](/functions/stability). ## Opening For `Open` and `OpenAndFill`, the history is the first declared input and `historyLen` its length (a C argument). Rows are in evaluation order ([R2](/spec/errors/#r2)). | Rule | Condition, in evaluation order | Code | Not checked in | |---|---|---|---| | **S1** | The history is empty (`historyLen < 1`) | `TA_OUT_OF_RANGE_START_INDEX` | | | **S2** | The history holds more than `TA_INDEX_MAX + 1` bars | `TA_OUT_OF_RANGE_END_INDEX` | | | **S3** | An optional parameter is outside its accepted values, or the parameters form a combination the function rejects ([I3](/spec/inputs-outputs/#i3)) | `TA_BAD_PARAM` | | | **S4** | A required argument is absent: an input, an output, or C's `outBegIdx` or `outNBElement` | `TA_BAD_PARAM` | Rust, C#: cannot be absent | | **S5** | An input's length differs from `historyLen` ([I2](/spec/inputs-outputs/#i2)), or an `OpenAndFill` output holds fewer than `historyLen - lookback` values | `TA_BAD_PARAM` | C: undefined ([B5](/spec/errors/#b5)) | | **S6** | `OpenAndFill`: an output aliases an input or another output ([N8](/spec/inputs-outputs/#n8)) | `TA_BAD_PARAM` | Rust: cannot alias | | **S6a** | `OpenAndFill`: an output that is not declinable is declined ([O5](/spec/inputs-outputs/#o5)) | `TA_BAD_PARAM` | Rust: cannot decline. C#: no check of its own (current behaviour) | | **S7** | The history holds fewer than [lookback](/spec/lookback/) `+ 1` bars | `TA_INSUFFICIENT_HISTORY` | | * One check precedes S1. C: the `stream` argument itself, NULL answering `TA_BAD_PARAM` with nothing written. Java: a null first input, answering `TA_BAD_PARAM`. Rust and C# have none. * S6a: C and Java decline with `NULL` or `null`, which S4 reports first. C# declines with an empty span, which only S5 bounds: when the history holds `lookback` bars or fewer, S5 requires no values and S7 answers `TA_INSUFFICIENT_HISTORY`, where C and Java answer `TA_BAD_PARAM`. * `TA_INSUFFICIENT_HISTORY` is the one recoverable code: send more bars rather than fix the call. An empty history is S1, not S7, so a loop that waits for enough history starts at one bar. * On S7, a C `OpenAndFill` sets `*outBegIdx` and `*outNBElement` to 0 and writes no output (current behaviour, an exception to [R4](/spec/errors/#r4)). * Non-finite history values: [I5](/spec/inputs-outputs/#i5). **H3** `OpenAndFill` writes what `batch(0, historyLen - 1)` writes, zero signs aside ([H1](/spec/streaming/#h1)): `historyLen - lookback` values per output from index 0, the first for bar `lookback`, and the same range. The handle it opens is the one `Open` opens on the same history. It takes no `startIdx`. ## Advancing `Update`, `Peek` and `Advance`. | Rule | Condition, in evaluation order | Code | Calls | Not checked in | |---|---|---|---|---| | **U1** | The handle is absent | `TA_BAD_PARAM` | all | Rust, Java, C#: cannot be absent | | **U4** | The bar this call would count leaves the index domain: `begIdx + count > TA_INDEX_MAX` | `TA_OUT_OF_RANGE_END_INDEX` | Update, Advance | | | **U2** | A required output is absent: a C out-pointer, a Java multi-output sink | `TA_BAD_PARAM` | Update, Peek | Rust, C#: value returned | | **U6a** | An output that is not declinable is declined ([O5](/spec/inputs-outputs/#o5)) | `TA_BAD_PARAM` | Update, Peek | Rust, Java, C#: nothing to decline | | **U3** | A bar value is NaN, `+Inf` or `-Inf` ([I5](/spec/inputs-outputs/#i5)) | `TA_BAD_PARAM` | Update, Peek | | * Outside both tables: [B8](/spec/errors/#b8) from an opener, and in C from some functions' `Update` and `Peek`; [B7](/spec/errors/#b7) in C from `Open`, `OpenAndFill`, `Clone`, and MAVP's `Update` and `Peek`. * `Peek` is exempt from U4: it counts no bar, so it keeps answering at the ceiling. * **N7** `Peek` never advances the stream and never writes the handle, whatever its outcome and however often it is called. Its value is bit-identical to what the next `Update` with the same bar returns. * **H4** A rejected `Update` or `Peek` changes nothing: no state, no value, no range, no output variable written. Answer a rejected bar by re-feeding it with a corrected value, or by counting it with `Advance` ([H5](/spec/streaming/#h5)); doing neither leaves the handle one bar behind the feed. U4 never clears: open a new handle on a shorter history. [B7](/spec/errors/#b7), [B8](/spec/errors/#b8) and [O7](/spec/inputs-outputs/#o7) are outside this rule. * **H5** `Advance` counts one bar the handle was not fed: the range grows by one and nothing else moves. That bar's output is the previous one, held, and `Value` answers it. Later Updates compute over the bars fed, as if the counted bar did not exist; only the range includes it. * A declination binds only its own call: the set an `Update` or `Peek` declines may differ from the opener's and from the previous call's. * An accepted bar whose output is not finite ([O6](/spec/inputs-outputs/#o6), such as LN on 0) is a success: the state advances, `Value` answers that value, and the range grows by one. ## Accessors **H6** `Value` returns the value(s) at the last counted bar, the bar the range ends on, without recomputing: after `Open` the last history bar's, after an accepted `Update` that bar's, after `Advance` the held value. `OutRange` is `[begIdx, begIdx + count)` in the input series' coordinates: the batch range over the same bars, Advance-counted bars included. `begIdx + count` never exceeds `TA_INDEX_MAX + 1`. **H7** `Clone` is a deep, independent fork at the same bar: the same state, value and range, and updating either never affects the other. The C accessors' error surface: | C call | `TA_BAD_PARAM` when | Other codes | |---|---|---| | `Value` | the stream is NULL, or a required output pointer is NULL; a declinable one may be NULL and is not written | none | | `OutRange` | the stream or either out-pointer is NULL | none | | `Advance` | the stream is NULL | U4 | | `Clone` | the stream or `clone` is NULL | `TA_ALLOC_ERR` | | `Close` | never | none | In Rust, Java and C#, only `Advance` (U4) and Java's multi-output `value(out)` (`TA_BAD_PARAM` for a null sink) reject anything. ## Lifetime * **C ownership.** Close every handle that `Open`, `OpenAndFill` or `Clone` returns, exactly once; `Close` frees it. When one of them fails, it sets its handle out-parameter (`*stream`, `*clone`) to NULL unless that argument is itself NULL ([B7](/spec/errors/#b7) aside), so never open or clone into a variable that holds a live handle. A failed `Clone` leaves the original untouched. * **X1** `Close(NULL)` is a success no-op. Only C has a release call; Rust drops a handle and Java and C# collect it. * **H8** A handle is not serializable and is valid only within the library version that opened it. To checkpoint, keep the history, the bars fed since and the number of bars counted with `Advance`; reopen on the bars and call `Advance` that many times ([H1](/spec/streaming/#h1), [H5](/spec/streaming/#h5)). * Threads on one handle: [T4](/spec/settings-threads/#t4). A setting changed while a stream is open: [T7](/spec/settings-threads/#t7). ## Index outputs **H9** In a stream, the index outputs of MININDEX, MAXINDEX and MINMAXINDEX count the bars fed to the handle: the history, then each accepted `Update`. A bar counted by `Advance` is not fed, so after an `Advance` an index no longer equals that bar's position in the range. Example in C, MININDEX at period 3: open on 6 bars, `Advance`, then `Update` with a new low; the stream answers 6, where batch over all 8 bars, the skipped one included, answers 7. ## Discovery **H10** Every function streams, in every language. The metadata flag is `TA_FUNC_FLG_STREAM`: Rust `FuncFlags::STREAM`, Java `FuncFlags.STREAMING`, C# `FuncFlags.Stream`. A stream is opened by its typed `Open`; the abstraction layer binds batch calls only. --- --- url: 'https://ta-lib.org/spec/settings-threads/index.md' description: >- C initialization and process-global settings, the immutable Core of the Rust, Java and C# APIs, setting validation, and what is safe across threads and under a live stream. --- # Settings and Threads *Part of TA-Lib's exhaustive [specifications](/spec/), intended for precise AI-agent-driven integration with TA-Lib, to minimize errors.* C keeps its settings (unstable periods and candle settings) in process globals that are set before any concurrent use; Rust, Java and C# keep them in an immutable `Core`. This page owns the C lifecycle, the rules every setter and getter enforces, and what may run concurrently. What each setting means: [Unstable Period](/api/unstable-period/), [Candlestick Settings](/api/candle-settings/) (with the defaults). Names per language: [names](/spec/#names). How a refusal reaches the caller: [failures](/spec/#failures). ## C lifecycle **T1** Call `TA_Initialize` once, from one thread, before any other TA call, and again before using the library after `TA_Shutdown`. It sets every unstable period to 0 and every candle setting to its default. Call `TA_Shutdown` from one thread while no other TA call runs. Rust, Java and C# have no lifecycle call: a `Core` is ready when constructed. Current behaviour in C: * Nothing checks that `TA_Initialize` was called, and every setter works without it. Without it, or after `TA_Shutdown`, every setting the caller has not set is zero: CDL functions drop the averaging period from their lookback (`TA_CDL3BLACKCROWS_Lookback` gives 3 instead of 13) and return `TA_SUCCESS` with values judged against zero thresholds. Zero is also an unstable period's initialized value, so only CDL functions are affected. * Every `TA_Initialize`, the first included, returns `TA_SUCCESS` and discards whatever was set before it. * When it succeeds, `TA_Shutdown` sets every unstable period and every candle setting to zero and releases nothing. It returns `TA_LIB_NOT_INITIALIZE`, and changes nothing, when `TA_Initialize` has not been called since the process started or since the last successful `TA_Shutdown`. ## C settings **T2** Unstable periods and candle settings are process-global, unsynchronized memory. Change them (`TA_SetUnstablePeriod`, `TA_SetCandleSettings`, `TA_RestoreCandleDefaultSettings`, and `TA_Initialize` or `TA_Shutdown`, which reset them) from one thread while no other TA call runs. Once they are set, batch calls, lookbacks, streams (under [T4](/spec/settings-threads/#t4)) and the abstraction layer, each thread with its own `TA_ParamHolder` ([T6](/spec/settings-threads/#t6)), may run on any number of threads. The library allocates with `malloc` and `free` and assumes both are thread-safe; an allocation failure is [B7](/spec/errors/#b7). How the settings enter a result: [L7](/spec/lookback/#l7) (unstable period), [L8](/spec/lookback/#l8) (candle averaging), [T7](/spec/settings-threads/#t7) (open streams). ## Managed cores **T3** In Rust, Java and C#, settings live on an immutable `Core` made by a builder. There are no process-global settings. One `Core` may be shared by any number of threads with no synchronization: Rust's is `Send + Sync`, Java's has only final, deeply immutable fields and is safe even when published racily, and C#'s cannot change once built. To change a setting, build another `Core`, from defaults or seeded from an existing one (`to_builder()`, `toBuilder()`, `ToBuilder()`); the existing one is unchanged. A Java or C# builder stays usable after `build()`, and later changes to it never reach a `Core` it built. Java's and C#'s `build()` cannot fail. How a refused setter call reaches the caller in each language: [failures](/spec/#failures) and [G7](/spec/settings-threads/#g7). ## Validation The rows hold for every setter and getter in all four languages, except where a note says otherwise. Within one language every row refuses the same way, so [R2](/spec/errors/#r2) leaves their order open. Java tests for a null argument before any row. | Rule | Condition | Language notes | |---|---|---| | **G1** | A setter refuses a target outside its enum, and a setter that takes a single target refuses the set-all wildcard. | Rust and Java enums cannot hold an out-of-domain target, so only the wildcard is refused there. | | **G2** | An unstable period is in `[0, TA_INDEX_MAX]`. | C takes an `unsigned int`, so a negative value arrives above `TA_INDEX_MAX` and is refused. Rust's `u32` cannot hold one. | | **G3** | Reading a setting for a target that names no single function or setting is refused. | C's `TA_GetUnstablePeriod` cannot refuse: it returns 0, which is also a legal period. The getters on `Core` refuse ([failures](/spec/#failures)): Rust `get_unstable_period`, Java `unstablePeriod`, C# `UnstablePeriod` and `CandleSettings`, the only candle-setting getter. | | **G4** | A candle setting's range type is a `TA_RangeType` member. | Checked in C and C#. Rust and Java cannot express another value. | | **G5** | A candle setting's `avgPeriod` is in `[0, TA_INDEX_MAX]`. | | | **G6** | A candle setting's `factor` is not NaN. An infinite factor is accepted. | | | **G7** | A refused call leaves every setting as it was, a wildcard call included. | Rust's builder latches the first refusal until `build()`: a later valid setter or `restore_candle_default` does not clear it, and `to_builder()` starts with none latched. | **N6** A wildcard is legal where a call documents one. `TA_FUNC_UNST_ALL` (`FuncUnstId::ALL`, `FuncUnstId.ALL`) sets every unstable period at once. `TA_AllCandleSettings` restores every candle setting's default through `TA_RestoreCandleDefaultSettings` and the builders' restore call (`restore_candle_default`, `restoreCandleDefault`, `RestoreCandleDefault`). Elsewhere G1 or G3 applies. A reserved `UNUSED_n` id is in domain: every setter and getter accepts it, and it moves no function (current behaviour). **N5** A negative `factor` is accepted in all four languages. On bars with `low <= min(open, close)` and `max(open, close) <= high` every candle range is non-negative, so with a positive average a negative factor gives a negative threshold ([model](/api/candle-settings/)): every test that a range is above it passes, and every test that a range is at or below it fails. For example, with a negative `BodyDoji` factor, CDLDOJI, whose test is at or below, fires on no bar with a positive average. Check a pattern's tests before relying on a negative factor. ## Threads **T4** A stream handle has one writer. `Update`, `Advance` and C's `Close` must not run concurrently with any other call on the same handle. With no writer running, `Peek`, `Value`, `OutRange` and `Clone` may run concurrently on it, since none of them writes the handle (for `Peek`, also [N7](/spec/streaming/#n7)): C declares all four on a `const` handle; Rust on `&self`, so the compiler enforces this rule, and every Rust handle is `Send + Sync + Clone`; Java and C# allow it once the handle has been safely published to the reading threads. Separate handles, a clone included, share nothing writable, so each may be driven on its own thread. **T5** A Java multi-output stream writes its results into a caller-owned sink (`Core.MacdOut` for MACD) on `update`, `peek` and `value`. The sink carries no publication guarantee: give each thread its own. The other languages' carriers: [names](/spec/#names). **T6** A parameter holder (C `TA_ParamHolder`, Java and C# `ParamHolder`) is not thread-safe, and in Java and C# neither is a `CoreBuilder`: confine each to one thread, or make one per call. In C, the `const` in `TA_CallFunc`'s signature does not make a holder shareable: the call writes the output buffers bound to the holder, and the setters write the holder itself, with no synchronization. The function catalogs (Java `Functions`, C# `FunctionCatalog`, Rust `FUNCS`) are immutable and shared freely. Rust's builder setters take the builder by value and its `ParamHolder` setters and `call` take `&mut self`, so the compiler confines both. ## Settings under a live stream **T7** What a stream sees when a setting changes after Open: | Setting | C | Rust, Java, C# | |---|---|---| | Unstable period | Read once, at Open. A later change applies to later opens, batch calls and lookbacks, never to an open handle, so `TA__Lookback` may then disagree with that handle's range (current behaviour). | The `Core` that opened the handle cannot change. To stream with other settings, open from another `Core`. | | Candle settings | Changing one while a CDL stream is open, by any call including `TA_Initialize` and `TA_Shutdown`, is undefined. Close the stream and open a new one. | The `Core` that opened the handle cannot change. | What an open handle's values equal: [H1](/spec/streaming/#h1). --- --- url: 'https://ta-lib.org/spec/versions/index.md' description: >- Which TA-Lib results are bit-identical across languages, machines, C builds and equivalent calls, and what a release keeps and may add. --- # Versions and Determinism *Part of TA-Lib's exhaustive [specifications](/spec/), intended for precise AI-agent-driven integration with TA-Lib, to minimize errors.* D1 to D4 say where the same call gives the same bits across languages, machines and C builds; the table below also indexes the equivalences other pages own. V1 to V4 say what a release keeps and what it may add. ## Determinism {#determinism} On this page, **bit-identical** means the same return code, the same output range, and every output element with the same bits, except that a NaN matches any NaN: no math library specifies a NaN's payload. **The same call** means the same function, input values, `startIdx` and `endIdx`, optional parameters and settings. **The same settings** means the same unstable periods and candle settings; in C that includes having called `TA_Initialize` ([T1](/spec/settings-threads/#t1)). | Compared | Result | Rule | |---|---|---| | the same call in C and Rust, one machine | bit-identical | [D1](/spec/versions/#d1) | | the same call in Java or C# and in C, one machine | bit-identical, except a call that evaluates a transcendental function | [D2](/spec/versions/#d2) | | the same call in one backend on two machines | bit-identical, except a call that evaluates a transcendental function | [D3](/spec/versions/#d3) | | C built from source | bit-identical only under D4's conditions | [D4](/spec/versions/#d4) | | the same bar from batch calls with different `startIdx` | not bit-identical in general | [Lookback](/spec/lookback/#start) | | a stream and the batch call over the same bars | bit-identical but for a zero's sign, under H1's conditions | [H1](/spec/streaming/#h1) | | `OpenAndFill` and the batch call over its history | bit-identical but for a zero's sign | [H3](/spec/streaming/#h3) | | `Peek` and the next `Update` with the same bar | bit-identical | [N7](/spec/streaming/#n7) | | a `Clone` and its original | the same state, value and range | [H7](/spec/streaming/#h7) | | a default sentinel and the explicit default | bit-identical | [N3](/spec/inputs-outputs/#n3) | | an output in place on its input, and in a separate buffer | bit-identical | [N4](/spec/inputs-outputs/#n4) | | a declinable output declined, and supplied | the other outputs bit-identical | [O5](/spec/inputs-outputs/#o5) | | a `float` input, and the `double` call on its widened values | bit-identical | [I6](/spec/inputs-outputs/#i6) | ### Transcendental functions {#transcendental} A **transcendental function** here is `exp`, `log`, `log10`, or a trigonometric, inverse trigonometric or hyperbolic function. C and Rust take it from the platform's C math library, Java from the JVM, C# from the .NET runtime, and none of them is required to round it correctly. A call evaluates one when its function does, or when an MA-type parameter selects an average that does. **Current behaviour**: the functions that do are ACOS, ALMA, ASIN, ATAN, CHOP, CHOPTR, COS, COSH, EXP, FRAMA, HT_DCPERIOD, HT_DCPHASE, HT_PHASOR, HT_SINE, HT_TRENDLINE, HT_TRENDMODE, LINEARREG_ANGLE, LN, LOG10, MAMA, SIN, SINH, TAN and TANH, and the averages that do are `MAMA` and `ALMA`. Where D2 or D3 lets such a call differ, the difference starts in the last bit of one result and can grow through the function's arithmetic. It can also jump: HT_DCPHASE, HT_SINE, HT_TRENDLINE and HT_TRENDMODE round a period computed with `atan` to the nearest whole number of bars, and on a constant series HT_DCPHASE and HT_SINE take `atan` of a ratio of rounding residues, where a last-bit difference can move the phase by whole degrees. Compare these calls with a tolerance, and expect the HT\_\* outputs to differ outright on some inputs. **D1** On one machine, C built as [D4](/spec/versions/#d4) requires and Rust are bit-identical, transcendental functions included. **D2** On one machine, Java and C# are bit-identical to C built as [D4](/spec/versions/#d4) requires, for every call that evaluates no transcendental function. A call that evaluates one may differ from C's; whether it does depends on the runtime and the host. **D3** Between machines (operating system, math library, CPU), a call that evaluates no transcendental function is bit-identical in every backend, C built as [D4](/spec/versions/#d4) requires. Every fused multiply-add is explicit in the source (C `fma`, Rust `mul_add`, Java `Math.fma`, C# `Math.FusedMultiplyAdd`), so a CPU with or without an FMA unit gives the same bits. A call that evaluates a transcendental function may differ between machines. **D4** The C sources give [D1](/spec/versions/#d1) and [D3](/spec/versions/#d3) only when the compiler evaluates every `double` operation as written. Stated for GCC and Clang: | Condition | GCC and Clang | Build files in the source tree | |---|---|---| | no contraction of `a*b+c` into a fused multiply-add | `-ffp-contract=off` | CMake passes it to every compiler but MSVC and those taking MSVC's command line (clang-cl); autotools passes it when the compiler accepts it | | no value-changing optimization | no `-ffast-math` or `-Ofast`, nor any part of them but `-fno-math-errno` | none uses them | | no extended-precision intermediates | on 32-bit x86, `-msse2 -mfpmath=sse` | only CMake's i386 cross-build toolchain, `cmake/toolchain-linux-i386.cmake`; a native 32-bit x86 build with CMake or autotools does not pass it, so add it yourself | Neither the optimization level, `-march`, nor `-fno-math-errno` (which CMake and autotools also pass to a compiler that accepts it) changes a value. Under MSVC, or clang-cl, CMake passes no floating-point option, so the compiler's defaults apply; D4 names no condition for them, and D1 and D3 are not promised for C built with them. **Current behaviour**: no `/arch:AVX2` is passed there, so the compiler has no FMA instruction to contract into. D4 concerns C only. ## Releases {#releases} **V1** Within one ABI generation N (the N of the soname `libta-lib.so.N`; the table below shows it on each platform), no function or callback signature, struct layout, typedef, enum value or `TA_` constant that a release shipped in the installed C headers is removed or changed, except that `TA_MATYPE_MAX` and `TA_FUNC_UNST_COUNT` follow their enums ([V3](/spec/versions/#v3)). A release that removes or changes one starts a new N; additions keep it. Deprecated names are part of that surface and keep compiling and linking. V1 covers declarations, not values ([not covered](/spec/versions/#not-covered)). `TA_LIB_SOURCES_DIGEST` is outside V1; it changes whenever the sources do. Rust, Java and C# have no ABI generation, and V1 does not apply to them. | Platform | Carrier | A program built against an earlier release with the same N | |---|---|---| | Linux | soname `libta-lib.so.N` | links and runs against a later one without rebuilding | | macOS | install name `libta-lib.N.dylib` | links and runs against a later one without rebuilding | | Windows | none: the DLL's name carries no N (`ta-lib.dll` under MSVC) | gets no signal at link or load time when N changes; rebuild against the headers of the DLL you ship | **V2** No enum member is renumbered, in any backend. A retired member keeps its number under a reserved name (`TA_FUNC_UNST_UNUSED_1` and the like) instead of being deleted. `TA_AllCandleSettings` is pinned at 11 and `TA_FUNC_UNST_ALL` at 65535; neither tracks the number of members. A Rust, Java or C# enum may omit C members; each member it has carries C's number. Reading the number: for `RetCode`, see the [hub](/spec/#failures); for the other enums, Rust `as i32`, Java `value()` on `FuncUnstId` and `ordinal()` on `MAType`, `RangeType` and `CandleSettingType`, C# an `(int)` cast. **Current behaviour**: new members have been appended. A reserved `UNUSED_n` slot is documented as reusable, so a later release may give its number to a new member; in C that removes the reserved name, which V1 counts as a change, so it comes with a new N. **V3** A release may add functions, MA types, unstable-period ids, candle settings and return codes. Enumerate functions through the abstraction layer (`TA_ForEachFunc` in C; each language's catalog is in the hub's [abstraction layer](/spec/#abstraction) table), never from a list fixed when your code was written. `TA_MATYPE_MAX` and `TA_FUNC_UNST_COUNT` grow when a member is appended to their enum; how to bound an MA-type value is [I3](/spec/inputs-outputs/#i3). Rust marks `RetCode`, `FuncUnstId`, `MAType`, `RangeType` and `CandleSettingType` `#[non_exhaustive]`, so a `match` on one needs a wildcard arm; give a Java or C# `switch` over them a default branch. **V4** In the function tier, the id a C internal error carries ([B8](/spec/errors/#b8)) is never reassigned: a later release keeps it on the same guard or retires it, so a reported number identifies the guard whichever release produced it. ### Not covered {#not-covered} * **Output values from one release to the next.** No rule is published, and a release can change a function's values behind an unchanged declaration. Validate against the release you ship. * **API compatibility of the Rust, Java and C# packages between releases**, beyond V2 and V3. No rule is published. * **Which versions and packages exist**: [Install](/install/). --- --- url: 'https://ta-lib.org/api/index.md' description: >- Calling TA-Lib from C/C++: initialization, the batch calling pattern, sizing outputs with the lookback, return codes, the abstraction layer and thread safety. --- # C/C++ Core API

1.0 Introduction

2.0 How to add TA-Lib to your app

3.0 Calling into TA-Lib

3.1 Initialize and Shutdown
3.2 Batch Processing
3.3 Output Size and Lookback
3.4 Return Codes

4.0 Advanced Features

4.1 Abstraction Layer
4.2 Numerical Stability
4.3 Candlestick Settings
4.4 Input Type: float vs. double
4.5 Index Range
4.6 High-performance Multi-threading

## 1.0 Introduction {#intro}

The Core API provides:

To process a live feed one bar at a time instead, see the companion C/C++ Streaming API.

You must first install the C/C++ library, which will provide all the shared/static libraries and headers needed to compile and link your program.

## 2.0 How to add TA-Lib to your app {#build}

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 the compiler's and linker's search paths. For example, with gcc: ```sh -I/usr/local/include/ta-lib -L/usr/local/lib -lta-lib ``` The paths depend on the method used to install. Typical locations for headers (`-I`) are: * `/usr/local/include/ta-lib` * `/usr/include/ta-lib` * `/opt/include/ta-lib` Typical locations for the libraries (`-L`) are: * `/usr/lib` * `/usr/lib64` * `/usr/local/lib` * `/usr/local/lib64` * `/opt/lib` * `/opt/local/lib` For [homebrew](https://formulae.brew.sh/formula/ta-lib), use brew --prefix ta-lib to find the paths. For Windows, look into C:\Program Files\TA-Lib for 64-bit and C:\Program Files (x86)\TA-Lib for 32-bit. ## 3.0 Calling into TA-Lib {#ta_func}

All of TA-Lib's public functions are declared in headers.

### 3.1 Initialize and Shutdown {#init}
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 three 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 {#direct_call}

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 four 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). For a moving-average type, use TA_MAType_DEFAULT.
  • 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:

double closePrice[400];
double out[400];
int    outBeg;
int    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):

double closePrice[300];
double out;
int    outBeg;
int    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
double 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 and Lookback {#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.

### 3.4 Return Codes {#retcode}

Every TA function returns a TA_RetCode. TA_SUCCESS (zero) means the call completed and wrote its outputs; on anything else, treat outBegIdx and outNBElement as undefined and the output buffers as untouched. TA_ALLOC_ERR is the exception: it is fatal, and nothing about the call is defined past it.

The codes a caller normally encounters:

| Code | Meaning | |------|---------| | `TA_SUCCESS` | No error. | | `TA_LIB_NOT_INITIALIZE` | [TA_Initialize](#init) was not called, or did not succeed. | | `TA_BAD_PARAM` | A parameter is out of range, or a required pointer is NULL. | | `TA_ALLOC_ERR` | Allocation failed, most likely out of memory. Fatal: nothing about the call is defined past it. | | `TA_OUT_OF_RANGE_START_INDEX` | startIdx is negative or above [TA_INDEX_MAX](#index_range). | | `TA_OUT_OF_RANGE_END_INDEX` | endIdx is negative, above [TA_INDEX_MAX](#index_range), or below startIdx. |

The full list is the TA_RetCode enumeration in ta_defs.h. Rather than mapping the codes yourself, TA_SetRetCodeInfo turns any of them - including one this version of the library does not know - into a printable name and description:

```c TA_RetCodeInfo info; if( retCode != TA_SUCCESS ) { TA_SetRetCodeInfo( retCode, &info ); printf( "Error %d(%s): %s\n", retCode, info.enumStr, info.infoStr ); } ```

which prints, for example:

``` Error 1(TA_LIB_NOT_INITIALIZE): TA_Initialize was not successfully called ```

The TA_XXXX_Lookback functions are the exception to the pattern: they return an int rather than a TA_RetCode, and answer -1 when a parameter is out of range. Check for that before using the value as an allocation size.

## 4.0 Advanced Features {#advanced} ### 4.1 Abstraction Layer {#abstract}

Instead of hard-coding calls to specific TA functions, an app can look them up by name at runtime through the interface in ta_abstract.h. For any function it reports:

  • the inputs it takes,
  • its optional parameters with their valid ranges,
  • the outputs it produces, and
  • metadata about numerical properties and suggested default, range and display hints.

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 {#numerical_stability}

Your value changed when you fed the same bar more history? That is by design: recursive functions converge as history accumulates. See Unstable Period for how to mitigate that.

Rounding is a separate axis: floating-point error accumulates over a very long series, which is one reason a call is capped at TA_INDEX_MAX.

Every function documentation page carries a numerical-stability property: how much the value at a given bar depends on where the series you passed in begins.

### 4.3 Candlestick Settings {#candle_settings}

The candlestick pattern functions (TA_CDL*) judge each candle against tunable thresholds — is its body "long", its shadow "short", two candles "near". These thresholds are global settings: change them once, from a single thread, before any concurrent calls (see multi-threading).

See the Candlestick Settings page for the API, the setting types and their defaults.

### 4.4 Input Type: float vs. double {#input_type}

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.5 Index Range {#index_range}

TA_INDEX_MAX is the largest value startIdx or endIdx may take: 100,000,000. A call outside the range is rejected rather than computed:

| Condition | Return code | |-----------|-------------| | `startIdx < 0` or `startIdx > TA_INDEX_MAX` | `TA_OUT_OF_RANGE_START_INDEX` | | `endIdx < 0`, `endIdx > TA_INDEX_MAX`, or `endIdx < startIdx` | `TA_OUT_OF_RANGE_END_INDEX` |

For context on the size: 100 million one-minute bars is about 190 years of 24/7 data, or over a millennium of a regular equity session (6.5 hours/day, 252 sessions/year).

TA_INDEX_MAX is a sanity bound. Past it, a call is more likely a caller bug than a real need, and it's also untested territory for overflow and rounding error.

### 4.6 High-performance Multi-threading {#multithreading}

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 at the other end is TA_Shutdown, which is single-threaded as well.

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.

--- --- url: 'https://ta-lib.org/api/stream/index.md' description: >- The TA-Lib C/C++ streaming API for live feeds: open a stream once, feed one bar at a time without recomputing the history, with values bit-identical to the batch functions. --- # C/C++ Streaming API 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 a new bar never costs a pass over the history: most indicators do constant work per bar, and the ones that work over their window, such as AVGDEV, CCI, MEDIAN and the rolling extremes, take time at most proportional to the window's length. Every value is **bit-identical** to what the [batch function](/api/) (`TA_SMA`, `TA_RSI`, …) would return by recomputing over the whole array. Every TA function gets these calls: | Call | When | Does | |------|------|------| | `TA__Open` | once | validate params, consume warm-up history, return a **stream** + current value | | `TA__Update` | once per **closed** bar | commit one bar, return the new value | | `TA__Peek` | any time on the **forming** bar | evaluate a provisional bar **without** committing state | | `TA__Close` | once | free the stream | One more call, `OpenAndFill`, writes array output instead of a single value — see [Array-Fill Open](#array-fill-open) below. Additional [utility functions](#utility-calls) are available. ## Example (SMA) ```c 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.** `Open` succeeds only if `historyLen >= TA__Lookback(params) + 1` — with fewer bars there is no defined value yet. After `Open`, the history buffer can be freed — the stream keeps everything it needs. * **Closed vs forming bar.** `Update` commits state irreversibly, so use it only for **closed** bars. `Peek` returns the exact value `Update` would, 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](/api/#numerical_stability) and [candle settings](/api/#candle_settings) are first read at `Open` and must not change during the stream's life. * **Threads.** A stream is single-writer: an `Update` or `TA__Advance` must 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. ## Multi-input / multi-output Inputs and outputs mirror the batch function — OHLCV in, one out-pointer per output: ```c /* 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](/api/) would produce — while still opening the stream: | Call | When | Does | |------|------|------| | `TA__OpenAndFill` | once, instead of `Open` | like `Open`, but returns the output for **every** history bar | ```c 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__Value` | any time | the value(s) at the last bar the stream counted, without recomputing | | `TA__Clone` | any time | an independent fork of the stream, at the same bar | | `TA__OutRange` | any time | the bars the stream has an output for — the batch range over the same bars | | `TA__Advance` | after a bar you will not feed | advances the OutRange without affecting any other internal state of the stream | ```c 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](#rules) for when concurrent reads of these are safe. ## Error model | Call | Returns | |------|---------| | `TA__Open` / `TA__OpenAndFill` |
  • `TA_INSUFFICIENT_HISTORY` when `historyLen` is below `lookback + 1` — the one failure worth retrying, since another bar might fix it
  • `TA_OUT_OF_RANGE_START_INDEX` when `historyLen` is 0
  • `TA_OUT_OF_RANGE_END_INDEX` when `historyLen` exceeds `TA_INDEX_MAX + 1`
  • `TA_BAD_PARAM` — a NULL pointer, or a parameter out of range
  • `TA_ALLOC_ERR` — a memory allocation failure
On any of these, `*stream` is NULL. | | `TA__Update` / `TA__Peek` |
  • `TA_BAD_PARAM` on NULL arguments, or invalid input such as NaN or ±Inf
  • `TA_OUT_OF_RANGE_END_INDEX` once the range has reached bar `TA_INDEX_MAX`, the last index the batch API addresses
  • `TA_ALLOC_ERR`: a memory allocation failure
Apart from `TA_ALLOC_ERR`, after which nothing is defined, a rejection changes nothing at all: no state, no output and no range. The next call sees exactly what the last accepted bar left. | | `TA__Close` | `TA_SUCCESS`; `TA__Close(NULL)` is a no-op | | `TA__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__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__OutRange` | `TA_BAD_PARAM` on a NULL argument | | `TA__Advance` | `TA_BAD_PARAM` on a NULL argument; `TA_OUT_OF_RANGE_END_INDEX` once the range has reached bar `TA_INDEX_MAX` | ## Discovering streamable functions When driving TA-Lib through the [abstraction layer](/api/#abstract), streamable functions carry the `TA_FUNC_FLG_STREAM` flag in their function info. --- --- url: 'https://ta-lib.org/api/rust/index.md' description: >- The ta-lib Rust crate: a native port with no C bindings, indicators as methods on Core over f64 slices, bit-identical to the reference C library. --- # Rust Core API ::: warning Not yet released The Rust API is not yet released. Estimated release: **Q1 2027**. :::

1.0 Introduction

2.0 Add it to your project

3.0 Calling into TA-Lib

3.1 Batch Processing
3.2 Output Size and Lookback
3.3 Results and Return Codes

4.0 Advanced Features

4.1 Abstraction Layer
4.2 Numerical Stability
4.3 Candlestick Settings
4.4 Index Range
4.5 Threading

5.0 Documentation

## 1.0 Introduction {#intro} The `ta-lib` crate is a native Rust port of TA-Lib — no C bindings, no `unsafe` at the call site. Every indicator is a method on `Core`, operates on `f64` slices, and is **bit-identical** to the reference C library over the same inputs. The **Core API** provides: * The [`Core`](#direct_call) type and the builder that configures it. * The settings each `Core` carries: [unstable period](/api/unstable-period/) and [candlestick settings](/api/candle-settings/). Multiple `Core` instances can safely co-exist (say for different settings). * Every TA function, each processing a whole array of data at once. * An optional [abstraction layer](#abstract) for calling those functions dynamically. To process a live feed one bar at a time instead of a whole array, see the companion [Rust Streaming API](/api/rust/stream/). There is no initialization step and nothing to shut down. Where C requires `TA_Initialize` before any call and `TA_Shutdown` at exit, Rust has `Core::new()`, and the `Core` is dropped like any other value. ## 2.0 Add it to your project {#build} ```toml [dependencies] ta-lib = "0.8" ``` ## 3.0 Calling into TA-Lib {#ta_func} ### 3.1 Batch Processing {#direct_call} Every function follows the same simple pattern: it reads its inputs from slices you pass in and writes its results into slices you allocate. A function never writes more elements than you request, so the output slice only needs to cover the `startIdx`-to-`endIdx` range. As an example, let's walk through `MA`, a method to calculate a moving average.
fn ma( &self,
       startIdx: usize,
       endIdx: usize,
       inReal: &[f64],
       optInTimePeriod: i32,
       optInMAType: MAType,
       outReal: &mut [f64] ) -> Result<OutRange, RetCode>
All TA functions use the same calling pattern, divided into four groups:
  • The output will be calculated only for the range specified by startIdx and endIdx. These are zero-based indices into the input slices.
  • One or more input slices 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 pass Core::INTEGER_DEFAULT, Core::REAL_DEFAULT or MAType::DEFAULT (depending on the type), and the function substitutes its documented default.
  • One or more output slices come last. In this example there is only one output (outReal). Where the values landed is the return value, not a parameter: on success you get an OutRange.
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:
use ta_lib::{Core, MAType, RetCode};

let core = Core::new();

// ...initialize your closing prices here...
let close: Vec<f64> = vec![0.0; 400];
let mut out = vec![0.0; 400];

let range = core.ma( 0, 399,
                     &close,
                     30, MAType::SMA,
                     &mut out )?;

// The output is displayed here
for i in 0..range.count {
    println!("Day {} = {}", range.beg_idx + i, out[i]);
}
After the call, read `range` to learn what was produced. Even though we requested the whole range (0 to 399), a 30-day average is not defined until the 30th day. Consequently, `range.beg_idx` will be 29 (zero-based) and `range.count` 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, `range.beg_idx` would be 125 and `range.count` 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 one, at index 299):
let range = core.ma( 299, 299,
                     &close,
                     14, MAType::EMA,
                     &mut out )?;
In this example, `range.beg_idx` will be 299, `range.count` will be 1, and only one value is written into `out`. If you do not provide enough data to calculate even one value, the call still succeeds and `range.count` is 0 — `range.is_empty()` says so directly. The input and the output are separate borrows, so a function cannot read and write the same buffer: pass a distinct output slice, and copy it back afterwards if you want the result in place. `Core` is cheap to create and holds only the library's settings; construct one and reuse it. ### 3.2 Output Size and Lookback {#output_size} It is important that the output slice is large enough — an undersized slice is `Err(RetCode::BadParam)`, never a write past the end. Here are three ways to determine the allocation size; all of them work for every TA function: | Method | Description | |------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------| | Input Matching | `allocation_size = endIdx + 1;`
**Pros**: Easy to understand and implement.
**Cons**: Memory allocation unnecessarily large when requesting a small range. | | Range Matching | `allocation_size = 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 | Derived from the function's lookback — see the example below.
**Pros**: Allocates exactly what is needed.
**Cons**: Slightly more complex, and the only one that has to handle an out-of-range parameter. | Each TA function has a matching `_lookback` method, taking the same optional parameters as the function itself. Example: for `SMA` it is `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. ```rust let lookback = core.sma_lookback(30)?; // 29 for a 30-period SMA ``` A lookback method returns `Result`, carrying `RetCode::BadParam` when a parameter is out of range — the same code the function itself would answer for it. Putting it together, the exact allocation for any TA function: ```rust let lookback = core._lookback(..)?; let temp = lookback.max(startIdx); let allocation_size = if temp > endIdx { 0 } else { endIdx - temp + 1 }; let mut out = vec![0.0; allocation_size]; ``` Too little data is a success, not an error: a range that ends before the lookback simply produces no values, and the returned range is empty (`count == 0`). ### 3.3 Results and Return Codes {#retcode} Every TA function returns `Result`, so it composes with `?`. `RetCode` implements `std::error::Error`. On success you get an [`OutRange`](https://docs.rs/ta-lib): `beg_idx` is the input index of the first value written, and `count` is how many were written. | Code | Meaning | |------|---------| | `RetCode::BadParam` | An optional parameter is outside its documented range, or a slice is too short: every input must cover `startIdx..=endIdx`, and every output must hold the number of values produced for that range. | | `RetCode::OutOfRangeStartIndex` | `startIdx` is above `Core::INDEX_MAX` (100,000,000). | | `RetCode::OutOfRangeEndIndex` | `endIdx` is above `Core::INDEX_MAX`, or below `startIdx`. | `RetCode` also carries `Success` — the code C returns and the one the other ports expose — plus `AllocErr` and `InternalError`, which the safe Rust code paths do not produce. Indexing is safe throughout: the crate is `#![forbid(unsafe_code)]`, so nothing here can read or write out of bounds. Slice sizes are checked before the call runs and reported as `BadParam`; a violated precondition anywhere below that is a panic, never memory corruption. A `NaN` or `±Inf` inside an input series is not detected, and nothing is promised about the output: a running sum or a recursion carries it into every later value, not only the bars whose window holds it. Clean or split the series before calling. ## 4.0 Advanced Features {#advanced} ### 4.1 Abstraction Layer {#abstract} `ta_lib::abstract_api` describes every function at run time and calls it without naming it at compile time — the Rust equivalent of C's [abstraction layer](/api/#abstract). Useful for a UI, a scripting bridge, or anything that enumerates indicators. ```rust use ta_lib::abstract_api::{for_each_func, get_func_handle}; // Look one up by name, or walk them all (FuncId::COUNT of them). let id = get_func_handle("SMA").expect("unknown function"); let info = id.info(); info.name; // "SMA" info.group; // Group::OverlapStudies info.hint; // one-line description info.inputs; // &[InputInfo] -- param_name, kind, flags info.opt_inputs; // &[OptInputInfo] -- display_name, hint, kind info.outputs; // &[OutputInfo] -- param_name, kind, flags for_each_func(|f| println!("{} ({:?})", f.name, f.group)); ``` Each optional parameter carries a typed `OptInputType` — `RealRange`, `IntegerRange`, `RealList` or `IntegerList` — with its bounds, default and suggested values, so a UI can build the right control without a lookup table of its own. It replaces C's type tag plus `void* dataSet` — two separate fields there, with the cast done by hand. Binding arguments at run time goes through a `ParamHolder`: ```rust let core = Core::new(); let mut out = vec![0.0; close.len()]; let mut call = id.new_call(&core); call.set_input(0, &close)?; // set_price_input / set_int_input also exist call.set_opt_input(0, 30)?; // takes i32 or f64 call.set_output(0, &mut out)?; let range = call.call(0, close.len() - 1)?; println!("{} values from bar {}", range.count, range.beg_idx); ``` Optional parameters left unset carry the same default sentinel an omitted argument does in C, so "unset" and "explicitly the default" are one code path. `FuncId::COUNT` is the registry size, and `MAX_INPUTS` / `MAX_OPT_INPUTS` / `MAX_OUTPUTS` bound the slots. ### 4.2 Numerical Stability {#numerical_stability} Your value changed when you fed the same bar more history? That is by design: recursive functions converge as history accumulates. See [Unstable Period](/api/unstable-period/) for how to mitigate that. Rounding is a separate axis: floating-point error accumulates over a very long series, which is one reason a call is capped at [`Core::INDEX_MAX`](#index_range). Every function documentation page carries a [numerical-stability property](/functions/stability): how much the value at a given bar depends on where the series you passed in begins. ### 4.3 Candlestick Settings {#candle_settings} The `CDL*` pattern functions judge each candle against tunable thresholds. See [candlestick settings](/api/candle-settings/) for the full list and defaults; the builder sets them the same way: ```rust use ta_lib::{CandleSetting, CandleSettingType, Core, RangeType}; let core = Core::builder() .candle_setting( CandleSettingType::BodyLong, CandleSetting { range_type: RangeType::RealBody, avg_period: 10, factor: 1.2 }, ) .build()?; ``` The setters are infallible so that they chain; `build()` reports a rejected argument once, as `RetCode::BadParam`. ### 4.4 Index Range {#index_range} `Core::INDEX_MAX` is the largest value `startIdx` or `endIdx` may take: **100,000,000**. It's a sanity bound. Past it, a call is more likely a caller bug than a real need, and it's also untested territory for overflow and rounding error. ### 4.5 Threading {#multithreading} A `Core` cannot change after `build()`, so it is `Send + Sync`. Share one read-only `Core` across threads (behind an `Arc`, say) and call indicators concurrently — no locking, and no setup ordering to respect. To change a setting, build another `Core`, or derive one from an existing `Core` with `to_builder()`. ## 5.0 Documentation {#docs} Every function carries rustdoc rendered from its canonical description, including a runnable doctest. Browse it with `cargo doc --open`, or on [docs.rs](https://docs.rs/ta-lib). --- --- url: 'https://ta-lib.org/api/rust/stream/index.md' description: >- Rust streaming API for live feeds: a stream carries indicator state from bar to bar, so an update never recomputes the history; its values are bit-identical to the batch calls. --- # Rust Streaming API ::: warning Not yet released The Rust API is not yet released. Estimated release: **Q1 2027**. ::: 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 a new bar never costs a pass over the history: most indicators do constant work per bar, and the ones that work over their window, such as AVGDEV, CCI, MEDIAN and the rolling extremes, take time at most proportional to the window's length. Every value is **bit-identical** to what the [batch method](/api/rust/) (`core.sma`, `core.rsi`, …) would return by recomputing over the whole slice. Each streamable function adds two constructors on `Core` and a handful of methods on its stream: | Call | When | Does | |------|------|------| | `core._open(history, params)` | once | validate params, consume warm-up history, return `(stream, value)` | | `stream.update(bar)` | once per **closed** bar | commit one bar, return the new value | | `stream.peek(bar)` | any time on the **forming** bar | evaluate a provisional bar **without** committing | One more call, `open_and_fill`, writes array output instead of a single value — see [Array-Fill Open](#array-fill-open) below. Additional [utility functions](#utility-calls) are available. There is no `close` — dropping the stream closes it (RAII). ## Example (SMA) ```rust use ta_lib::Core; let core = Core::new(); // Seed with warm-up history (>= sma_lookback(period) + 1 bars). let history: Vec = /* ...your closing prices... */; let (mut s, last) = core.sma_open(&history, 30)?; // stream + value at the last history bar // Each time a bar closes: let v = s.update(new_close)?; // Err on a non-finite bar, or past INDEX_MAX // Intra-bar, on the not-yet-closed bar (repeat as the price ticks): let provisional = s.peek(forming_close)?; // state left unchanged // dropping `s` closes the stream ``` `open` returns a `Result` — `Err(RetCode::InsufficientHistory)` if there is too little history (another bar might fix it, so this is the one worth retrying), `Err(RetCode::BadParam)` if a parameter is out of range. `update` and `peek` return a `Result` too, and after a successful `open` what they reject is invalid input such as NaN or ±Inf. They also reject a bar past `Core::INDEX_MAX`, the last index the batch API addresses. A rejection changes nothing at all — no state, no value, and no range. ## Rules * **Warm-up.** `open` succeeds only if `history.len() >= _lookback(params) + 1` — with fewer bars there is no defined value yet. After `open`, the history can be dropped — the stream keeps everything it needs. * **Closed vs forming bar.** `update` commits state irreversibly, so use it only for **closed** bars. `peek` returns exactly the value the next `update` would, 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](/api/rust/#numerical_stability) and [candle settings](/api/rust/#candle_settings) are captured from the immutable `Core` at `open` and cannot change during the stream's life. * **Threads.** `update(&mut self)` makes the single-writer rule a **compile-time** guarantee — one exclusive writer per stream. `peek(&self)` and `value(&self)` never write the stream, so they may run concurrently. Streams are `Send + Sync + Clone`; **cloning forks an independent stream**. ## Multi-input / multi-output Inputs and outputs mirror the batch method. Multi-output functions return a tuple in batch output order; candlestick patterns return `i32`: ```rust // MACD: one input, three outputs let (mut s, (macd, signal, hist)) = core.macd_open(&history, 12, 26, 9)?; let (macd, signal, hist) = s.update(new_close)?; // A candlestick pattern returns i32 let (mut s, _) = core.cdldoji_open(&open, &high, &low, &close)?; let pattern: i32 = s.update(o, h, l, c)?; ``` ## Array-Fill Open `open` and `update` each write a single value. One more call writes a full slice instead — the same shape the [batch method](/api/rust/) would produce — while still opening the stream: | Call | When | Does | |------|------|------| | `core._open_and_fill(..)` | once, instead of `open` | like `open`, but also fills the output for **every** history bar, returning `(stream, OutRange)` | ```rust let mut warmup = vec![0.0; history.len()]; let (mut s, filled) = core.sma_open_and_fill(&history, 30, &mut warmup)?; // warmup[..filled.count] is the SMA over all of history; then stream on: let v = s.update(new_close)?; ``` `open_and_fill` takes the [batch method](/api/rust/)'s optional parameters and one slice per output, and returns the range it wrote as the same `OutRange` the batch method returns, beside the live stream. ## Utility Calls | Call | When | Does | |------|------|------| | `stream.value()` | any time | the value(s) at the last bar the stream counted, without recomputing | | `stream.clone()` | any time | an independent fork of the stream, at the same bar | | `stream.out_range()` | any time | the bars the stream has an output for — the batch range over the same bars | | `stream.advance()` | after a bar you will not feed | advances the range without affecting any other internal state of the stream | ```rust let v = s.value(); // the value at the last bar s counted let mut fork = s.clone(); // independent from here on let r = s.out_range(); // the bars s has an output for s.advance()?; // a bar you skipped, counted ``` The first three return no `Result`: they read what the stream already holds, so there is nothing to reject. `advance()` returns one — it moves the range, and the range cannot pass `Core::INDEX_MAX`. See [Rules](#rules) for when concurrent reads of these are safe. ## Discovering streamable functions When driving TA-Lib through the [abstraction layer](/api/rust/#abstract), streamable functions carry `FuncFlags::STREAM` in `FuncInfo::flags`. --- --- url: 'https://ta-lib.org/api/java/index.md' description: >- io.github.talib: a native Java port with no JNI, indicators as methods on a Core instance over double arrays, bit-identical to the reference C library. --- # Java Core API

1.0 Introduction

2.0 Add it to your project

3.0 Calling into TA-Lib

3.1 Batch Processing
3.2 Output Size and Lookback
3.3 Errors

4.0 Advanced Features

4.1 Abstraction Layer
4.2 Numerical Stability
4.3 Candlestick Settings
4.4 Input Type: float vs. double
4.5 Index Range
4.6 Threading

5.0 Documentation

## 1.0 Introduction {#intro} The Java library is a native port of TA-Lib in the `io.github.talib` package — no JNI, pure Java. Every indicator is a method on a `Core` instance, operates on `double[]` arrays (or `float[]`, see [4.4](#input_type)), and is **bit-identical** to the reference C library over the same inputs. The **Core API** provides: * The [`Core`](#direct_call) type and the builder that configures it. * The settings each `Core` carries: [unstable period](/api/unstable-period/) and [candlestick settings](/api/candle-settings/). Multiple `Core` instances can safely co-exist (say for different settings). * Every TA function, each processing a whole array of data at once. * An optional [abstraction layer](#abstract) for calling those functions dynamically. To process a live feed one bar at a time instead, see the companion [Java Streaming API](/api/java/stream/). There is no initialization step and nothing to shut down. Where C requires `TA_Initialize` before any call and `TA_Shutdown` at exit, Java has `Core.DEFAULT` (or a configured `Core.builder()...build()`) ready immediately, and an unreferenced `Core` is simply garbage-collected. ## 2.0 Add it to your project {#build} ```xml io.github.ta-lib ta-lib 0.8.1 ``` Every released version is listed on [Maven Central](https://central.sonatype.com/artifact/io.github.ta-lib/ta-lib). ## 3.0 Calling into TA-Lib {#ta_func} Every indicator is exposed as a method on `Core`, taking the same startIdx/endIdx/inputs/optional-parameters/outputs shape as the C function it mirrors. ### 3.1 Batch Processing {#direct_call} Every function follows the same simple pattern: it reads its inputs from arrays you pass in and writes its results into arrays you allocate. A function never writes more elements than you request, so the output array only needs to cover the `startIdx`-to-`endIdx` range. As an example, let's walk through `SMA`, a method to calculate a moving average.
public OutRange sma( int      startIdx,
                     int      endIdx,
                     double[] inReal,
                     int      optInTimePeriod,
                     double[] outReal )
All TA methods use the same calling pattern, divided into four 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 is one optional input. These parameters give finer control specific to each function. Passing Integer.MIN_VALUE for an integer parameter, the real-default sentinel -4e37 for a double parameter, or MAType.DEFAULT for an MA-type parameter selects that parameter's documented default.
  • One or more output arrays come last. In this example there is only one output (outReal). Where the values landed is the return value, not a parameter: on success you get an OutRange.
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:
import io.github.talib.Core;
import io.github.talib.OutRange;

double[] close = /* ...your closing prices... */;
double[] out   = new double[close.length];

OutRange r = Core.DEFAULT.sma(
    0, close.length - 1,
    close,
    30,
    out );

// out[0 .. r.count() - 1] holds the SMA; out[i] is input bar r.begIdx() + i.
for (int i = 0; i < r.count(); i++) {
    System.out.println("bar " + (r.begIdx() + i) + " = " + out[i]);
}
After the call, read `r` to learn what was produced. Even though we requested the whole range (`0` to `close.length - 1`), a 30-day average is not defined until the 30th day. Consequently `r.begIdx()` will be 29 (zero-based) and `r.count()` will be `close.length - 29`. In other words, only that many elements of `out` are written, corresponding to input elements 29 through the end. If you do not provide enough data to calculate even one value, the call still succeeds and `r.count()` is 0 — `r.isEmpty()` says so directly. `OutRange` is an immutable record with two components — `begIdx()` and `count()` — plus the conveniences `isEmpty()` and `EMPTY`. The component names match the C, Rust and C# surfaces (`outBegIdx` / `outNBElement`), so the same concept reads the same way in every backend. Every indicator is overloaded for `float[]` inputs as well as `double[]` — see [4.4](#input_type). ### 3.2 Output Size and Lookback {#output_size} An output is written only where the indicator is defined — a 30-period SMA has no value until the 30th bar. `begIdx()` is the first valid bar and `count()` is the number written; the rest of the array is left untouched, never padded with NaN. Size the output array to at least `endIdx - startIdx + 1`, or exactly with the lookback: ```java int lookback = Core.DEFAULT.smaLookback(30); // 29 for a 30-period SMA ``` Each TA method has a matching `Lookback` method, taking the same optional parameters as the method itself. The lookback is how many inputs are consumed before the first output. **Too little data is a success, not an error.** A valid range that ends before the lookback simply produces no values: `count()` is 0 and `isEmpty()` is true. No exception is thrown — this matches the C library's `TA_SUCCESS` with `outNBElement == 0`. Nothing is written, so the output array's length is not checked on such a call — it may even be zero-length. The input is still checked, though: an `endIdx` past the end of the series you passed is a mistake worth hearing about in any range, and an empty range would otherwise hide it behind a "no data yet" result. ### 3.3 Errors {#retcode} Misuse throws rather than returning a return code: | Mistake | Exception | |---|---| | `startIdx`/`endIdx` negative, above `Core.INDEX_MAX`, or `endIdx < startIdx` | `TALibIndexException` | | Optional parameter outside its documented range | `TALibArgumentException` | | Two outputs sharing one array | `TALibArgumentException` | | An array too short for the range requested, including an `endIdx` past the end of the input | `TALibArgumentException` | | A null input or output array | `TALibArgumentException` | Each extends the platform type you would reach for — `TALibIndexException` an `IndexOutOfBoundsException`, the rest an `IllegalArgumentException` — so catching either shape works, and every one carries its `RetCode`. Array lengths are checked before anything is written, so a rejected call leaves every buffer untouched. An input must reach `endIdx`; an output must hold the values actually produced, `endIdx - max(startIdx, lookback) + 1`. The message names the array and both sizes — `SMA: outReal has length 3, needs 191`. A `NaN` or `±Inf` inside an input series is not detected, and nothing is promised about the output: a running sum or a recursion carries it into every later value, not only the bars whose window holds it. Clean or split the series before calling. ## 4.0 Advanced Features {#advanced} ### 4.1 Abstraction Layer {#abstract} The `io.github.talib.metadata` package describes every function at run time and calls it without naming it at compile time — the Java equivalent of C's [abstraction layer](/api/#abstract). Useful for a UI, a scripting bridge, or anything that enumerates indicators. ```java import io.github.talib.metadata.FuncInfo; import io.github.talib.metadata.Functions; FuncInfo f = Functions.byName("SMA"); f.name(); // "SMA" f.group(); // "Overlap Studies" f.hint(); // one-line description f.inputs(); // List -- one entry per input f.optInputs(); // List -- one entry per optional parameter f.outputs(); // List -- one entry per output Functions.all().forEach(fi -> System.out.println(fi.name() + " (" + fi.group() + ")")); ``` Binding arguments at run time goes through a `ParamHolder`, obtained from `FuncInfo#newCall()`: ```java FuncInfo f = Functions.byName("SMA"); OutRange r = f.newCall() .setInput(0, close) .setOptInput(0, 30) .setOutput(0, out) .call(0, close.length - 1); ``` Everything is validated against the `FuncInfo` row: an index out of bounds, a type that does not match the declared parameter, or an unset parameter at `call()` time throws `IllegalArgumentException`. The call itself then behaves exactly like the typed method, including throwing on misuse and returning an empty `OutRange` when the range ends before the lookback. A `ParamHolder` is not thread-safe: confine one to one thread, or build one per call. Streamable functions carry the `FuncFlags.STREAMING` bit in `FuncInfo#flags()` — check it with `f.hasFlags(FuncFlags.STREAMING)`. ### 4.2 Numerical Stability {#numerical_stability} Your value changed when you fed the same bar more history? That is by design: recursive functions converge as history accumulates. See [Unstable Period](/api/unstable-period/) for how to mitigate that. Rounding is a separate axis: floating-point error accumulates over a very long series, which is one reason a call is capped at [`Core.INDEX_MAX`](#index_range). Every function documentation page carries a [numerical-stability property](/functions/stability): how much the value at a given bar depends on where the series you passed in begins. ### 4.3 Candlestick Settings {#candle_settings} The `CDL*` pattern methods judge each candle against tunable thresholds. See [candlestick settings](/api/candle-settings/) for the full list and defaults; the builder sets them the same way: ```java import io.github.talib.CandleSettingType; import io.github.talib.Core; import io.github.talib.RangeType; Core core = Core.builder() .candleSetting(CandleSettingType.BODY_LONG, RangeType.REAL_BODY, 10, 1.0) .build(); ``` Each setter throws immediately (`IllegalArgumentException`) if an argument is out of range, so the rejection names the call that caused it, and `build()` cannot fail. C# behaves the same way; Rust is the one backend that defers, because a setter there cannot throw. ### 4.4 Input Type: float vs. double {#input_type} Every indicator is overloaded for `float[]` inputs as well as `double[]` — the `float` overload widens each element to `double` before computing, so a result beyond `float` range still lands correctly in the `double` output. Both overloads produce the same output, bit-for-bit. Use it to feed price data already stored as `float` without copying. Because the two overloads differ only in the input array type, a bare `null` argument is ambiguous; cast it (`(double[]) null`) if you ever need to pass one. ### 4.5 Index Range {#index_range} `Core.INDEX_MAX` is the largest value `startIdx` or `endIdx` may take: **100,000,000**. It's a sanity bound. Past it, a call is more likely a caller bug than a real need, and it's also untested territory for overflow and rounding error. ### 4.6 Threading {#multithreading} **`Core` is immutable.** Every field is final and the settings it carries are deeply immutable, so one instance is safe to share across any number of threads with no synchronization — even when published racily (JLS 17.5 final-field semantics). There are no locks on any call path. Use `Core.DEFAULT` for the all-defaults instance. There are no setters: to change a setting, derive a new instance with `core.toBuilder()`. Read a configured unstable period back with `core.unstablePeriod(FuncUnstId.EMA)` — the same name the builder writes it under, since a `Core` is immutable and has no writer to distinguish it from. ## 5.0 Documentation {#docs} Every function's Javadoc is rendered from the same canonical description as every other backend's docs. It is published to Maven Central as the artifact's `javadoc` jar, which an IDE fetches alongside the library; build it locally with `./mvnw clean javadoc:javadoc` in `ta_codegen/output/java/library`. --- --- url: 'https://ta-lib.org/api/java/stream/index.md' description: >- Java streaming API for live feeds: a stream carries indicator state from bar to bar, so an update never recomputes the history; its values are bit-identical to the batch calls. --- # Java Streaming API 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 a new bar never costs a pass over the history: most indicators do constant work per bar, and the ones that work over their window, such as AVGDEV, CCI, MEDIAN and the rolling extremes, take time at most proportional to the window's length. Every value is **bit-identical** to what the [batch method](/api/java/) (`core.sma`, `core.rsi`, …) would return by recomputing over the whole array. Each streamable function adds two factory methods on `Core` and a handful of methods on its stream (a class nested in `Core`, e.g. `Core.SmaStream` — unrelated to `java.util.stream`): | Call | When | Does | |------|------|------| | `core.Open(history, params)` | once | validate params, consume warm-up history, return a **stream** | | `stream.update(bar)` | once per **closed** bar | commit one bar and answer the new value | | `stream.peek(bar)` | any time on the **forming** bar | evaluate a provisional bar **without** committing | A single-output function answers with a `double` (or an `int` for a candlestick pattern) return. A multi-output one writes into a sink you pass and own — see [Multi-input / multi-output](#multi-input-multi-output). One more call, `openAndFill`, writes array output instead of a single value — see [Array-Fill Open](#array-fill-open) below. Additional [utility functions](#utility-calls) are available. There is no `close` — a stream is ordinary heap state, so an unreferenced stream is simply garbage-collected. ## Example (SMA) ```java import io.github.talib.Core; Core core = Core.DEFAULT; // Seed with warm-up history (>= smaLookback(period) + 1 bars). double[] history = /* ...your closing prices... */; Core.SmaStream s = core.smaOpen(history, 30); // value() starts at the last history bar // Each time a bar closes: double v = s.update(newClose); // throws on a non-finite bar, or past INDEX_MAX // Intra-bar, on the not-yet-closed bar (repeat as the price ticks): double provisional = s.peek(formingClose); // state left unchanged ``` `open` returns the stream directly; its `value()` starts at the last history bar's value. After a successful `open`, what `update` and `peek` reject is invalid input such as NaN or ±Inf; `update` also rejects a bar past `Core.INDEX_MAX`, the last index the batch API addresses. A rejection changes nothing at all — no state, no value, and no range. To count a rejected bar rather than re-feed it, call `advance()`; `value()` then answers the value(s) at the last bar the stream counted (see [Utility Calls](#utility-calls)). ## Rules * **Warm-up.** `open` succeeds only if `history.length >= Lookback(params) + 1` — with fewer bars there is no defined value yet. Too little history throws `InsufficientHistoryException` (see [Error model](#error-model)). After `open`, the history can be discarded — the stream keeps everything it needs. * **Closed vs forming bar.** `update` commits state irreversibly, so use it only for **closed** bars. `peek` returns exactly the value the next `update` would, without committing — call it as often as the forming bar ticks. `value()` re-reads the last committed value without recomputing. * **Parameters are fixed at `open`.** Changing a parameter means a new stream. [Unstable period](/api/java/#numerical_stability) and [candle settings](/api/java/#candle_settings) are read from the owning `Core` at `open`. Since `Core` is immutable they cannot change underneath a live stream — to stream with different settings, build a new `Core` and open from that. * **Threads.** A stream is single-writer: `update` must 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. ## Multi-input / multi-output Inputs and outputs mirror the batch method. A multi-output function writes its outputs into a `Core.Out` — a plain mutable object with one public field per output, in batch output order — that **you** allocate and pass in. Candlestick patterns return `int`: ```java // MACD: one input, three outputs Core.MacdStream m = core.macdOpen(history, 12, 26, 9); Core.MacdOut out = new Core.MacdOut(); // allocate once, reuse every bar m.update(newClose, out); // out.macd, out.macdSignal, out.macdHist // A candlestick pattern returns int Core.CdldojiStream c = core.cdldojiOpen(open, high, low, close); int pattern = c.update(o, h, l, cl); ``` Reusing one sink is the point: `update`, `peek` and `value` overwrite its fields rather than allocating a new one. The price is that **its contents are only valid until the next call that writes it**. It is a buffer, not a reading — a reference kept past that call, or one put in a collection, sees the value change underneath it. Copy the fields out if the reading has to outlive the call, or allocate one sink per slot. For the same reason `Out` deliberately has no `equals`/`hashCode`: value equality on a mutable object breaks `HashMap`/`HashSet` the moment a reused sink becomes a key. Passing `null` is an `IllegalArgumentException`, taken before the bar is committed. ## Array-Fill Open `open` and `update` each write a single value. One more call writes a full array instead — the same shape the [batch method](/api/java/) would produce — while still opening the stream: | Call | When | Does | |------|------|------| | `core.OpenAndFill(..)` | once, instead of `open` | like `open`, but also fills the output for **every** history bar | ```java import io.github.talib.OutRange; double[] warmup = new double[history.length]; Core.SmaStream s = core.smaOpenAndFill(history, 30, warmup); OutRange r = s.outRange(); // the bars it has an output for // warmup[0 .. r.count() - 1] is the SMA over all of history; then stream on: double v = s.update(newClose); ``` The optional parameters and output arrays are exactly the [batch method](/api/java/)'s. The range written is reported on the returned stream as `outRange()` rather than through out-parameters — see [Utility Calls](#utility-calls) below. The output arrays must not alias the input or each other. ## Utility Calls | Call | When | Does | |------|------|------| | `stream.value()` / `stream.value(out)` | any time | the value(s) at the last bar the stream counted, without recomputing | | `stream.clone()` | any time | an independent fork of the stream, at the same bar | | `stream.outRange()` | any time | the bars the stream has an output for — the batch range over the same bars | | `stream.advance()` | after a bar you will not feed | advances the range without affecting any other internal state of the stream | ```java Core.SmaStream s = core.smaOpen(history, 30); double v = s.value(); // the value at the last bar s counted Core.SmaStream fork = s.clone(); // independent from here on OutRange r = s.outRange(); // the bars s has an output for s.advance(); // a bar you skipped, counted ``` `clone()` overrides `Object.clone()` but does not use the `Cloneable` protocol — the body is a copy constructor, so it needs no marker interface and throws no `CloneNotSupportedException`. See [Rules](#rules) for when concurrent reads of these are safe. ## Error model | Call | Behaviour | |------|-----------| | `Open` / `OpenAndFill` | Too little history throws `InsufficientHistoryException` (a subclass of `IllegalArgumentException` — catch it to accumulate more bars and retry). Out-of-range parameters throw plain `IllegalArgumentException`. | | `update` / `peek` |
  • `IllegalArgumentException` on invalid input such as NaN or ±Inf
  • `IndexOutOfBoundsException` once the range has reached bar `Core.INDEX_MAX`, the last index the batch API addresses
A rejection changes nothing at all — no state, no value, and no range. | | `advance` | `IndexOutOfBoundsException` once the range has reached bar `Core.INDEX_MAX`, the last index the batch API addresses. | | `value()` / `clone` / `outRange` | Never throw. `value(out)` throws `IllegalArgumentException` on a null sink, as `update` and `peek` do. | ## Discovering streamable functions When driving TA-Lib through the [abstraction layer](/api/java/#abstract), streamable functions carry the `FuncFlags.STREAMING` bit in `FuncInfo#flags()`. --- --- url: 'https://ta-lib.org/api/csharp/index.md' description: >- TALib: a native C# port with no P/Invoke, indicators as methods on a Core instance taking spans, bit-identical to the reference C library. --- # C# Core API ::: warning Not yet released The C# API is not yet released. Estimated release: **Q1 2027**. :::

1.0 Introduction

2.0 Add it to your project

3.0 Calling into TA-Lib

3.1 Batch Processing
3.2 Output Size and Lookback
3.3 Errors

4.0 Advanced Features

4.1 Abstraction Layer
4.2 Numerical Stability
4.3 Candlestick Settings
4.4 Input Type: float vs. double
4.5 Index Range
4.6 Threading
4.7 Trimming and NativeAOT

5.0 Documentation

## 1.0 Introduction {#intro} The .NET library is a native port of TA-Lib in the `TALib` namespace — no P/Invoke, no native dependency, pure managed C# targeting `net10.0`. Every indicator is a method on a `Core` instance, takes its series as spans, and is **bit-identical** to the reference C library over the same inputs. The **Core API** provides: * The [`Core`](#direct_call) type and the builder that configures it. * The settings each `Core` carries: [unstable period](/api/unstable-period/) and [candlestick settings](/api/candle-settings/). Multiple `Core` instances can safely co-exist (say for different settings). * Every TA function, each processing a whole array of data at once. * An optional [abstraction layer](#abstract) for calling those functions dynamically. To process a live feed one bar at a time instead, see the companion [C# Streaming API](/api/csharp/stream/). There is no initialization step and nothing to shut down. Where C requires `TA_Initialize` before any call and `TA_Shutdown` at exit, C# has `Core.Default` (or a configured `Core.Builder()...Build()`) ready immediately; a `Core` owns only managed state, so an unreferenced one is simply garbage-collected. ## 2.0 Add it to your project {#build} The package is not on NuGet yet. Until it is, reference the `TALib` project directly: ```xml ``` It targets `net10.0`. ## 3.0 Calling into TA-Lib {#ta_func} Every indicator is exposed as a method on `Core`, taking the same startIdx/endIdx/inputs/optional-parameters/outputs shape as the C function it mirrors. ### 3.1 Batch Processing {#direct_call} Every function follows the same simple pattern: it reads its inputs from spans you pass in and writes its results into spans you allocate. A function never writes more elements than you request, so the output span only needs to cover the `startIdx`-to-`endIdx` range. As an example, let's walk through `SMA`, a method to calculate a moving average.
public OutRange Sma( int    startIdx,
                     int    endIdx,
                     ReadOnlySpan<double> inReal,
                     int    optInTimePeriod,
                     Span<double> outReal )
All TA methods use the same calling pattern, divided into four groups:
  • The output will be calculated only for the range specified by startIdx and endIdx. These are zero-based indices into the input spans.
  • One or more input spans 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 is one optional input. These parameters give finer control specific to each function. Passing int.MinValue for an integer parameter, the real-default sentinel -4e37 for a double parameter, or MAType.DEFAULT for an MA-type parameter selects that parameter's documented default.
  • One or more output spans come last. In this example there is only one output (outReal). Where the values landed is the return value, not a parameter: on success you get an OutRange.
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:
using TALib;

var core = Core.Default;

double[] close = [ /* ...your closing prices... */ ];
var outReal = new double[close.Length];

OutRange r = core.Sma(
    0, close.Length - 1,
    close,
    30,
    outReal );

// outReal[0 .. r.Count - 1] holds the SMA; outReal[i] is input bar r.BegIdx + i.
for (int i = 0; i < r.Count; i++)
{
    Console.WriteLine($"bar {r.BegIdx + i} = {outReal[i]}");
}
After the call, read `r` to learn what was produced. Even though we requested the whole range (`0` to `close.Length - 1`), a 30-day average is not defined until the 30th day. Consequently `r.BegIdx` will be 29 (zero-based) and `r.Count` will be `close.Length - 29`. In other words, only that many elements of `outReal` are written, corresponding to input elements 29 through the end. Arrays convert to spans implicitly, so the call above and a call passed a slice of a larger buffer (`close.AsSpan(start, count)`) are both ordinary code — no copy either way. `startIdx` and `endIdx` index the span you pass, not the array it came from: a slice holds no bars before its first element, so `Sma(0, n - 1, close.AsSpan(100, n), ...)` takes its lookback from inside the slice and produces fewer, possibly different, values than `Sma(100, 100 + n - 1, close, ...)`. Both calls succeed. A span is never null, so passing `null` arrives as an empty span and is rejected by the length check as one (`ArgumentException` naming the parameter). Every input an indicator declares is checked, including the OHLC series a few candlestick patterns never read. If the range ends before the lookback, so no value can be calculated, the call still succeeds and `r.Count` is 0 (`r.IsEmpty`). `OutRange` is a `readonly record struct` with two components — `BegIdx` and `Count` — plus the conveniences `IsEmpty` and `Empty`. They are C's `outBegIdx` / `outNBElement`, Java's `begIdx` / `count` and Rust's `beg_idx` / `count`. Every indicator also has a `ReadOnlySpan` overload — see [4.4](#input_type). ### 3.2 Output Size and Lookback {#output_size} An indicator consumes a number of leading bars — its **lookback** — before it can produce anything. Query it with the matching `*Lookback` method: ```csharp int lookback = core.SmaLookback(30); // 29 ``` Output is written only where the indicator is defined: `outReal[0]` corresponds to input bar `r.BegIdx`, and nothing outside `0 .. r.Count - 1` is touched. The library never pads with `NaN`. A range that ends before the lookback is a **success with no values** (`r.Count == 0`), not an error. ### 3.3 Errors {#retcode} The public methods throw rather than return a status code: | Condition | Exception | |---|---| | `startIdx`/`endIdx` negative, above `Core.IndexMax`, or `endIdx < startIdx` | `TALibArgumentOutOfRangeException` | | An optional parameter outside its documented range | `TALibArgumentException` | | An input span that does not reach `endIdx`, or an output span shorter than the values produced | `TALibArgumentException` naming the span | | Two outputs overlapping, or an output *partially* overlapping an input | `TALibArgumentException` | | An inconsistency in the library's own state: a bug, please report it | `TALibInvalidOperationException` carrying `RetCode.InternalError` | Each extends the framework type you would reach for and implements `ITALibFailure`, so `catch (ArgumentException)` still works and the `RetCode` is there when you want it. Computing wholly in place is allowed and stays supported — passing the same buffer as both an input and an output is how several indicators are meant to be used. What is rejected is *partial* overlap, which only spans can express: two views of the same memory at different offsets make a body write through what it is still reading, and the result would be silently wrong rather than merely surprising. A `NaN` or `±Inf` inside an input series is not detected, and nothing is promised about the output: a running sum or a recursion carries it into every later value, not only the bars whose window holds it. Clean or split the series before calling. A batch call may allocate managed scratch, sized by a period (MFI, ULTOSC) or, for some functions built from other functions such as STOCHRSI, by the range. An allocation of 85,000 bytes or more (about 10,600 doubles) lands on the large object heap. ## 4.0 Advanced Features {#advanced} ### 4.1 Abstraction Layer {#abstract} `TALib.Metadata.FunctionCatalog` describes every function at run time and calls it without naming it at compile time — the C# equivalent of C's [abstraction layer](/api/#abstract). It exists because a span cannot be boxed: the API cannot be invoked through `MethodInfo.Invoke`, so calling a function chosen at run time needs a typed path instead of reflection — which is also faster. ```csharp using TALib; using TALib.Metadata; foreach (var f in Core.Functions.Where(f => f.Flags.HasFlag(FuncFlags.Candlestick))) { Console.WriteLine($"{f.Name}: {f.Hint}"); } ``` `Core.Functions` (an alias for `FunctionCatalog.Default`) implements `IReadOnlyList`, so it is directly enumerable and LINQ-able, and is indexable by position or by name (`Core.Functions["SMA"]`). The name is matched with `StringComparer.OrdinalIgnoreCase`, so `"SMA"`, `"sma"` and `"Sma"` all resolve to the same function; `FuncInfo.Name` stays the canonical `"SMA"`. Streamable functions carry `FuncFlags.Stream`. Binding arguments at run time goes through a `ParamHolder`, obtained from `FuncInfo.CreateCall()`: ```csharp var f = Core.Functions["SMA"]; var range = f.CreateCall() .SetInput(0, close) .SetOptInput(0, 30) .SetOutput(0, outReal) .Call(0, close.Length - 1); ``` An index out of range, a type that does not match the declared parameter, or an unbound input or output at call time throws `ArgumentException`. Optional parameters left unbound take their documented defaults. A `ParamHolder` is not thread-safe: confine one to one thread, or build one per call. The `FunctionCatalog` it comes from is immutable and shared freely. ### 4.2 Numerical Stability {#numerical_stability} Your value changed when you fed the same bar more history? That is by design: recursive functions converge as history accumulates. See [Unstable Period](/api/unstable-period/) for how to mitigate that. Rounding is a separate axis: floating-point error accumulates over a very long series, which is one reason a call is capped at [`Core.IndexMax`](#index_range). Every function documentation page carries a [numerical-stability property](/functions/stability): how much the value at a given bar depends on where the series you passed in begins. ### 4.3 Candlestick Settings {#candle_settings} The `CDL*` pattern methods judge each candle against tunable thresholds. See [candlestick settings](/api/candle-settings/) for the full list and defaults; the builder sets them the same way: ```csharp var core = Core.Builder() .CandleSetting(CandleSettingType.BodyDoji, RangeType.HighLow, 10, 0.1) .Build(); ``` Each setter throws `ArgumentOutOfRangeException` immediately if an argument is out of range, so the rejection names the call that caused it. `Build()` cannot fail. Rust is the one backend that defers: a setter there cannot throw, so `build()` returns a `Result`. ### 4.4 Input Type: float vs. double {#input_type} Every indicator also has a `ReadOnlySpan` overload (`float[]` converts implicitly), for callers who store series at single precision; the arithmetic is `double` either way, so both overloads produce the same output, bit-for-bit. ### 4.5 Index Range {#index_range} `Core.IndexMax` is the largest value `startIdx` or `endIdx` may take: **100,000,000**. It's a sanity bound. Past it, a call is more likely a caller bug than a real need, and it's also untested territory for overflow and rounding error. ### 4.6 Threading {#multithreading} A `Core` is immutable once built, so it is safe to share read-only across threads and call any indicator concurrently — no locking, and no setup ordering to respect. `Core.Default` is the all-defaults instance. To change a setting, build another `Core` with `Core.Builder()`. ### 4.7 Trimming and NativeAOT {#aot} The library is annotated `IsAotCompatible`, uses no reflection, and publishes clean under `PublishAot` with `TrimMode=full`. One publishing note worth knowing: at ILC's **default** instruction-set baseline, `Math.FusedMultiplyAdd` is compiled to a library call rather than the hardware FMA instruction. Values are unaffected — output is bit-identical across the JIT and both AOT baselines — but the indicators that lean on it are measurably slower (TRIX ~3.7x, DEMA ~2.3x, EMA ~1.5x, with SMA flat as a control). If you publish AOT and care about throughput, raise the baseline: ```xml x86-64-v3 ``` ## 5.0 Documentation {#docs} Every function ships XML doc comments rendered from the same canonical description as every other backend's docs, so your IDE's tooltips and IntelliSense are populated without a separate doc build. `GenerateDocumentationFile` is on and `CS1591` (a public member missing its doc comment) is an error, so the assembly can never ship undocumented. --- --- url: 'https://ta-lib.org/api/csharp/stream/index.md' description: >- C# streaming API for live feeds: a stream carries indicator state from bar to bar, so an update never recomputes the history; its values are bit-identical to the batch calls. --- # C# Streaming API ::: warning Not yet released The C# API is not yet released. Estimated release: **Q1 2027**. ::: 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 a new bar never costs a pass over the history: most indicators do constant work per bar, and the ones that work over their window, such as AVGDEV, CCI, MEDIAN and the rolling extremes, take time at most proportional to the window's length. Every value is **bit-identical** to what the [batch method](/api/csharp/) (`core.Sma`, `core.Rsi`, …) would return by recomputing over the whole array. Each streamable function adds two factory methods on `Core` and a handful of members on its stream (a class nested in `Core`, e.g. `Core.SmaStream`): | Call | When | Does | |------|------|------| | `core.Open(history, params)` | once | validate params, consume warm-up history, return a **stream** | | `stream.Update(bar)` | once per **closed** bar | commit one bar, return the new value | | `stream.Peek(bar)` | any time on the **forming** bar | evaluate a provisional bar **without** committing | One more call, `OpenAndFill`, writes array output instead of a single value — see [Array-Fill Open](#array-fill-open) below. Additional [utility functions](#utility-calls) are available. There is **no `Dispose`**: a stream owns only managed state — its arrays, its sub-streams and a `Core` reference — so an unreferenced stream is simply collected. The stream types deliberately do not implement `IDisposable`. ## Example (SMA) ```csharp using TALib; var core = Core.Default; // Seed with warm-up history (>= SmaLookback(period) + 1 bars). double[] history = [ /* ...your closing prices... */ ]; Core.SmaStream s = core.SmaOpen(history, 30); // Value starts at the last history bar // Each time a bar closes: double v = s.Update(newClose); // throws on a non-finite bar, or past IndexMax // Intra-bar, on the not-yet-closed bar (repeat as the price ticks): double provisional = s.Peek(formingClose); // state left unchanged ``` `Open` returns the stream directly; its `Value` starts at the last history bar's value. After a successful `Open`, what `Update` and `Peek` reject is invalid input such as NaN or ±Inf; `Update` also rejects a bar past `Core.IndexMax`, the last index the batch API addresses. A rejection changes nothing at all — no state, no value, and no range. To count a rejected bar rather than re-feed it, call `Advance()`; `Value` then answers the value(s) at the last bar the stream counted (see [Utility Calls](#utility-calls)). ## Rules * **Warm-up.** `Open` succeeds only if `history.Length >= Lookback(params) + 1` — with fewer bars there is no defined value yet. Too little history throws `InsufficientHistoryException` (see [Error model](#error-model)). After `Open`, the history can be discarded — the stream keeps everything it needs. * **Closed vs forming bar.** `Update` commits state irreversibly, so use it only for **closed** bars. `Peek` returns exactly the value the next `Update` would, without committing — call it as often as the forming bar ticks. `Value` re-reads the last committed value without recomputing. * **Parameters are fixed at `Open`.** Changing a parameter means a new stream. [Unstable period](/api/csharp/#numerical_stability) and [candle settings](/api/csharp/#candle_settings) are read from the owning `Core` at `Open`. Since `Core` is immutable they cannot change underneath a live stream — to stream with different settings, build a new `Core` and open from that. * **Threads.** A stream is single-writer: `Update` must 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. * **Spans, not arrays.** Series parameters are `ReadOnlySpan` in and `Span` out, so a warm-up window can be a slice of a larger buffer with no copy. Arrays convert implicitly, so `SmaOpen(history, 30)` on a `double[]` is unchanged. Because a span is never null, a null history arrives as an empty span and is rejected as one. ## Multi-input / multi-output `Update` and `Peek` take one argument per input series, in the batch call's order, and return one value per output. Multi-output indicators return a generated `readonly record struct` nested in `Core` and named after the function, whose members are the output names with the leading `out` stripped: ```csharp Core.BbandsStream b = core.BbandsOpen(history, 20, 2.0, 2.0, MAType.SMA); Core.BbandsValue v = b.Update(newClose); Console.WriteLine($"{v.RealUpperBand} {v.RealMiddleBand} {v.RealLowerBand}"); // It deconstructs, too: var (upper, middle, lower) = b.Value; ``` ::: tip Equality on a value type These are record structs, so `==` is .NET's `double` equality: `NaN` equals `NaN` **and** `+0.0` equals `-0.0`. (Java's record differs on the second.) Compare `BitConverter.DoubleToInt64Bits` per component when bit-level identity is what you mean. ::: ## Array-Fill Open `Open` and `Update` each write a single value. One more call writes a full array instead — the same shape the [batch method](/api/csharp/) would produce — while still opening the stream: | Call | When | Does | |------|------|------| | `core.OpenAndFill(..)` | once, instead of `Open` | like `Open`, but also fills the output for **every** history bar | ```csharp double[] history = [ /* ...your closing prices... */ ]; var outReal = new double[history.Length]; Core.SmaStream s = core.SmaOpenAndFill(history, 30, outReal); OutRange r = s.OutRange; // the bars it has an output for // outReal[0 .. r.Count - 1] == what core.Sma(0, history.Length - 1, ...) writes // ...and s is live, ready for Update. ``` The output arguments are the batch call's, in the same order. An output may not overlap an input, or another output — that throws `ArgumentException` and mints no stream. With spans that means genuine memory overlap, not just the same buffer: two slices of one array that share even one element are rejected. ## Utility Calls | Call | When | Does | |------|------|------| | `stream.Value` | any time | the value(s) at the last bar the stream counted, without recomputing | | `stream.Clone()` | any time | an independent fork of the stream, at the same bar | | `stream.OutRange` | any time | the bars the stream has an output for — the batch range over the same bars | | `stream.Advance()` | after a bar you will not feed | advances the range without affecting any other internal state of the stream | ```csharp Core.SmaStream s = core.SmaOpen(history, 30); double v = s.Value; // the value at the last bar s counted Core.SmaStream fork = s.Clone(); // independent from here on OutRange r = s.OutRange; // the bars s has an output for s.Advance(); // a bar you skipped, counted ``` `Clone()` is a typed `Clone()`, deliberately not `ICloneable` — that interface returns `object` and leaves deep-versus-shallow unsaid, and this is neither. See [Rules](#rules) for when concurrent reads of these are safe. ## Error model `Open` and `OpenAndFill` throw. After a successful open, `Update` and `Peek` reject invalid input such as NaN or ±Inf, or a bar past `Core.IndexMax`. A rejection changes nothing at all — no state, no value, and no range. `Value`, `Clone()` and `OutRange` never throw; `Advance()` throws only at the `IndexMax` ceiling. | Condition | Exception | |---|---| | An empty history (zero bars, or a null array) | `ArgumentOutOfRangeException` carrying `RetCode.OutOfRangeStartIndex` | | A history longer than `Core.IndexMax + 1` bars | `ArgumentOutOfRangeException` carrying `RetCode.OutOfRangeEndIndex` | | An optional parameter outside its documented range, a non-finite real parameter included | `ArgumentException` | | An input series whose length differs from the history's | `ArgumentException` naming it | | (`OpenAndFill`) an output shorter than the values the fill writes, or overlapping an input or another output | `ArgumentException` | | Fewer than `lookback + 1` history bars | `InsufficientHistoryException` | | A non-finite bar (NaN or ±Inf) | `ArgumentException` naming the input | | A bar past `Core.IndexMax`, the last index the batch API addresses | `ArgumentException` carrying `RetCode.OutOfRangeEndIndex` | `InsufficientHistoryException` derives from `ArgumentException`, so you can catch it specifically — it is the one routine, data-dependent rejection — or catch every open failure uniformly. An empty history is not that case: zero bars is an index fault, so a loop that retries on `InsufficientHistoryException` until enough bars arrive must not start before the first bar. Messages carry a stable `" : "` prefix (`open`, `openAndFill`, `update`, `peek` or `advance`), and `` is always the *called* function's name: `core.MaOpen(...)` rejecting reports `MA open:`, never the name of whatever moving average it delegates to. Insufficient history is knowable in advance, so it need not be exceptional in your code: compare against `Lookback(params) + 1` before opening. ## Absolute-index outputs `MININDEX`, `MAXINDEX` and `MINMAXINDEX` report bar indices. In the streaming tier those count bars fed to the stream rather than positions in an array — so treat an index as a position within this handle's own window, not as one you can compare against an index a different handle reported. ## Discovering streamable functions The catalogue flags them, so you do not have to hardcode a list: ```csharp using TALib; using TALib.Metadata; foreach (var f in Core.Functions) { if ((f.Flags & FuncFlags.Stream) != 0) { Console.WriteLine(f.Name); } } ``` That is discovery only. Unlike the batch tier, there is no name-based way to *open* a stream — `ParamHolder` binds batch calls, and nothing binds streams. Opening one means calling its typed `Open` directly. This is deliberate rather than an oversight, and the same is true of the other language bindings. A generic opener would have to return a stream whose type varies per function, and `Update` varies in both arity and return type, so the values would have to be boxed, an allocation on every Update. Worth designing properly if there is a call for it; not worth guessing at. --- --- url: 'https://ta-lib.org/api/unstable-period/index.md' description: >- How many warm-up bars TA-Lib discards from recursive indicators such as EMA, RSI and ADX before reporting their output, and how to set it in C, Rust, Java and C#. --- # Unstable Period **TL;DR:** Some indicators need a warm-up before their output settles. TA-Lib can discard those bars for you, so unstable values never reach your application. ## Why it exists Some indicators have "memory". Each output depends on the previous one, seeded from the start of the data. An Exponential Moving Average is the classic example: the seed's effect is large at first, and decays with each bar until the result is **stable**.
145 150 155 0 20 40 60 80 100 bar fed from bar 0 fed from bar 10 fed from bar 20 unstable stable
Three 20-bar EMAs of the same prices, each fed from a different starting bar; from bar 65 on they stabilize within an acceptable error margin.
This is inherent to the algorithms, not something specific to TA-Lib: every implementation has to seed the recursion somewhere. ## What to do There are three distinct approaches, from the most common to the most rigorous: 1. **Ignore the problem.** What most charting sites do, and usually fine: the latest bar has plenty of history behind it. Nothing warns you when it doesn't; a short series, or a back-test on the earliest bars, quietly uses bad values. 2. **Scrub it yourself.** TA-Lib stays at its default (unstable period `0`) and returns everything it can compute; your code decides how many leading outputs to drop. 3. **Let TA-Lib do it.** Set an unstable period and the function stops emitting that many leading values, the ones the seed still distorts. ## API ::: code-tabs#lang @tab C ```c TA_RetCode TA_SetUnstablePeriod( TA_FuncUnstId id, unsigned int unstablePeriod ); unsigned int TA_GetUnstablePeriod( TA_FuncUnstId id ); /* Strip 30 extra bars from every EMA-based calculation: */ TA_SetUnstablePeriod( TA_FUNC_UNST_EMA, 30 ); /* Apply the same unstable period to ALL affected functions at once: */ TA_SetUnstablePeriod( TA_FUNC_UNST_ALL, 30 ); ``` @tab Rust ```rust use ta_lib::{Core, FuncUnstId}; // Strip 30 extra bars from every EMA-based calculation: let core = Core::builder() .unstable_period(FuncUnstId::EMA, 30) .build()?; // Apply the same unstable period to ALL affected functions at once: let core = Core::builder() .unstable_period(FuncUnstId::ALL, 30) .build()?; let n = core.get_unstable_period(FuncUnstId::EMA)?; // read it back ``` @tab Java ```java import io.github.talib.Core; import io.github.talib.FuncUnstId; // Strip 30 extra bars from every EMA-based calculation: Core core = Core.builder() .unstablePeriod(FuncUnstId.EMA, 30) .build(); // Apply the same unstable period to ALL affected functions at once: Core all = Core.builder() .unstablePeriod(FuncUnstId.ALL, 30) .build(); int n = core.unstablePeriod(FuncUnstId.EMA); // read it back ``` @tab C# ```csharp using TALib; // Strip 30 extra bars from every EMA-based calculation: Core core = Core.Builder() .UnstablePeriod(FuncUnstId.EMA, 30) .Build(); // Apply the same unstable period to ALL affected functions at once: Core all = Core.Builder() .UnstablePeriod(FuncUnstId.ALL, 30) .Build(); int n = core.UnstablePeriod(FuncUnstId.EMA); // read it back ``` ::: `id` selects which function to affect. The period sets how many warm-up bars that function discards; the larger the value, the later the first output. The default, `0`, discards nothing: you get every value the function can compute. The setting follows the function wherever it runs: whether you call it directly, or another indicator uses it internally. The EMA id therefore affects EMA itself and every indicator built on one, such as MACD and DEMA. ## Functions with an unstable period `ADX`, `ATR`, `CMO`, `DX`, `EMA`, `HT_DCPERIOD`, `HT_DCPHASE`, `HT_PHASOR`, `HT_SINE`, `HT_TRENDLINE`, `HT_TRENDMODE`, `KAMA`, `MAMA`, `MINUS_DI`, `MINUS_DM`, `NATR`, `PLUS_DI`, `PLUS_DM`, `RSI`, `T3`, `RMA`, `HA`, `RVI`, `FRAMA`, `MCGD`, `VIDYA`, `STC`. | Language | Id | Enum | | --- | --- | --- | | C | `TA_FUNC_UNST_` | [ta_defs.h](https://github.com/TA-Lib/ta-lib/blob/main/include/ta_defs.h) | | Rust | `FuncUnstId::` | [types.rs](https://github.com/TA-Lib/ta-lib/blob/main/ta_codegen/output/rust/library/src/ta_func/types.rs) | | Java | `FuncUnstId.` | [FuncUnstId.java](https://github.com/TA-Lib/ta-lib/blob/main/ta_codegen/output/java/library/src/main/java/io/github/talib/FuncUnstId.java) | | C# | `FuncUnstId.` | [FuncUnstId.cs](https://github.com/TA-Lib/ta-lib/blob/main/ta_codegen/output/csharp/library/src/FuncUnstId.cs) | `` may also be `ALL`, which targets every function above at once. ## See also * [C/C++ Core API](/api/) / [Rust Core API](/api/rust/) * [Candlestick Settings](/api/candle-settings/) --- --- url: 'https://ta-lib.org/functions/stability.md' description: >- What it means for an indicator to be start-independent, to carry an initial unstable period, to depend on the MA type selected, or to be path-dependent. --- # Numerical Stability The [Function Documentation](/functions/) specifies which of the four categories below applies to each function. They answer a single practical question: **does the value at a given bar depend on where the series you passed in begins?** ## If Start-Independent, then... {#start-independent} The value at a bar does not depend on where your data starts. Feed the function a year or a decade and the value it reports for a given bar is identical. These functions read a bounded window — a fixed number of bars — and ignore everything older. ## If Initial Unstable Period, then... {#initial-unstable-period} Early values depend on how much history precedes them, and converge as more bars are supplied. These functions are defined recursively: each value folds in the previous one, so the series never entirely forgets where it began — though the influence decays until it is lost in floating-point rounding. See [Unstable Period](/api/unstable-period/) for what to do about it: when to ignore it, when to supply extra history, and how to have TA-Lib drop the unstable values for you. ## If Depends on MA Type, then... {#depends-on-ma-type} Some functions take an `optInMAType` parameter selecting how their moving average is computed. That choice decides which of the properties above applies: a recursive MA type gives the function an initial unstable period, a windowed one leaves it start-independent. | MA Type | Value | Numerical Stability | Why | | :-- | --: | :-- | :-- | | [SMA](/functions/sma.md) | 0 | Start-Independent | A windowed average: it reads a fixed number of bars and forgets everything older. | | [EMA](/functions/ema.md) | 1 | Initial Unstable Period | Recursive: each value folds in the previous one. Tunable via EMA's own unstable period. | | [WMA](/functions/wma.md) | 2 | Start-Independent | A windowed average: it reads a fixed number of bars and forgets everything older. | | [DEMA](/functions/dema.md) | 3 | Initial Unstable Period | Built from EMA, and inherits its unstable period. | | [TEMA](/functions/tema.md) | 4 | Initial Unstable Period | Built from EMA, and inherits its unstable period. | | [TRIMA](/functions/trima.md) | 5 | Start-Independent | A windowed average: it reads a fixed number of bars and forgets everything older. | | [KAMA](/functions/kama.md) | 6 | Initial Unstable Period | Recursive: each value folds in the previous one. Tunable via KAMA's own unstable period. | | [MAMA](/functions/mama.md) | 7 | Initial Unstable Period | Recursive: each value folds in the previous one. Tunable via MAMA's own unstable period. | | [T3](/functions/t3.md) | 8 | Initial Unstable Period | Recursive: each value folds in the previous one. Tunable via T3's own unstable period. | | [HMA](/functions/hma.md) | 9 | Start-Independent | A windowed average: it reads a fixed number of bars and forgets everything older. | | `DISABLED` | 10 | Start-Independent | Not a moving average: the input is copied through unchanged. | | `DEFAULT` | 11 | — | Not a moving average: selects the documented default of whichever parameter it is passed to. | | [ZLEMA](/functions/zlema.md) | 12 | Initial Unstable Period | Built from EMA, and inherits its unstable period. | | [RMA](/functions/rma.md) | 13 | Initial Unstable Period | Recursive: each value folds in the previous one. Tunable via RMA's own unstable period. | | [VIDYA](/functions/vidya.md) | 14 | Initial Unstable Period | Recursive: each value folds in the previous one. Tunable via VIDYA's own unstable period. | | [ALMA](/functions/alma.md) | 15 | Start-Independent | A windowed average: it reads a fixed number of bars and forgets everything older. | ## If Path-Dependent, then... {#path-dependent} The value is built up from the first bar — a running accumulation or a state machine that tracks the path prices took — so it depends on where your data begins and never converges. Unlike an unstable period, there is no warm-up you can discard: the difference persists for the whole series. Two Examples: * [AD](/functions/ad.md) adds each bar's money-flow volume to a running total that begins at zero on your first bar. Only the differences between bars carry meaning; the absolute level is an artifact of the start date. * [SAR](/functions/sar.md) is a state machine: it reads the first two bars to decide whether the trend starts long or short, then carries that direction, the extreme price, and an acceleration factor forward. Start a day earlier and it can pick the opposite direction, putting the stop on the other side of price for the rest of the run. Do not compare these values across differently-sized windows, and expect a backtest starting at a different date to produce different numbers. --- --- url: 'https://ta-lib.org/api/candle-settings/index.md' description: >- Tune the thresholds the CDL* pattern functions judge candles against: body length, shadows, near-equal candles. Defaults, and how to set them in C, Rust, Java and C#. --- # Candlestick Settings The candlestick pattern functions (the `CDL*` family) judge each candle — is its body "long", its shadow "short", two candles "near" — relative to a set of tunable thresholds. These settings control those judgements. ## API A candle characteristic is measured against an average of a chosen range over the previous `avgPeriod` bars, scaled by `factor`. For each setting type: * **range type** — what to measure: the real body (open-to-close), the high-to-low range, or the two shadows. * **`avgPeriod`** — how many prior bars to average (`0` means "use only the current candle", no averaging). * **`factor`** — the multiplier applied to that average to form the threshold. ::: code-tabs#lang @tab C ```c TA_RetCode TA_SetCandleSettings( TA_CandleSettingType settingType, TA_RangeType rangeType, int avgPeriod, double factor ); TA_RetCode TA_RestoreCandleDefaultSettings( TA_CandleSettingType settingType ); /* Treat a "long body" as 1.2x the average real body of the last 10 candles: */ TA_SetCandleSettings( TA_BodyLong, TA_RangeType_RealBody, 10, 1.2 ); /* ...later, restore the default for that one setting: */ TA_RestoreCandleDefaultSettings( TA_BodyLong ); ``` @tab Rust ```rust use ta_lib::{CandleSetting, CandleSettingType, Core, RangeType}; // Treat a "long body" as 1.2x the average real body of the last 10 candles: let core = Core::builder() .candle_setting( CandleSettingType::BodyLong, CandleSetting { range_type: RangeType::RealBody, avg_period: 10, factor: 1.2 }, ) .build()?; ``` @tab Java ```java import io.github.talib.CandleSettingType; import io.github.talib.Core; import io.github.talib.RangeType; // Treat a "long body" as 1.2x the average real body of the last 10 candles: Core core = Core.builder() .candleSetting(CandleSettingType.BODY_LONG, RangeType.REAL_BODY, 10, 1.2) .build(); // ...later, restore the default for that one setting: Core restored = core.toBuilder() .restoreCandleDefault(CandleSettingType.BODY_LONG) .build(); ``` @tab C# ```csharp using TALib; // Treat a "long body" as 1.2x the average real body of the last 10 candles: Core core = Core.Builder() .CandleSetting(CandleSettingType.BodyLong, RangeType.RealBody, 10, 1.2) .Build(); // ...restore one setting, or every one with AllCandleSettings: Core restored = core.ToBuilder() .RestoreCandleDefault(CandleSettingType.BodyLong) .Build(); ``` ::: ## Setting types and defaults The setting types, with the defaults every binding starts from. C spells them `TA_BodyLong`; Rust `CandleSettingType::BodyLong`; C# `CandleSettingType.BodyLong`; Java takes its own constant case, `CandleSettingType.BODY_LONG`. | Setting | Range type | avgPeriod | factor | |--------------------|------------|-----------|--------| | `BodyLong` | RealBody | 10 | 1.0 | | `BodyVeryLong` | RealBody | 10 | 3.0 | | `BodyShort` | RealBody | 10 | 1.0 | | `BodyDoji` | HighLow | 10 | 0.1 | | `ShadowLong` | RealBody | 0 | 1.0 | | `ShadowVeryLong` | RealBody | 0 | 2.0 | | `ShadowShort` | Shadows | 10 | 1.0 | | `ShadowVeryShort` | HighLow | 10 | 0.1 | | `Near` | HighLow | 5 | 0.2 | | `Far` | HighLow | 5 | 0.6 | | `Equal` | HighLow | 5 | 0.05 | `AllCandleSettings` targets every setting at once. It is meaningful only to the restore call. ## See also * [C/C++ Core API](/api/) / [Rust Core API](/api/rust/) * [Unstable Period](/api/unstable-period/) * The candlestick pattern functions in the [function reference](/functions/) (the `Pattern Recognition` group). --- --- url: 'https://ta-lib.org/functions/index.md' description: >- Every TA-Lib technical analysis function, grouped by category, with the formula, inputs, outputs and source for each. --- # Functions All technical-analysis functions, grouped by category. Each page documents the formula, inputs, outputs, and links to the C / Rust / Java source. ## Cycle Indicators * [HT_DCPERIOD](/functions/ht_dcperiod.md) — Hilbert Transform - Dominant Cycle Period * [HT_DCPHASE](/functions/ht_dcphase.md) — Hilbert Transform - Dominant Cycle Phase * [HT_PHASOR](/functions/ht_phasor.md) — Hilbert Transform - Phasor Components * [HT_SINE](/functions/ht_sine.md) — Hilbert Transform - SineWave * [HT_TRENDMODE](/functions/ht_trendmode.md) — Hilbert Transform - Trend vs Cycle Mode ## Math Operators * [ADD](/functions/add.md) — Vector Arithmetic Add * [CUMSUM](/functions/cumsum.md) — Cumulative Sum * [DIV](/functions/div.md) — Vector Arithmetic Div * [MAX](/functions/max.md) — Highest value over a specified period * [MAXINDEX](/functions/maxindex.md) — Index of highest value over a specified period * [MIN](/functions/min.md) — Lowest value over a specified period * [MININDEX](/functions/minindex.md) — Index of lowest value over a specified period * [MINMAX](/functions/minmax.md) — Lowest and highest values over a specified period * [MINMAXINDEX](/functions/minmaxindex.md) — Indexes of lowest and highest values over a specified period * [MULT](/functions/mult.md) — Vector Arithmetic Mult * [SUB](/functions/sub.md) — Vector Arithmetic Subtraction * [SUM](/functions/sum.md) — Summation ## Math Transform * [ACOS](/functions/acos.md) — Vector Trigonometric ACos * [ASIN](/functions/asin.md) — Vector Trigonometric ASin * [ATAN](/functions/atan.md) — Vector Trigonometric ATan * [CEIL](/functions/ceil.md) — Vector Ceil * [COS](/functions/cos.md) — Vector Trigonometric Cos * [COSH](/functions/cosh.md) — Vector Trigonometric Cosh * [EXP](/functions/exp.md) — Vector Arithmetic Exp * [FLOOR](/functions/floor.md) — Vector Floor * [LN](/functions/ln.md) — Vector Log Natural * [LOG10](/functions/log10.md) — Vector Log10 * [SIN](/functions/sin.md) — Vector Trigonometric Sin * [SINH](/functions/sinh.md) — Vector Trigonometric Sinh * [SQRT](/functions/sqrt.md) — Vector Square Root * [TAN](/functions/tan.md) — Vector Trigonometric Tan * [TANH](/functions/tanh.md) — Vector Trigonometric Tanh ## Momentum Indicators * [AC](/functions/ac.md) — Accelerator/Decelerator Oscillator * [ADX](/functions/adx.md) — Average Directional Movement Index * [ADXR](/functions/adxr.md) — Average Directional Movement Index Rating * [AO](/functions/ao.md) — Awesome Oscillator * [APO](/functions/apo.md) — Absolute Price Oscillator * [AROON](/functions/aroon.md) — Aroon * [AROONOSC](/functions/aroonosc.md) — Aroon Oscillator * [ASI](/functions/asi.md) — Wilder Accumulative Swing Index * [BOP](/functions/bop.md) — Balance Of Power * [CCI](/functions/cci.md) — Commodity Channel Index * [CG](/functions/cg.md) — Center of Gravity Oscillator * [CHOP](/functions/chop.md) — Choppiness Index * [CHOPTR](/functions/choptr.md) — Choppiness Index (True Range Box) * [CMO](/functions/cmo.md) — Chande Momentum Oscillator * [CMOU](/functions/cmou.md) — Chande Momentum Oscillator (Unsmoothed) * [COPPOCK](/functions/coppock.md) — Coppock Curve * [CRSI](/functions/crsi.md) — Connors Relative Strength Index * [CTI](/functions/cti.md) — Correlation Trend Indicator * [DPO](/functions/dpo.md) — Detrended Price Oscillator * [DX](/functions/dx.md) — Directional Movement Index * [ER](/functions/er.md) — Kaufman Efficiency Ratio * [ERI](/functions/eri.md) — Elder Ray Index (Bull Power / Bear Power) * [FOSC](/functions/fosc.md) — Forecast Oscillator * [FRACTAL](/functions/fractal.md) — Williams Fractal * [IBS](/functions/ibs.md) — Internal Bar Strength * [IMI](/functions/imi.md) — Intraday Momentum Index * [KDJ](/functions/kdj.md) — KDJ Stochastic * [KST](/functions/kst.md) — Know Sure Thing (Pring) * [KSTEXT](/functions/kstext.md) — Know Sure Thing with controllable MA type * [MACD](/functions/macd.md) — Moving Average Convergence/Divergence * [MACDEXT](/functions/macdext.md) — MACD with controllable MA type * [MACDFIX](/functions/macdfix.md) — Moving Average Convergence/Divergence Fix 12/26 * [MFI](/functions/mfi.md) — Money Flow Index * [MINUS_DI](/functions/minus_di.md) — Minus Directional Indicator * [MINUS_DM](/functions/minus_dm.md) — Minus Directional Movement * [MOM](/functions/mom.md) — Momentum * [PLUS_DI](/functions/plus_di.md) — Plus Directional Indicator * [PLUS_DM](/functions/plus_dm.md) — Plus Directional Movement * [PPO](/functions/ppo.md) — Percentage Price Oscillator * [QSTICK](/functions/qstick.md) — Qstick * [ROC](/functions/roc.md) — Rate of change : ((price/prevPrice)-1)\*100 * [ROCP](/functions/rocp.md) — Rate of change Percentage: (price-prevPrice)/prevPrice * [ROCR](/functions/rocr.md) — Rate of change ratio: (price/prevPrice) * [ROCR100](/functions/rocr100.md) — Rate of change ratio 100 scale: (price/prevPrice)\*100 * [RSI](/functions/rsi.md) — Relative Strength Index * [SI](/functions/si.md) — Wilder Swing Index * [SMI](/functions/smi.md) — Stochastic Momentum Index * [STC](/functions/stc.md) — Schaff Trend Cycle * [STOCH](/functions/stoch.md) — Stochastic * [STOCHF](/functions/stochf.md) — Stochastic Fast * [STOCHRSI](/functions/stochrsi.md) — Stochastic Relative Strength Index * [TRIX](/functions/trix.md) — 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA * [TSI](/functions/tsi.md) — True Strength Index * [ULTOSC](/functions/ultosc.md) — Ultimate Oscillator * [VHF](/functions/vhf.md) — Vertical Horizontal Filter * [VORTEX](/functions/vortex.md) — Vortex Indicator * [WAD](/functions/wad.md) — Williams' Accumulation/Distribution * [WILLR](/functions/willr.md) — Williams' %R ## Overlap Studies * [ACCBANDS](/functions/accbands.md) — Acceleration Bands * [ALMA](/functions/alma.md) — Arnaud Legoux Moving Average * [BBANDS](/functions/bbands.md) — Bollinger Bands * [CKSP](/functions/cksp.md) — Chande Kroll Stop * [DEMA](/functions/dema.md) — Double Exponential Moving Average * [DONCHIAN](/functions/donchian.md) — Donchian Channels * [EMA](/functions/ema.md) — Exponential Moving Average * [FRAMA](/functions/frama.md) — Fractal Adaptive Moving Average * [HMA](/functions/hma.md) — Hull Moving Average * [HT_TRENDLINE](/functions/ht_trendline.md) — Hilbert Transform - Instantaneous Trendline * [KAMA](/functions/kama.md) — Kaufman Adaptive Moving Average * [KC](/functions/kc.md) — Keltner Channels * [MA](/functions/ma.md) — Moving average * [MAMA](/functions/mama.md) — MESA Adaptive Moving Average * [MAVP](/functions/mavp.md) — Moving average with variable period * [MCGD](/functions/mcgd.md) — McGinley Dynamic * [MIDPOINT](/functions/midpoint.md) — MidPoint over period * [MIDPRICE](/functions/midprice.md) — Midpoint Price over period * [RMA](/functions/rma.md) — Wilder's Smoothed Moving Average * [SAR](/functions/sar.md) — Parabolic SAR * [SAREXT](/functions/sarext.md) — Parabolic SAR - Extended * [SMA](/functions/sma.md) — Simple Moving Average * [SUPERTREND](/functions/supertrend.md) — SuperTrend * [T3](/functions/t3.md) — Triple Exponential Moving Average (T3) * [TEMA](/functions/tema.md) — Triple Exponential Moving Average * [TRIMA](/functions/trima.md) — Triangular Moving Average * [VIDYA](/functions/vidya.md) — Variable Index Dynamic Average * [VWMA](/functions/vwma.md) — Volume Weighted Moving Average * [WMA](/functions/wma.md) — Weighted Moving Average * [ZLEMA](/functions/zlema.md) — Zero-Lag Exponential Moving Average ## Pattern Recognition * [CDL2CROWS](/functions/cdl2crows.md) — Two Crows * [CDL3BLACKCROWS](/functions/cdl3blackcrows.md) — Three Black Crows * [CDL3INSIDE](/functions/cdl3inside.md) — Three Inside Up/Down * [CDL3LINESTRIKE](/functions/cdl3linestrike.md) — Three-Line Strike * [CDL3OUTSIDE](/functions/cdl3outside.md) — Three Outside Up/Down * [CDL3STARSINSOUTH](/functions/cdl3starsinsouth.md) — Three Stars In The South * [CDL3WHITESOLDIERS](/functions/cdl3whitesoldiers.md) — Three Advancing White Soldiers * [CDLABANDONEDBABY](/functions/cdlabandonedbaby.md) — Abandoned Baby * [CDLADVANCEBLOCK](/functions/cdladvanceblock.md) — Advance Block * [CDLBELTHOLD](/functions/cdlbelthold.md) — Belt-hold * [CDLBREAKAWAY](/functions/cdlbreakaway.md) — Breakaway * [CDLCLOSINGMARUBOZU](/functions/cdlclosingmarubozu.md) — Closing Marubozu * [CDLCONCEALBABYSWALL](/functions/cdlconcealbabyswall.md) — Concealing Baby Swallow * [CDLCOUNTERATTACK](/functions/cdlcounterattack.md) — Counterattack * [CDLDARKCLOUDCOVER](/functions/cdldarkcloudcover.md) — Dark Cloud Cover * [CDLDOJI](/functions/cdldoji.md) — Doji * [CDLDOJISTAR](/functions/cdldojistar.md) — Doji Star * [CDLDRAGONFLYDOJI](/functions/cdldragonflydoji.md) — Dragonfly Doji * [CDLENGULFING](/functions/cdlengulfing.md) — Engulfing Pattern * [CDLEVENINGDOJISTAR](/functions/cdleveningdojistar.md) — Evening Doji Star * [CDLEVENINGSTAR](/functions/cdleveningstar.md) — Evening Star * [CDLGAPSIDESIDEWHITE](/functions/cdlgapsidesidewhite.md) — Up/Down-gap side-by-side white lines * [CDLGRAVESTONEDOJI](/functions/cdlgravestonedoji.md) — Gravestone Doji * [CDLHAMMER](/functions/cdlhammer.md) — Hammer * [CDLHANGINGMAN](/functions/cdlhangingman.md) — Hanging Man * [CDLHARAMI](/functions/cdlharami.md) — Harami Pattern * [CDLHARAMICROSS](/functions/cdlharamicross.md) — Harami Cross Pattern * [CDLHIGHWAVE](/functions/cdlhighwave.md) — High-Wave Candle * [CDLHIKKAKE](/functions/cdlhikkake.md) — Hikkake Pattern * [CDLHIKKAKEMOD](/functions/cdlhikkakemod.md) — Modified Hikkake Pattern * [CDLHOMINGPIGEON](/functions/cdlhomingpigeon.md) — Homing Pigeon * [CDLIDENTICAL3CROWS](/functions/cdlidentical3crows.md) — Identical Three Crows * [CDLINNECK](/functions/cdlinneck.md) — In-Neck Pattern * [CDLINVERTEDHAMMER](/functions/cdlinvertedhammer.md) — Inverted Hammer * [CDLKICKING](/functions/cdlkicking.md) — Kicking * [CDLKICKINGBYLENGTH](/functions/cdlkickingbylength.md) — Kicking - bull/bear determined by the longer marubozu * [CDLLADDERBOTTOM](/functions/cdlladderbottom.md) — Ladder Bottom * [CDLLONGLEGGEDDOJI](/functions/cdllongleggeddoji.md) — Long Legged Doji * [CDLLONGLINE](/functions/cdllongline.md) — Long Line Candle * [CDLMARUBOZU](/functions/cdlmarubozu.md) — Marubozu * [CDLMATCHINGLOW](/functions/cdlmatchinglow.md) — Matching Low * [CDLMATHOLD](/functions/cdlmathold.md) — Mat Hold * [CDLMORNINGDOJISTAR](/functions/cdlmorningdojistar.md) — Morning Doji Star * [CDLMORNINGSTAR](/functions/cdlmorningstar.md) — Morning Star * [CDLONNECK](/functions/cdlonneck.md) — On-Neck Pattern * [CDLPIERCING](/functions/cdlpiercing.md) — Piercing Pattern * [CDLRICKSHAWMAN](/functions/cdlrickshawman.md) — Rickshaw Man * [CDLRISEFALL3METHODS](/functions/cdlrisefall3methods.md) — Rising/Falling Three Methods * [CDLSEPARATINGLINES](/functions/cdlseparatinglines.md) — Separating Lines * [CDLSHOOTINGSTAR](/functions/cdlshootingstar.md) — Shooting Star * [CDLSHORTLINE](/functions/cdlshortline.md) — Short Line Candle * [CDLSPINNINGTOP](/functions/cdlspinningtop.md) — Spinning Top * [CDLSTALLEDPATTERN](/functions/cdlstalledpattern.md) — Stalled Pattern * [CDLSTICKSANDWICH](/functions/cdlsticksandwich.md) — Stick Sandwich * [CDLTAKURI](/functions/cdltakuri.md) — Takuri (Dragonfly Doji with very long lower shadow) * [CDLTASUKIGAP](/functions/cdltasukigap.md) — Tasuki Gap * [CDLTHRUSTING](/functions/cdlthrusting.md) — Thrusting Pattern * [CDLTRISTAR](/functions/cdltristar.md) — Tristar Pattern * [CDLUNIQUE3RIVER](/functions/cdlunique3river.md) — Unique 3 River * [CDLUPSIDEGAP2CROWS](/functions/cdlupsidegap2crows.md) — Upside Gap Two Crows * [CDLXSIDEGAP3METHODS](/functions/cdlxsidegap3methods.md) — Upside/Downside Gap Three Methods ## Price Transform * [AVGDEV](/functions/avgdev.md) — Average Deviation * [AVGPRICE](/functions/avgprice.md) — Average Price * [HA](/functions/ha.md) — Heikin-Ashi Candles * [MEDPRICE](/functions/medprice.md) — Median Price * [TYPPRICE](/functions/typprice.md) — Typical Price * [WCLPRICE](/functions/wclprice.md) — Weighted Close Price ## Statistic Functions * [BETA](/functions/beta.md) — Beta * [CORREL](/functions/correl.md) — Pearson's Correlation Coefficient (r) * [KURTOSIS](/functions/kurtosis.md) — Rolling Excess Kurtosis * [LINEARREG](/functions/linearreg.md) — Linear Regression * [LINEARREG_ANGLE](/functions/linearreg_angle.md) — Linear Regression Angle * [LINEARREG_INTERCEPT](/functions/linearreg_intercept.md) — Linear Regression Intercept * [LINEARREG_SLOPE](/functions/linearreg_slope.md) — Linear Regression Slope * [MEDIAN](/functions/median.md) — Rolling Median * [PERCENTILE](/functions/percentile.md) — Percentile (nearest rank) * [PERCENTRANK](/functions/percentrank.md) — Percent Rank * [STDDEV](/functions/stddev.md) — Standard Deviation * [TSF](/functions/tsf.md) — Time Series Forecast * [VAR](/functions/var.md) — Variance ## Volatility Indicators * [ADR](/functions/adr.md) — Average Day Range * [ATR](/functions/atr.md) — Average True Range * [BBW](/functions/bbw.md) — Bollinger BandWidth * [CVI](/functions/cvi.md) — Chaikin's Volatility * [MASSI](/functions/massi.md) — Mass Index * [NATR](/functions/natr.md) — Normalized Average True Range * [PERCENTB](/functions/percentb.md) — Bollinger Bands %B * [RVI](/functions/rvi.md) — Relative Volatility Index * [RVIR](/functions/rvir.md) — Relative Volatility Index, refined high/low form * [TRANGE](/functions/trange.md) — True Range ## Volume Indicators * [AD](/functions/ad.md) — Chaikin A/D Line * [ADOSC](/functions/adosc.md) — Chaikin A/D Oscillator * [CMF](/functions/cmf.md) — Chaikin Money Flow * [EFI](/functions/efi.md) — Elder's Force Index * [EMV](/functions/emv.md) — Arms Ease of Movement * [MARKETFI](/functions/marketfi.md) — Market Facilitation Index * [NVI](/functions/nvi.md) — Negative Volume Index * [OBV](/functions/obv.md) — On Balance Volume * [PVI](/functions/pvi.md) — Positive Volume Index * [PVO](/functions/pvo.md) — Percentage Volume Oscillator * [PVT](/functions/pvt.md) — Price Volume Trend * [RVOL](/functions/rvol.md) — Relative Volume * [VWAP](/functions/vwap.md) — Volume Weighted Average Price --- --- url: 'https://ta-lib.org/index.md' description: >- Open-source technical analysis library: 200+ indicators (ADX, MACD, RSI), candlestick patterns. Native C/C++, Java, C# and Rust, plus Python and R wrappers. --- # TA-Lib
TA-Lib ### Technical analysis, battle-tested since 2001
* 200+ indicators such as ADX, MACD, RSI, Stochastic, Bollinger Bands etc... [See complete list...](/functions/) * Candlestick patterns recognition * Native implementation in [C/C++](/api/), [Java](/api/java/), [C#](/api/csharp/) and [Rust](/api/rust/). * Wrappers for Python, R, and [more](/install/#wrappers). * Open-Source (BSD License). Can be freely integrated in your own open-source or commercial applications. TA-Lib implements standard technical analysis algorithms used across the industry — stable, well-tested, and production-proven. --- --- url: 'https://ta-lib.org/about/index.md' description: >- Who builds TA-Lib: the administrators, feature contributors, wrapper authors and issue reporters credited across two decades of the project. --- # About Us TA-Lib has been built and refined by an open community of traders, engineers and researchers for more than two decades. This page credits the people whose work is recorded across the source tree and the wider ecosystem. Join us on [Discord](https://discord.com/invite/Erb6SwsVbH)!
## TA-Lib Administrators | Administrator | Role | | --- | --- | | **Mario Fortier** — [@mario4tier](https://github.com/mario4tier) | Founder and lead maintainer. Original author of the C/C++ core. | | **John Benediktsson** — [@mrjbq7](https://github.com/mrjbq7) | Author and lead maintainer. Created the Python ([ta-lib-python](https://github.com/TA-Lib/ta-lib-python)) and Zig ([ta-lib-zig](https://github.com/TA-Lib/ta-lib-zig)) wrappers; `ta-lib-python` is by far the most widely used TA-Lib binding. | ## Feature Contributors The people behind some of TA-Lib's major features. | Contributor | Contribution | | --- | --- | | **Angelo Ciceri** | Candlestick pattern recognition — the complete family of `CDL*` functions. | | **Chad Furman** — [@chadfurman](https://github.com/chadfurman) | Native Rust port and co-designer of `ta_codegen`, which now automates maintenance of every backend (C, Rust, Java, .NET, docs, streaming API) from a single source of truth. | | **Barry Tsung** | Early Java `Core`: candle-settings initialization and unstable-period APIs. | | **Richard Gomes** | Java abstract/reflection layer — the `meta` package: annotation-based RTTI and late-bound (dynamic) TA-function invocation. | | **Paweł Konieczny** | Early contributor to `ta_regtest`, the build system and the now-defunct `ta_data` feature. | | **Alexander Trufanov** — [@trufanov-nok](https://github.com/trufanov-nok) | Numerical-robustness improvements and streaming-API inspiration. | | **[@kevinlincg](https://github.com/kevinlincg)** | Multiple new TA functions, plus optimizations, fixes and test coverage across the generator and every backend. | ### Language wrappers {#wrappers} TA-Lib reaches many languages thanks to the maintainers of these wrappers: | Maintainer | Wrapper | | --- | --- | | **John Benediktsson** — [@mrjbq7](https://github.com/mrjbq7) | Python — [ta-lib-python](https://github.com/TA-Lib/ta-lib-python) · Zig — [ta-lib-zig](https://github.com/TA-Lib/ta-lib-zig) | | **Brad Peabody** — [@bradleypeabody](https://github.com/bradleypeabody) | Go — [ta-lib-cgo](https://github.com/TA-Lib/ta-lib-cgo) | | **Rafael Ernesto Espinosa Santiesteban** — [@rernesto](https://github.com/rernesto) | PHP — [ext-ta-lib](https://github.com/TA-Lib/ext-ta-lib) | | **Marcelo Teixeira Monteiro** — [@tuxmonteiro](https://github.com/tuxmonteiro) | PostgreSQL — [ta_pg](https://github.com/TA-Lib/ta_pg) | | **Victor Yang** — [@Youngv](https://github.com/Youngv) | Ruby — [ta-lib-ruby](https://github.com/TA-Lib/ta-lib-ruby) | | **Serkan Korkmaz** — [@serkor1](https://github.com/serkor1) | R — [ta-lib-R](https://github.com/serkor1/ta-lib-R) | | **Kevin Johnson** — [@twopirllc](https://github.com/twopirllc) (original author) · **[@xgboosted](https://github.com/xgboosted)** (current maintainer) | pandas — [pandas-ta-classic](https://github.com/xgboosted/pandas-ta-classic) | ## Other Code Contributors Everyone else whose fixes, optimizations and new functions are recorded in the TA-Lib source tree. | Contributor | Contribution | | --- | --- | | **Adrian Michel** — [amichel.com](http://amichel.com) | Fixed the missing `atan()` in `LINEARREG_ANGLE`. | | **Anatoliy Belsky** | Initial implementations of `IMI` and `AVGDEV`. | | **Anatoliy Siryi** — [@hmG3](https://github.com/hmG3) | Visual Studio 2022 build support ([#34](https://github.com/TA-Lib/ta-lib/pull/34)). | | **Andrew Atkinson** | Lookback, out-of-bounds and null-pointer fixes in `APO`, `PPO`, `STOCHRSI` and `TRIX`. | | **[@CaptainTrunky](https://github.com/CaptainTrunky)** | Conan package-manager support ([#86](https://github.com/TA-Lib/ta-lib/issues/86)). | | **Chris** — crokusek@hotmail.com | Reported the `TRIMA` range-handling bug. | | **Christo Fogelberg** | `period = 1` correctness fixes across `SAR`, `PLUS_DI`/`PLUS_DM` and `MINUS_DI`. | | **Christopher Barnhouse** | Fixed an out-of-bounds write in `CDLTRISTAR`. | | **Drew McCormack** — [trade-strategist.com](http://www.trade-strategist.com) | Initial implementation of `ULTOSC`. | | **echo999** — echo999@ifrance.com | Found and fixed a `STOCHF` `outFastD` bug. | | **Fernando José** — [@iglesias](https://github.com/iglesias) | Fixed a floating-point multiplication overflow ([#33](https://github.com/TA-Lib/ta-lib/pull/33)). | | **[@greenTableWork](https://github.com/greenTableWork)** | Helper script for the vcpkg post-release PR workflow ([#82](https://github.com/TA-Lib/ta-lib/pull/82)). | | **guycom** | Reported the `ADX` divide-by-zero bug. | | **[@halohsu](https://github.com/halohsu)** | macOS libtool build support ([#39](https://github.com/TA-Lib/ta-lib/pull/39)). | | **jdoyle** | Fixed start/end range handling in `AD`. | | **Jesus Viver** | Speed optimizations for `STDDEV`, `VAR`, `MIN` and `MAX`. | | **John Price** — jp_talib@gcfl.net | Initial implementation of the `LINEARREG` family. | | **JP Pienaar** | Fixed the `MACD` period-swap logic. | | **Kenneth Jorgensen** — [@kennethjor](https://github.com/kennethjor) | Documentation index (`index.md`) updates ([#70](https://github.com/TA-Lib/ta-lib/pull/70)). | | **[@Lqingyu](https://github.com/Lqingyu)** | Out-of-bounds fix in the regression-test tooling ([#62](https://github.com/TA-Lib/ta-lib/pull/62)). | | **Major Hayden** — [@major](https://github.com/major) | Added the BSD 3-Clause LICENSE file ([#38](https://github.com/TA-Lib/ta-lib/pull/38)). | | **Matthew Lindblom** | Implementation of `T3`. | | **Michael Williamson** | Initial implementation of `BETA`. | | **Mikhail Smirnov** — [@cpp4ever](https://github.com/cpp4ever) | CMake build-script fix ([#9](https://github.com/TA-Lib/ta-lib/pull/9)). | | **Mirek Fontan** — [fontan.cz](http://fontan.cz) | Reported a divide-by-zero bug. | | **[@mw66](https://github.com/mw66)** | Removed the spurious unstable period from `MFI`. | | **[@nehemiah888](https://github.com/nehemiah888)** | Added function documentation, including Chinese translations ([#75](https://github.com/TA-Lib/ta-lib/pull/75)). | | **Peter Pudaite** | Initial `STOCHRSI`; reworked the `SAREXT` parameters. | | **Robert Meier** | Initial implementation of `ACCBANDS`. | | **Rowe Wilson Frederisk Holme** — [@Frederisk](https://github.com/Frederisk) | Fixed the `CdlStickSandwich` name typos ([#28](https://github.com/TA-Lib/ta-lib/pull/28)). | | **Thorsten Alteholz** — [@alteholz](https://github.com/alteholz) | Spelling fixes across the library, including the `TA_LIB_NOT_INITIALIZE` return-code message ([#68](https://github.com/TA-Lib/ta-lib/pull/68)). | | **Vikas N Kumar** — [@vikasnkumar](https://github.com/vikasnkumar) | Debian 11 / Ubuntu 22.04 support with a lower minimum CMake version ([#51](https://github.com/TA-Lib/ta-lib/pull/51)). | | **Vincent Bernardoff** — [@vbmithr](https://github.com/vbmithr) | Linux / autotools build fixes ([#1](https://github.com/TA-Lib/ta-lib/pull/1)). | | **wony** — [@wony-zheng](https://github.com/wony-zheng) | Removed the spurious unstable period from `IMI`. | ## Issue Reporters Community members whose bug reports and requests led to a committed change — with our thanks. | Reporter | Issue | | --- | --- | | **[@731315163](https://github.com/731315163)** | `HT_TRENDLINE` internal-buffer investigation ([#88](https://github.com/TA-Lib/ta-lib/issues/88)). | | **Anton Danylchenko** — [@1st](https://github.com/1st) | Proposed the GitHub Action, now [setup-ta-lib](https://github.com/TA-Lib/setup-ta-lib) ([#79](https://github.com/TA-Lib/ta-lib/issues/79)). | | **Benjamin Leff** — [@BwL1289](https://github.com/BwL1289) | CMake `libm` linkage and shared/static build options ([#77](https://github.com/TA-Lib/ta-lib/issues/77), [#78](https://github.com/TA-Lib/ta-lib/issues/78)). | | **Cole Richardson** — [@SeeRich](https://github.com/SeeRich) | Requested the repository LICENSE file ([#35](https://github.com/TA-Lib/ta-lib/issues/35)). | | **[@hotston](https://github.com/hotston)** | Reported MACD signal-line repainting, leading to the `period = 1` fix ([#59](https://github.com/TA-Lib/ta-lib/issues/59)). | | **Ilia Pozdnyakov** — [@iliazeus](https://github.com/iliazeus) | Prompted a release including the small-values fix ([#31](https://github.com/TA-Lib/ta-lib/issues/31)). | | **Jake Arkinstall** — SourceForge | `HT_TRENDLINE` internal-buffer investigation ([#88](https://github.com/TA-Lib/ta-lib/issues/88)). |
*** Want to help? See [How to contribute a new TA function](/contribute/), [How to get support](/faq/) or open an issue on [GitHub](https://github.com/TA-Lib/ta-lib/issues). --- --- url: 'https://ta-lib.org/contribute/index.md' description: >- Contribute a new TA function to TA-Lib: agree the spec in the open, hand the implementation to an AI agent, prove it against golden values from an oracle. --- # How to Contribute a New TA Function ::: tip Just want to request a function, not implement it? Then add it to the [New TA Functions board](https://github.com/orgs/TA-Lib/projects/1) and someone else might implement it for you. ::: TA-Lib development is **human-driven specs, AI-driven code**. The implementation is meant to be written by an AI agent: hand it this page, which contains everything needed to do the job. Humans agree, in the open, what a function computes before code is written: its name, formula, inputs, parameters and defaults. No function is ever integrated without hardcoded golden values in the regression tests, taken from an independent oracle or a published sample. The regression tests are the final arbiter of correctness, and they are human-reviewed. The test harness is exhaustive (verifies many edge cases) and you should not have to modify these. Any modification to the harness requires explicit human approval. Adding and registering your own function's test is expected. "The harness" means the shared machinery: the comparison gates, tolerances and other functions' tests. ## What a contribution looks like TA-Lib generates all of its per-function code from a single source of truth. One function is one directory, `ta_codegen/input//`, holding three files: | File | Contains | | --- | --- | | `.yaml` | Metadata: inputs, outputs, parameters, defaults, group, flags. Data only, never logic. | | `.c` | The algorithm: a `_lookback()` and a `()` batch function, in plain portable C. | | `.md` | Documentation: summary, the formula in its original algebraic form, references. | From these three files, the `ta_codegen` generator produces everything the project ships: the C library, native Rust, Java and .NET implementations, streaming variants, the test servers, benchmarks, and this website's function page. You never write Rust, Java or C# by hand, and you never edit generated files. Every backend is then verified by `ta_regtest`, which drives all languages through JSON-RPC servers and cross-checks their outputs against the C reference, bit-for-bit in the strictest gates. ## Development setup Any of Linux, macOS, Windows or WSL2. You need: * git, a C compiler (gcc/clang/MSVC), CMake ≥ 3.18 * The Rust toolchain via [rustup](https://rustup.rs) (the generator is written in Rust) * Recommended, for full cross-language verification: a JDK (`javac`/`java`) and the .NET SDK (`dotnet`) that `global.json` pins, or a later patch of its band; `scripts/build.py libraries`, which builds the publishable Java/C# artifacts, also needs `unzip` for the committed Maven wrapper. Without them, pass `--language=c,rust` to `scripts/build.py servers` and `scripts/regtest.py`. The C and Rust gates still verify your function, and CI runs the full matrix. ```bash git clone https://github.com/TA-Lib/ta-lib.git cd ta-lib git switch dev # contributions branch from and merge into dev scripts/build.py # build the C library + tools scripts/build.py test # run the C regression tests (confirms your setup works) scripts/build.py servers # build the generator + the per-language test servers ``` `scripts/build.py` checks prerequisites per target and configures CMake automatically on first run. ## Steps 1. **Agree on the spec first.** Claim a card on the [board](https://github.com/orgs/TA-Lib/projects/1), or open an issue if there is none. Settle the name, group, inputs, parameters with defaults, flags (does it stream?), and the formula with a citable reference before writing code. This is the human-approved part. 2. **Write the three input files** in `ta_codegen/input//`. Start by copying a similar shipped function; `ta_codegen/input/cmf/` is a small, recent example. Input files carry no license header — the generator injects the BSD-3-Clause notice into every generated file — but the `.c` opens with a contributor and change-history block: add your initials there, and a one-line MMDDYY entry describing your change. The file-format references are in the repository: [`docs/ta_codegen_input_yaml.md`](https://github.com/TA-Lib/ta-lib/blob/dev/docs/ta_codegen_input_yaml.md), [`ta_codegen_input_code.md`](https://github.com/TA-Lib/ta-lib/blob/dev/docs/ta_codegen_input_code.md) and [`ta_codegen_input_doc.md`](https://github.com/TA-Lib/ta-lib/blob/dev/docs/ta_codegen_input_doc.md). When in doubt, read your checkout's copy; it tracks the generator you are running. 3. **Generate** all backends: `scripts/build.py generate`, then `scripts/build.py servers` to rebuild the language servers from the regenerated sources. 4. **Verify**: run `scripts/regtest.py`, the full pipeline. Its `ta_regtest --codegen` step diffs every language server against the C library, a brand-new function like any other: that proves the languages agree, and the next step proves the values. `--no-perftest` skips the benchmarks a correctness change does not need. 5. **Prove the values.** A new function needs a regression test with golden values from an independent source: a published reference implementation or worked examples from the literature. Document the source, its version and the tolerance at the test call site; against a double-precision oracle ~1e-12 relative is typical, and anything looser needs a written justification. See `src/tools/ta_regtest/ta_test_func/test_composite1.c` for a composite and `test_marketfi.c` for a standalone file, and register the test in four places: a prototype in `ta_test_func.h`, a `DO_TEST` entry in `ta_regtest.c` whose tag names every function the group covers, and the file added to both `CMakeLists.txt` and `src/tools/ta_regtest/Makefile.am` (`scripts/build.py check-source-lists` verifies the two agree). While iterating, `cd bin && ./ta_regtest --codegen --function=` re-runs just your group; each call it routes through `server_verify` is also cross-checked bitwise against every language server. 6. **Check the diff.** After regenerating, `git diff` should touch only files belonging to your function. Unrelated churn in other generated files means something is wrong. 7. **Open a pull request** against the `dev` branch, citing the spec issue and the verification source. Stuck at any step? Ask on [Discord](https://discord.com/invite/Erb6SwsVbH) or comment on your spec issue. ## Notes for AI assistants You are implementing a TA function for TA-Lib, following the steps above on behalf of a human contributor. Additional constraints and pointers: **Ground truth is the repository, not this page.** Read, in order: * `CLAUDE.md` at the repo root * In `docs/`: `ta_codegen_input_yaml.md`, then `ta_codegen_input_code.md`, then `ta_codegen_input_doc.md` If this page and the repo disagree, the repo wins; it is versioned with the code. If you are Claude Code, the repo ships a `/new-ta-func` skill that automates this workflow; use it. It is an accelerator, not a requirement: everything it does is covered by this page and the repository docs. **Invariants.** Violating any of these fails review: * No logic in YAML, ever. No metadata in the `.c` file. * Never edit generated output: `src/ta_func/`, `src/ta_abstract/` and the per-function sources under `ta_codegen/output/` are overwritten on the next `generate`. Change `ta_codegen/input/` and regenerate. Not all of `output/` is generated — the hand-written scaffolding, the build files (`pom.xml`, `TALib.csproj`) and the Java and C# test suites live there too, and `generate` preserves them; treat those as harness, per the rule above. **A banner is proof that a file is generated; its absence is not proof of the opposite.** Around thirty committed files are emitted without one — `src/ta_abstract/ta_abstract.c` among them, written by `backends/ta_abstract_c.rs`. Before editing anything under `src/` or `output/`, grep the generator for the file name; `generate` reverts an edit it owns without a word. * `.md` documents the original algebra of the indicator, never implementation artifacts: no zero-guards, epsilon comparisons or `period == 1` special cases in the formula. State the value returned where the algebra is undefined only when a reader would otherwise wonder, as RVI's `or 50 when Up + Down = 0` does; a guard that merely avoids a divide by zero is noise. * In the `.c` input, call other TA functions by their bare lowercase name (`sma(...)`, `ema_lookback(...)`); the generator resolves each to the language's native symbol. * Your function may be called with an output array aliasing one of its inputs — `outReal == inClose` is a supported, tested calling convention. Within a bar, read every input value you need *before* writing that bar's output; a trailing index can reach the slot you just wrote. Carry what you need in a scalar. Every function is checked, bitwise, on every input/output pair. * Emit each value at the bar whose data computes it. A chart that plots the line shifted forward or backward does not shift the output array, and no output may read a bar after its own. * A decaying recursion the function defines itself (a Wilder or EMA-style update, an adaptive alpha, IIR filter poles) gets its own `TA_FUNC_UNST_` id. One the primary source defines as a call to a function that already has an unstable period (EMA, RSI, ATR) is inherited through that callee's lookback and gets no id; one function can have both. Finite windows and non-decaying state (running sums, resets, pivots, counts) get none. * Enums, groups and other shared surfaces are generated; search the generator before hand-adding one anywhere. * If `generate` panics on a C construct, do not contort the algorithm to dodge the parser. Match the style of a shipped input file, or raise it on the spec issue: parser extensions are generator changes and need maintainer sign-off. **Definition of done:** * `scripts/regtest.py` passes end to end (C tests + all-language verification). * The new function has a non-vacuous test: golden values from an independent source, with source, version and tolerance documented at the call site. A test that cannot fail on a wrong formula does not count. To show it cannot, break what it guards and watch it go red — and in a generated tree, confirm the break actually landed: mutate `ta_codegen/input/`, regenerate, then check the mutation is present in the generated source. A green gate over a mutation that never reached the code means *sabotage never applied*, not *guard verified*. * Regeneration is idempotent: running `generate` again leaves `git status` clean. * The generator's own suite passes: `cd ta_codegen/generator && cargo test`. Some of its tests are inventories keyed on a function's properties; a new function may belong in one. A failure naming your function in a test you never touched is the inventory asking to be updated, not a regression. * The generated `website/src/functions/.md` is correct; its sections are gated against the YAML by the generator. Optional live preview: `cd website && pnpm install && pnpm docs:dev` (needs Node and pnpm). **DO NOT:** * **DO NOT** compute golden values yourself and attribute them to a reference implementation. What makes an oracle independent is not the citation but the execution: the values must be *produced by running* the cited source at the cited version, or transcribed unchanged from a table published in it. Re-deriving the formula and labelling the result with a vendor's name is the same computation twice with a false provenance attached — worse than no oracle, because it agrees with your implementation for exactly the reason it must not. If you cannot run the source, say so on the spec issue rather than substituting your own arithmetic; a maintainer may be able to run it for you. * **DO NOT** invent parameter defaults or ranges. The `.yaml` spec is the human-approved source of truth for acceptable ranges and defaults; ask the contributor. * **DO NOT** modify the test harness or loosen a tolerance to make a gate pass. Harness changes require explicit human approval. * **DO NOT** include unrelated generated-file churn in the pull request. * **DO NOT** commit or push without explicit human approval. --- --- url: 'https://ta-lib.org/faq/index.md' description: >- Whether TA-Lib is still maintained (yes, actively again since 2025) and where to get support: Discord, GitHub issues and the wrapper communities. --- # FAQ **Is TA-Lib maintained?** Yes — and more actively than it has been in years! Development slowed to a near-hibernation between 2014 and 2024. That changed in 2025: packaging was modernized with automated CI/CD releases, and new feature development is underway — including a native Rust implementation, a streaming API, and more. The classic C library is as reliable as ever, and the project is once again moving forward. **How to get support?** Various ways: * Open a discussion on [Discord](https://discord.com/invite/Erb6SwsVbH) * Open a [Github Issue](https://github.com/TA-Lib/ta-lib/issues) * Check these communities: * --- --- url: 'https://ta-lib.org/install/index.md' description: >- Install TA-Lib: a dozen languages, natively or through a wrapper. Native C/C++, Java, C# and Rust, plus community wrappers for Python, R, Go, Ruby, PHP, Zig and more. --- # Install TA-Lib reaches a dozen languages: natively, or through a wrapper. ## Native Implementation * [C/C++](/install/c/) * [C#](/api/csharp/) * [Java](/api/java/) * [Rust](/api/rust/) ## Wrappers Community-maintained bindings for other ecosystems. | Language | Github Repos | | --- | --- | | Go | [ta-lib-cgo](https://github.com/TA-Lib/ta-lib-cgo) | | pandas | [pandas-ta-classic](https://github.com/xgboosted/pandas-ta-classic) | | PHP | [ext-ta-lib](https://github.com/TA-Lib/ext-ta-lib) | | PostgreSQL | [ta_pg](https://github.com/TA-Lib/ta_pg) | | Python | [ta-lib-python](https://github.com/ta-lib/ta-lib-python) | | R | [ta-lib-R](https://github.com/serkor1/ta-lib-R) | | Ruby | [ta-lib-ruby](https://github.com/TA-Lib/ta-lib-ruby) | | Zig | [ta-lib-zig](https://github.com/TA-Lib/ta-lib-zig) | --- --- url: 'https://ta-lib.org/install/c/index.md' description: >- Install the TA-Lib C/C++ libraries and headers: Windows installer, macOS Homebrew, Linux packages, or build from source with CMake or autotools. --- # Install C/C++ Instructions for installing the shared/static libraries and headers on your system. Latest release is [0.8.1 on Github](https://github.com/ta-lib/ta-lib/releases/latest) Both CMake and autotools build systems are included, enabling an optimized build from source on most platforms. * [Windows](#windows) * [Executable Installer (recommended)](#executable-installer-recommended) * [Binaries](#windows-binaries) * [Build from source](#windows-build-from-source) * [macOS](#macos) * [Homebrew (recommended)](#macos-homebrew-recommended) * [Build from source](#macos-build-from-source) * [Linux](#linux) * [Debian packages](#linux-debian-packages) * [Build from source](#linux-build-from-source) * [vcpkg](#vcpkg) * [Use it from CMake](#use-it-from-cmake) * [GitHub Actions](#github-actions) ## Windows ### Executable Installer (recommended) 1. **Download** latest [ta-lib-0.8.1-windows-x86_64.msi](https://github.com/ta-lib/ta-lib/releases/download/v0.8.1/ta-lib-0.8.1-windows-x86_64.msi) 2. **Run the Installer**: * Double-click the downloaded `.msi` file. * Follow the on-screen instructions. To update, just repeat the installation (older version is automatically uninstalled). If you choose to uninstall, use the [Add/Remove Apps](https://support.microsoft.com/en-us/windows/uninstall-or-remove-apps-and-programs-in-windows-4b55f974-2cc6-2d2b-d092-5905080eaf98) in windows settings. If you prefer a non-interactive installation, you can use msiexec [from the command line](https://learn.microsoft.com/en-us/windows/win32/msi/standard-installer-command-line-options). ### Windows Binaries Use the .zip packages when you prefer to get the libraries without installing (e.g. to embed the TA-Lib binaries in your own installer). | Platform | Download | |------------------------|--| | Intel/AMD 64-bits| [ta-lib-0.8.1-windows-x86_64.zip](https://github.com/ta-lib/ta-lib/releases/download/v0.8.1/ta-lib-0.8.1-windows-x86_64.zip) | | Intel/AMD 32-bits| [ta-lib-0.8.1-windows-x86_32.zip](https://github.com/ta-lib/ta-lib/releases/download/v0.8.1/ta-lib-0.8.1-windows-x86_32.zip) | | ARM64 | Not yet available. | ### Windows Build from Source Install Visual Studio 2022 Community and do: ```cmd C:\ta-lib> "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 C:\ta-lib> mkdir build C:\ta-lib> cd build C:\ta-lib\build> cmake .. C:\ta-lib\build> cmake --build . ``` You might need to adjust the `vcvarsall.bat` command depending on your Visual Studio installation and platform. ## macOS ### macOS Homebrew (recommended) ```bash brew install ta-lib ``` See the [homebrew formula](https://formulae.brew.sh/formula/ta-lib) for the latest supported release and platforms. ### macOS Build from Source Ensure you have the required dependencies: `brew install automake && brew install libtool` 1. **Download** latest [ta-lib-0.8.1-src.tar.gz](https://github.com/ta-lib/ta-lib/releases/download/v0.8.1/ta-lib-0.8.1-src.tar.gz) (or, alternatively, clone down and checkout the main branch) 2. **Extract the Tarball** if you downloaded the source manually: ```bash tar -xzf ta-lib-0.8.1-src.tar.gz cd ta-lib-0.8.1 ``` 3. **Build and Install**: ```bash chmod +x autogen.sh # ensure the permissions are set to generate the configure file ./autogen.sh # generate the configure file ./configure make sudo make install ``` Follow the same procedure for an update (the older version is overwritten, no need to uninstall). If you choose to uninstall do: ```bash sudo make uninstall ``` ## Linux ### Linux Debian Packages Recommended for all debian-based distributions (e.g. Ubuntu, Mint...) 1. **Download** the `.deb` package matching your platform: | Platform | Download | |------------------------|--| | Intel/AMD 64-bits | [ta-lib_0.8.1_amd64.deb](https://github.com/ta-lib/ta-lib/releases/download/v0.8.1/ta-lib_0.8.1_amd64.deb) | | ARM64 (e.g. Raspberry Pi)| [ta-lib_0.8.1_arm64.deb](https://github.com/ta-lib/ta-lib/releases/download/v0.8.1/ta-lib_0.8.1_arm64.deb) | | Intel/AMD 32-bits| [ta-lib_0.8.1_i386.deb](https://github.com/ta-lib/ta-lib/releases/download/v0.8.1/ta-lib_0.8.1_i386.deb) | 2. **Install or Update**: ```bash # For Intel/AMD (64 bits) sudo dpkg -i ta-lib_0.8.1_amd64.deb # or sudo dpkg -i ta-lib_0.8.1_arm64.deb # or sudo dpkg -i ta-lib_0.8.1_i386.deb ``` If you choose to uninstall do: ```bash sudo dpkg -r ta-lib ``` ### Linux Build from Source 1. **Download** latest [ta-lib-0.8.1-src.tar.gz](https://github.com/ta-lib/ta-lib/releases/download/v0.8.1/ta-lib-0.8.1-src.tar.gz) (or, alternatively, clone down and checkout the main branch) 2. **Extract the Tarball** if you downloaded the source manually: ```bash tar -xzf ta-lib-0.8.1-src.tar.gz cd ta-lib-0.8.1 ``` 3. **Build and Install**: ```bash ./configure make sudo make install sudo ldconfig # refresh the shared-library cache so the linker finds libta-lib.so ``` If you cloned the repository instead of downloading the tarball, the `configure` script is not included; generate it first with `./autogen.sh` (requires the `autoconf`, `automake` and `libtool` packages). Follow the same procedure for an update (the older version is overwritten, no need to uninstall). If you choose to uninstall do: ```bash sudo make uninstall ``` ## vcpkg TA-Lib is available as the [`talib`](https://vcpkg.io/en/package/talib) port in [vcpkg](https://vcpkg.io/), Microsoft's cross-platform C/C++ package manager (Windows, Linux and macOS). Classic mode: ```bash vcpkg install talib ``` Manifest mode (add it to your project's `vcpkg.json`): ```bash vcpkg add port talib ``` See the [vcpkg documentation](https://learn.microsoft.com/en-us/vcpkg/get_started/get-started) for one-time setup and CMake/MSBuild integration. ## Use it from CMake An install done with CMake provides a package config, so a consumer needs only: ```cmake find_package(ta-lib CONFIG REQUIRED) target_link_libraries(myapp PRIVATE ta-lib::ta-lib) ``` `ta-lib::ta-lib` is the portable name. It is the shared library when one was built and the static library otherwise, so the same two lines work against any install. Where both linkages were installed, `ta-lib::ta-lib-static` picks the static one explicitly. Linking the target is all that is needed. Both `#include ` and `#include ` resolve, and a static link pulls in the math library. An install done with autotools (`./configure && make install`, which is what Homebrew uses) provides `ta-lib.pc` for pkg-config instead. ## GitHub Actions To install the TA-Lib C library in a CI pipeline, use the [setup-ta-lib](https://github.com/TA-Lib/setup-ta-lib) action. It runs on Linux, macOS and Windows runners. ```yaml - uses: TA-Lib/setup-ta-lib@v1 ``` The latest release is installed by default. To pin a specific version: ```yaml - uses: TA-Lib/setup-ta-lib@v1 with: version: "0.8.1" ``` This is handy as a step before installing a wrapper that depends on the C library, such as the Python `ta-lib` package. --- --- url: 'https://ta-lib.org/wrappers/index.md' description: >- Community-maintained TA-Lib wrappers for Python, R, Go, Ruby, PHP, Zig, pandas and PostgreSQL, with a link to each project's GitHub repository. --- # Wrappers TA-Lib reaches a wider ecosystem through these community-maintained wrappers: | Language | Github Repos | | --- | --- | | Go | [ta-lib-cgo](https://github.com/TA-Lib/ta-lib-cgo) | | pandas | [pandas-ta-classic](https://github.com/xgboosted/pandas-ta-classic) | | PHP | [ext-ta-lib](https://github.com/TA-Lib/ext-ta-lib) | | PostgreSQL | [ta_pg](https://github.com/TA-Lib/ta_pg) | | Python | [ta-lib-python](https://github.com/ta-lib/ta-lib-python) | | R | [ta-lib-R](https://github.com/serkor1/ta-lib-R) | | Ruby | [ta-lib-ruby](https://github.com/TA-Lib/ta-lib-ruby) | | Zig | [ta-lib-zig](https://github.com/TA-Lib/ta-lib-zig) |