Technical analysis with FreePascal and TA-lib

As the home page explains, TA-Lib is a C++ library widely used by trading software developers requiring to perform technical analysis of financial market data. It Includes 200 indicators such as ADX, MACD, RSI, Stochastic, Bollinger Bands, and Candlestick pattern recognition.

The library was written in C++, but its developers made a very intelligent decision by creating a C wrapper, to allow other languages interact with it. Here I'll show an example of how you can calculate Bollinger Bands using this library and FreePascal.

Let's download and uncompress the library.

cd ~/
wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
tar xvfz ta-lib-0.4.0-src.tar.gz


This will create a ta-lib directory in our home. For example in /home/leonardo/ta-lib.

Now, we need to create a shared library from its sources.

cd ~/ta-lib
./configure
make


That's all, the files "src/libta_lib.la" and "src/.libs/libta_lib.so" were created.

Now, let's create a new directory for our FreePascal program.

mkdir ~/fpc-talib
cd ~/fpc-talib


...and copy libta_lib.so to that new directory.

cp ~/ta-lib/src/.libs/libta_lib.so ~/fpc-talib
cd ~/fpc-talib


Before creating our first FPC/ta_lib program, I recommend reading the TA-Lib API Documentation, and also taking a look at the functions from the "src/ta_func" directory.

Now, let's take a look at the function TA_BBANDS. It allows us to calculate the Bollinger Bands for a serie of closing prices.


TA_RetCode TA_BBANDS( int startIdx,
int endIdx,
const double inReal[],
int optInTimePeriod,
double optInNbDevUp,
double optInNbDevDn,
TA_MAType optInMAType,
int *outBegIdx,
int *outNBElement,
double outRealUpperBand[],
double outRealMiddleBand[],
double outRealLowerBand[] )


The function's input is an array of double, containing for example the closing prices of XYZ stock for the last year. And its outputs are three arrays of double, of the same length as the input, containing the points that define the upper, middle and lower Bollinger bands.

To be able to work with this function, we must create a Pascal version of its interface:


TTA_BBANDS = function(
startIdx, endIdx: Integer;
const inReal: Array of Double;
optInTimePeriod: Integer;
optInNbDevUp, optInNbDevDn: Double;
optInMAType: TTA_MAType;
out outBegIdx: Integer;
out outNBElement: Integer;
outRealUpperBand: Array of Double;
outRealMiddleBand: Array of Double;
outRealLowerBand: Array of Double
): Integer; cdecl;


Well, I must admit it took me a whole afternoon to figure out that the function needed those "out" params, but after that, everything was pretty smooth.

Show me a complete example!


unit formulas;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils,
DynLibs;

type
TTA_MAType = (TA_MAType_SMA, TA_MAType_EMA, TA_MAType_WMA, TA_MAType_DEMA,
TA_MAType_TEMA, TA_MAType_TRIMA, TA_MAType_KAMA, TA_MAType_MAMA, TA_MAType_T3);

TTA_BBANDS = function(
startIdx, endIdx: Integer;
const inReal: Array of Double;
optInTimePeriod: Integer;
optInNbDevUp, optInNbDevDn: Double;
optInMAType: TTA_MAType;
out outBegIdx: Integer;
out outNBElement: Integer;
outRealUpperBand: Array of Double;
outRealMiddleBand: Array of Double;
outRealLowerBand: Array of Double
): Integer; cdecl;


implementation

var
lHandle: TLibHandle;
lBBands: TTA_BBANDS;
lInReal: Array of double;
lOutBegIdx: Integer;
lOutNBElement: Integer;
lOutRealUpper: Array of double;
lOutRealMiddle: Array of double;
lOutRealLower: Array of double;
lRes: Integer;
I: Integer;
lLowerVol: Double;
lSqueeze: Integer;

begin
lHandle := LoadLibrary('/home/leonardo/fpc-talib/libta_lib.so');
if lHandle <> 0 then
begin
Pointer(lBBands) := GetProcAddress(lHandle, 'TA_BBANDS');
if @lBBands <> nil then
begin
(* lInReal is the array of Closing prices containing
the last 100 days for XYZ stock *)
SetLength(lInReal, 100);
lInReal[0] := 10.50;
lInReal[1] := 10.75;
lInReal[2] := 11.25;
//..
//.. and so on to the 99nth element.
//..
lInReal[99] := 8.35;

SetLength(lOutRealUpper, Length(lInReal)); // the same length as lInReal
SetLength(lOutRealMiddle, Length(lInReal));// the same length as lInReal
SetLength(lOutRealLower, Length(lInReal));// the same length as lInReal

lRes := lBBands(
0, AQuotes.Count - 1, lInReal, APeriods, 2, 2, TA_MAType_SMA,
lOutBegIdx, lOutNBElement, lOutRealUpper, lOutRealMiddle, lOutRealLower);

lLowerVol := 0;
for I := 0 to Length(lInReal) - 1 do
begin
writeln(
Format('Close %f - Upper BBand %f - Middle BBand %f - Lower BBand %f',
[lInReal[I], lOutRealUpper[I], lOutRealMiddle[I], lOutRealLower[I]])
);
end;
end;
UnloadLibrary(lHandle);
end;
end;

end.

And that's it.

Following the same approach, I created a home-made trading system based on Bollinger Bands and Option Straddles that is performing pretty well!. I'm very seriously thinking of creating an investment fund, what about "The FreePascal Investment Fund" ? :). See you in my next post.