Versions and Determinism
Part of TA-Lib's specification, a reference for AI-agent-driven integration.
The rules for when the same call gives the same bits, and for what a release keeps and may add. On one machine, a result validated in one language holds bit for bit in the others, except for a transcendental call (rD1).
The caller must
Compare with a tolerance any call across machines, and a transcendental call across languages or between a stream and a batch call.
When you build C from source, keep the project's floating-point flags. rD1 holds for C only when the compiler evaluates every
doubleoperation as written:Condition GCC and Clang Build files in the source tree no contraction of a*b+cinto a fused multiply-add-ffp-contract=offCMake 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-mathor-Ofast, nor any part of them but-fno-math-errnonone uses them no extended-precision intermediates on 32-bit x86, -msse2 -mfpmath=sseonly CMake's i386 cross-build toolchain, cmake/toolchain-linux-i386.cmake; add it yourself to a native 32-bit x86 buildrD1 is not promised for C built with MSVC or clang-cl.
Enumerate, never hard-code a list. A release may add what rV3 lists. Enumerate functions through the Abstract API, check a raw MA-type integer (rP2), give every
switchormatchover a TA-Lib enum a default branch, and ignore an unknown metadata flag.Validate against the release you ship. No rule covers output values from one release to the next, nor API compatibility of the Rust, Java, C# and TypeScript packages between releases beyond rV2 and rV3. Which versions and packages exist: Install.
Determinism
In this spec, bit-identical means the same return code, the same output range, and every output element with the same bits, a NaN matching any NaN. The same call means the same function, input values, startIdx and endIdx, optional parameters and settings.
rD1 On one machine, the same call gives bit-identical results in C, Rust, Java, C# and TypeScript. The exception is a call that evaluates a transcendental function.
rD2 Where rD1 or rH1 lets two results differ, TA-Lib targets a difference below 1e-9, and 1e-11 between TypeScript and C: absolute for a value below 1 in magnitude, relative above it. CI verifies it across a wide range of series. It is not a promise for every input: a degenerate one, such as a flat series, can exceed it.
rD3 A difference caused by the unstable period falls outside rD2's target: values a function computes for the same bar from different starts can differ by far more than 1e-9. Handling the unstable period is the caller's choice and responsibility, and TA-Lib provides a solution: numerical Auto-Stabilization, whose counts and limits are specified.
Transcendental functions
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, TypeScript from the JavaScript engine's Math object, and none of them is required to round it correctly. TypeScript's result can also change with the engine and its version. A platform can also provide two routines for one function, one for a single value and one for several values at a time, and the two need not round alike: where a batch call takes the vectorized routine (the run-time key vmath.transcendental tells whether one is in use), its result can differ from a stream's, which evaluates one value at a time, and from another language's. A call evaluates one when its function does, or when an MA-type parameter selects an average that does. The functions that do carry the metadata flag TA_FUNC_FLG_USES_TRANSCENDENTAL, and the averages that do are MAMA and ALMA. A transcendental call's difference starts in the last bits of one math-library result and can grow through the function's arithmetic; the HT_* outputs that round a computed period to whole bars can differ outright on some inputs. HT_DCPHASE and HT_SINE have no bound on an input that stays flat for a whole dominant cycle: their phase then comes from cancellation noise, so a one-bit difference in a sine or cosine can move it by hundreds of degrees, in every language.
Across machines
No rule promises the same bits on two machines: a different CPU, compiler or math library can change a value, and a release may compute a function differently on one CPU family than on another. TA-Lib targets the same 1e-9 there (rD2).
Each release is checked on every supported platform against the regression suite's reference values, some compared exactly and some within a tolerance.
Equivalent calls
| Compared | Rule |
|---|---|
| a stream and the batch call over the same bars | rH1 |
OpenAndFill and the batch call over its history | rH3 |
Peek and the next Update with the same bar | rH4 |
a Clone and its original | rH8 |
| a default sentinel and the explicit default | rP3 |
| an output in place on its input, and in a separate buffer | rW6 |
a float input, and the double call on its widened values | rP4 |
Releases
rV1 Within one ABI generation N (the N of libta-lib.so.N; the table below shows it per 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 the counts that grow with their enums (rV3). Deprecated names are included. An addition starts no new N. TA_LIB_SOURCES_DIGEST is outside rV1: it changes whenever the sources do.
| 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 |
rV2 No member of RetCode, MAType, FuncUnstId, RangeType or CandleSettingType is renumbered, in any language. TA_AllCandleSettings is pinned at 11 and TA_FUNC_UNST_ALL at 65535; neither tracks the number of members. A Rust, Java, C# or TypeScript enum may omit C members; each member it has carries C's number. Reading the number: for RetCode, see the hub; for the other enums, Rust as i32, Java value() on FuncUnstId and ordinal() on MAType, RangeType and CandleSettingType, valid while the enum lists every member in order; C# an (int) cast; in TypeScript the member is the number.
rV3 A release may add functions, MA types, unstable-period ids, candle settings, return codes, metadata flags and run-time information keys. TA_MATYPE_MAX and TA_FUNC_UNST_COUNT grow when a member is appended to their enum. Rust marks RetCode, FuncUnstId, MAType, RangeType and CandleSettingType #[non_exhaustive].