Usage Index
Introduction
Tulip Indicators is a set of technical analysis indicator functions implemented in ANSI C. It has no external dependencies. Tulip Indicators currently implements 104 indicators. The complete list is here.
A primary goal in implementing Tulip Indicators was to create an easy-to-use interface. To this end, every Tulip Indicators function has exactly the same interface. Therefore, if you learn how to use one indicator, you know how to use them all.
Features
- ANSI C. No dependencies. Easy to compile.
- Bindings available for many programming languages.
- Implements over 100 indicators.
- Fast and efficient algorithms.
- Thoroughly tested.
- Free software. (LGPL)
Building
Tulip Indicators requires a good C compiler, and has no other external dependencies.
Tulip Indicators is easiest to build from the command line. On most platforms,
you'll just need to type make
. This will build Tulip Indicators as
static library and run the unit tests.
git clone https://github.com/TulipCharts/tulipindicators
cd tulipindicators
make
To use Tulip Indicators in your project, you'll need only the header file
indicators.h
and the static library, libindicators.a
.
If you are having trouble with make, you can build manually by compiling every
.c
file in the indicators
and utils
sub-directories along with
indicators_index.c
in the main directory. The other .c
files in the main
directory are utilities used for testing or other purposes.
If you're still having trouble, contact us. It's important to me that everyone can easily build and use Tulip Indicators.
Indicator Interface
int ti_XXX_start(TI_REAL const *options);
int ti_XXX(int size,
TI_REAL const *const *inputs,
TI_REAL const *options,
TI_REAL *const *outputs);
Each of the 104 indicators provided by Tulip Indicators implements the
above two functions (where XXX
is the indicator name).
The first function is the start
function. Call the start
function with a
given set of option parameters, and it will tell you how much shorter the
calculated output array(s) will be than the input array(s) length.
The second function does the actual calculation. Pass in the input array length, an array of input data, an array of options, and an array output data. The array of output data will be overwritten with the calculated output.
Inputs, options, and outputs are always passed as arrays. This is so that every Tulip Indicators function has exactly the same interface, regardless of how many inputs, options, or outputs it actually requires.
Tulip Indicators expects the oldest data in the time series to be in index 0. Order your data from oldest to most recent.
A first example
As an example, we'll look at calculating a Simple Moving Average on an example dataset. The Simple Moving Average function expects one input, one option, and provides one output. We'll setup those arguments before calling it.
Our example data set will be defined as:
/* Order data from oldest to newest (index 0 is oldest) */
const double data_in[] = {5,8,12,11,9,8,7,10,11,13};
const int input_length = sizeof(data_in) / sizeof(double); /* 10 in this example */
The first thing we need to figure out, is which options we are going to give to
the indicator function. The Simple Moving Average function takes one option, which is the
moving average period. In this example we'll use a period of 3
. The Tulip
Indicators function will expect all the options to be in an array. This may
seem silly for passing in one option, but it allows a consistency with the
functions that take multiple options.
We put our option, the period 3
, into an array:
const double options[] = {3};
We can now calculate exactly how big our expected output is. Each Tulip
Indicators function has a corresponding start
function which takes a set of
options and tells us how much smaller the output array will be than the input
array. In this case, we call the start
function for Simple Moving Average as follows:
/* Find start size for given options. */
const int start = ti_sma_start(options);
/* Output length is input length minus start size. */
const int output_length = input_length - start;
In this example, the start amount will be 2
. This means that although we are
passing in 10
input bars, we will only get 8
output bars (that is 10
minus 2
). This is because the Simple Moving Average is not valid for the first 2
bars
(given our option of 3
being the period).
We can now allocate memory for the output:
double *data_out = malloc(output_length * sizeof(double));
assert(data_out != 0);
There is one last step before doing the Simple Moving Average calculation. We must put all of our inputs and outputs into arrays. Again, this is because Tulip Indicators uses a consistent interface for all of the indicator functions. Many indicators take either multiple inputs or generate multiple outputs.
const double *all_inputs[] = {data_in};
double *all_outputs[] = {data_out};
And finally we are ready to do the actual Simple Moving Average calculation.
int error = ti_sma(input_length, all_inputs, options, all_outputs);
assert(error == TI_OKAY);
Take a look at example1.c
to see it altogether.
Generic Interface
One of the best features of Tulip Indicators is that you can enumerate all the indicator functions at runtime. This means you can easily add all of the Tulip Indicator functions to your program with only a few lines of code. This is also the recommended method for using Tulip Indicators.
Tulip Indicators defines the following structure in indicators.h
:
typedef struct ti_indicator_info {
char *name;
char *full_name;
ti_indicator_start_function start;
ti_indicator_function indicator;
int type, inputs, options, outputs;
char *input_names[TI_MAXINDPARAMS];
char *option_names[TI_MAXINDPARAMS];
char *output_names[TI_MAXINDPARAMS];
} ti_indicator_info;
If you know the name of an indicator you're looking for, you can get its info
by calling ti_find_indicator()
.
/*Searches for an indicator by name. Returns 0 if not found.*/
const ti_indicator_info *ti_find_indicator(const char *name);
For example, you can find the Simple Moving Average function at runtime with:
ti_indicator_info *info = ti_find_indicator("sma");
if (info) {
printf("Found indicator %s.\n It takes %d inputs, %d options, and provides %d outputs\n",
info->full_name, info->inputs, info->options, info->outputs);
/* TODO use the indicator (e.g. info->start(...), info->indicator(...)) */
} else {
printf("Erorr, not found\n");
}
You can also quickly loop through all available functions with the
ti_indicators
array.
/* Set info to first indicators in array. */
const ti_indicator_info *info = ti_indicators;
/* The last item is all zeros, so loop until then. */
while (info->name != 0) {
/* TODO use the info structure to do something.
e.g. printf("Found %s\n", info->name); */
++info; /* Next indicator. */
}
Regardless of how you get the ti_indicator_info
structure for a function, the usage is the same:
/* Assuming 'info' is a pointer to a ti_indicator_info structure. */
/* Get the name (e.g. "sma") and full name (e.g. "Simple Moving Average"). */
printf("Have indicator %s (%s)\n", info->name, info->full_name);
/* Get number of inputs, options, outputs. */
printf("This indicator has %d inputs, %d options, and calculates %d outputs.\n",
info->inputs, info->options, info->outputs);
/* The arrays:
info->input_names contains the names of each expected input
info->option_names contains the names of each expected option
info->output_names contains the names of each output
*/
/* TODO have inputs and options. e.g.
double *inputs[] = {a, b, c};
double options[] = {5, 7, 10};
double *outputs[] = {x, y, z};
*/
/* Find how much shorter the outputs are than the inputs. */
const int start = info->start(options);
/* TODO allocate output array as (size - start) for each output. */
/* Call the indicator to do the actual calculation. */
const int r = info->indicator(size, inputs, options, outputs);
if (r == TI_OKAY) {
/* It worked, the output arrays have been filled. */
} else {
/* Something went wrong. */
}
See example2.c
for an example of looping through each indicator. Also see
sample.c
as an example that will either loop through each indicator, or
search for one indicator by name and run it on some test data. The programs
smoke.c
and benchmark.c
also use the generic interface, but are a bit more
complicated.
If you have any questions or need help, don't hesitate to contact me.