Abstract API
TL;DR: Every function describes itself at run time and can be called by name. Use it when the function or its parameters are not fixed in your code.
When to use it
- Generating wrappers or glue code for another language.
- Picking up new functions after a TA-Lib upgrade with no code change.
- Building a charting app: the indicator menu and each settings dialog come from the metadata.
- Searching over functions and parameters (optimizers, strategy search).
If you only need a handful of specific functions, calling them directly is simpler.
Describe a function
Look a function up by name, or enumerate them all. Each one reports its group, its inputs, its optional parameters (type, range, default) and its outputs, with flags, plus a JSON string of attributes no flag can carry, such as RSI's 30/70 reference levels. The specification lists every flag and attribute.
#include <ta_abstract.h>
const TA_FuncHandle *handle;
const TA_FuncInfo *info;
const TA_OptInputParameterInfo *opt;
const char *json;
TA_GetFuncHandle( "SMA", &handle );
TA_GetFuncInfo( handle, &info ); /* name, group, hint, flags, nbInput, nbOptInput, nbOutput */
TA_GetOptInputParameterInfo( handle, 0, &opt ); /* displayName, type, dataSet (range), defaultValue */
TA_GetFuncAttributes( handle, &json ); /* "{}"; RSI: {"outputs":{"outReal":{"levels":[30,70]}}} */
/* Every function: TA_ForEachFunc( callback, opaqueData ); */use ta_lib::abstract_api::{for_each_func, get_func_handle};
let id = get_func_handle("SMA").expect("unknown function");
let info = id.info(); // name, group, hint, flags, inputs, opt_inputs, outputs, attributes
for_each_func(|f| println!("{} ({:?})", f.name, f.group));import io.github.talib.metadata.FuncInfo;
import io.github.talib.metadata.Functions;
FuncInfo f = Functions.byName("SMA"); // name(), group(), hint(), flags(), inputs(), optInputs(), outputs(), attributes()
Functions.all().forEach(fi -> System.out.println(fi.name() + " (" + fi.group() + ")"));using TALib;
using TALib.Metadata;
FuncInfo f = Core.Functions["SMA"]; // Name, Group, Hint, Flags, Inputs, OptInputs, Outputs, Attributes
foreach (var fi in Core.Functions)
{
Console.WriteLine($"{fi.Name} ({fi.Group})");
}import { Functions } from 'ta-lib/metadata';
const f = Functions.byName('SMA'); // name, group, hint, flags, inputs, optInputs, outputs, attributes
for (const fi of Functions.all()) {
console.log(`${fi.name} (${fi.group})`);
}The name lookup ignores case. Core.Functions in C# is an alias for FunctionCatalog.Default.
Call a function
Bind the inputs, the optional parameters and the outputs to a parameter holder, then call it. A parameter left unset takes its default.
TA_ParamHolder *params;
int outBeg, outNbElement;
TA_ParamHolderAlloc( handle, ¶ms );
TA_SetInputParamRealPtr( params, 0, close );
TA_SetOptInputParamInteger( params, 0, 30 );
TA_SetOutputParamRealPtr( params, 0, out );
TA_CallFunc( params, 0, size - 1, &outBeg, &outNbElement );
TA_ParamHolderFree( params );let core = Core::new();
let mut out = vec![0.0; close.len()];
let mut call = get_func_handle("SMA").expect("unknown function").new_call(&core);
call.set_input(0, &close)?;
call.set_opt_input(0, 30)?;
call.set_output(0, &mut out)?;
let range = call.call(0, close.len() - 1)?;OutRange r = Functions.byName("SMA").newCall()
.setInput(0, close)
.setOptInput(0, 30)
.setOutput(0, out)
.call(0, close.length - 1);OutRange r = Core.Functions["SMA"].CreateCall()
.SetInput(0, close)
.SetOptInput(0, 30)
.SetOutput(0, outReal)
.Call(0, close.Length - 1);const r = Functions.byName('SMA')!.newCall()
.setInput(0, close)
.setOptInput('timePeriod', 30) // a parameter by its options key, or by position: 0
.setOutput(0, out)
.call(); // the whole series, as the typed call's defaultsThe call behaves like the typed one: same values, same range, same rejections. In TypeScript every row also carries the typed call's key (timePeriod, prices, outUpperBand), and an optional parameter binds by that key or by position. A parameter holder is not thread-safe: confine one to one thread, or build one per call. The exact rules: Abstract API and Metadata.
Lookback and display shift
The holder answers both from the optional parameters alone, so neither needs the inputs or outputs bound. The lookback sizes the outputs; the display shift tells a chart where to draw one output.
int lookback, shift;
TA_GetFuncHandle( "DPO", &handle );
TA_ParamHolderAlloc( handle, ¶ms );
TA_SetOptInputParamInteger( params, 0, 20 );
TA_GetLookback( params, &lookback );
TA_GetDisplayShift( params, 0, &shift ); /* output 0: -11 */
TA_ParamHolderFree( params );let core = Core::new();
let mut call = get_func_handle("DPO").expect("unknown function").new_call(&core);
call.set_opt_input(0, 20)?;
let lookback = call.lookback()?;
let shift = call.display_shift(0)?; // output 0: -11ParamHolder call = Functions.byName("DPO").newCall().setOptInput(0, 20);
int lookback = call.lookback();
int shift = call.displayShift(0); // output 0: -11ParamHolder call = Core.Functions["DPO"].CreateCall().SetOptInput(0, 20);
int lookback = call.Lookback();
int shift = call.DisplayShift(0); // output 0: -11const call = Functions.byName('DPO')!.newCall().setOptInput(0, 20);
const lookback = call.lookback();
const shift = call.displayShift(0); // output 0: -11A function with at least one shifted output carries the display-shift flag, and so does each such output, so a generic client can skip the query for every other function. The exact rules: Lookback and Shift.