Issue 13/2001 (No. 21)
AmiBroker Tips newsletter.
Issue 13/2001. No 21.
1 November 2001.
Copyright (C)2001 Tomasz Janeczko.
All back issues available from:
http://www.amibroker.com/newsletter/
IN THIS ISSUE
1 Welcome
2 AFL Library: Component Object Model support in AFL
1 Welcome

Welcome to the 13th issue of AmiBroker Tips newsletter in the 2001. Recently I was quite busy and this is main reason why you had to wait for this issue so long. In the meantime the version 3.70 was launched (if you haven't yet upgraded to it, please check downloads section at http://www.amibroker.com/download.html) and 3.80 is right round the corner.

As version 3.80 brings several exiting new features including syntax highlighting AFL editor, ability to write your own plug-in DLLs and COM support in AFL, this issue of the newsletter will try to focus on the latter ones. In order to test-run this new features you are welcomed to download the latest beta version 3.79 from here: http://www.amibroker.com/bin/ab379beta.exe. Make sure to take a look at installation instructions included in the archive before installing the beta.

Just a reminder: if you have any comments/suggestions or article ideas, please don't hesitate to drop a line to newsletter@amibroker.com

2 AFL Library: Component Object Model support in AFL

Note: Examples provided in this article require AmiBroker 3.75 beta or higher

2.1 Introduction

The Component Object Model (COM) is the technology that defines and implements mechanisms that enable software components, such as applications, data objects, controls, and services, to interact as objects. The COM support in AFL introduced in version 3.75beta allows to create instances of COM objects and call the functions (methods) exposed by those objects.

The COM object can be created in virtually any language including any C/C++ flavour, Visual Basic, Delphi, etc. This enables you to write parts of your indicators, systems, explorations and commentaries in the language of your choice and run them at full compiled code speed.

The scripting engines used by AFL scripting host (JScript and VBScript) also expose themselves as COM objects. AFL COM support now allows you to call functions defined in scripting part directly from AFL without the use of variables to pass the data to and retrieve data from the script.

2.2 Calling functions defined in script

Until version 3.75 the only way to exchange information between AFL and the script was using variables - this technique is explained in detail in AFL scripting host documentation .

Let's suppose we need a function that calculates second order IIR (infinite impulse response) filter:

y[ n ] = f0 * x[ n ] + f1 * y[ n - 1 ] + f2 * y[ n - 2 ]

Please note that well known exponential smoothing is a first order IIR filter. Implementing higher order filters minimizes lag, therefore our second order IIR may be used as a "better" EMA.

In the "old way" we would need to write the following code:

EnableScript("jscript");

x = ( High + Low )/2;

f0 = 0.2;
f1 = 1.2;
f2 = -0.4;

<%
x = VBArray( AFL( "x" ) ).toArray();
f0 = AFL( "f0" );
f1 = AFL( "f1" );
f2 = AFL( "f2" );

y = new Array();

// initialize first 2 elements of result array
y[ 0 ] = x[ 0 ];
y[ 1 ] = x[ 1 ]

for( i = 2; i < x.length; i++ )
{
  y[ i ] = f0 * x[ i ] + f1 * y[ i - 1 ] + f2 * y[ i - 2 ];
}

AFL.Var("y") = y;
%>

Graph0 = Close;
Graph0Style = 64;
Graph1 = y;

While it is OK for one-time use, if we need such a function multiple times we had to have repeat the script part which is not very nice. Much nicer approach is to have a function that can be called from multiple places without the need to repeat the same code. Defining functions in JScript of VBScript is no problem at all:

EnableScript("jscript");

<%


function IIR2( x, f0, f1, f2 )
{

x = VBArray( x ).toArray();

y = new Array();

// initialize first 2 elements of result array
y[ 0 ] = x[ 0 ];
y[ 1 ] = x[ 1 ];

for( i = 2; i < x.length; i++ )
{
   y[ i ] = f0 * x[ i ] + f1 * y[ i - 1 ] + f2 * y[ i - 2 ];
}

return y;

}

%>

.. but how to call such a function from AFL?

The most important thing is that script engine exposes itself as a COM object. A new AFL function GetScriptObject() can be used to obtain the access to the script engine. The rest is simple - once we define the function in the script it is exposed as a method of script object retrieved by GetScriptObject:

script = GetScriptObject();
Graph0 = script.IIR2( ( High + Low )/2, 0.2, 1.2, -0.4 );
Graph1 = script.IIR2( ( Open + Close )/2, 0.2, 1.0, -0.2 ); // call it again and again...

Note also, that with this approach we may pass additional arguments so our IIR2 filter may be re-used with various smoothing parameters.

So, thanks to a new COM support in AFL, you can define functions in scripts and call those functions from multiple places in your formula with ease.

2.3 Using external COM/ActiveX objects in AFL

In a very similar way we can call functions (methods) in an external COM objects directly from the AFL formula. Here I will show how to write such external ActiveX in Visual Basic but you can use any other language for this (Delphi for example is very good choice for creating ActiveX/COM objects).

It is quite easy to create your own ActiveX DLL in Visual Basic, here are the steps required:

  • Run Visual Basic
  • In the "New project" dialog choose "ActiveX DLL" icon - this will create the "Project1" that looks like in the picture on the right:
  • Now click on the (Name) and rename the "Project1" to something more meaningfull, for example "MyAFLObject"
  • Then double click on the "Class1" in the project tree item. The code window will get the title of "MyAFLObject - Class1 (Code)" as shown below:
  • Now you are ready to enter the code

As an example we will implement a similar function to one shown in the JScript. The function will calculate second order Infinite Impulse Response filter. We will call this function "IIR2"

Public Function IIR2(InputArray() As Variant, f0 As Variant, f1 As Variant, f2 As Variant) As Variant

Dim Result()

ReDim Result(UBound(InputArray)) ' size the Result array to match InputArray

'initialize first two elements

Result(0) = InputArray(0)
Result(1) = InputArray(1)

For i = 2 To UBound(InputArray)

  Result(i) = f0 * InputArray(i) + f1 * Result(i - 1) + f2 * Result(i - 2)

Next

IIR2 = Result

End Function

The code is quite similar to the JScript version. The main difference is declaring types. As you can see all variables passed from and to AFL must be declared as Variants. This is so, because AmiBroker does not know what kind of object it speaks to and puts all arguments to the most universal Variant type and expects the function to return the value as Variant also. Currently AmiBroker can pass to your object floating point numbers, arrays of floating point numbers, strings, and pointers to other objects (dispatch pointers) - all of them packed into Variant type. When you write the ActiveX, it is your responsibility to interpret Variants received from AmiBroker correctly.

Now you should choose Run->Start in Visual Basic to compile and run the component. The code in Visual Basic will wait until external process accesses the code.

To access the freshly created ActiveX we will use the following AFL formula (enter it in the Indicator Builder):


myobj = CreateObject("MyAFLObject.Class1");

Graph0 = Close;
Graph0Style = 64;
Graph1 = myobj.IIR2( Close, 0.2, 1.2, -0.4 );

The AFL formula simply creates the instance of our ActiveX object and calls its member function (IIR2). Note that we are using new dot (.) operator to access myobj members.
Now click the "Apply" button in the Indicator Builder to see how all this setup works. You should see candlestick chart with a quite nice moving average.

2.4 Conclusion

Introduction of COM support in AFL brings even more power to AFL and AmiBroker. Now you can write indicators, trading systems, explorations and commentaries using custom functions that are easy to create using scripting language or full-featured development environment of Visual Basic, Borland Delphi, C++ Builder, Visual C++ and many, many others. Using integrated development environments like those mentioned makes debugging, testing and developing much easier and faster. Also resulting compiled code executes several times faster than interpreted script or AFL.

But this is not the end of the story... C/C++ programmers can choose to write plugin DLLs that do not use COM technology at all. Plugin DLLs has some additional features including ability to call back AFL built-in functions, directly retreive and set AFL variables and support automatic syntax colouring of functions exposed by the plugin. This topic is large enough for a separate newsletter so stay tuned till the next time.

.... and that's all for this week - hope you enjoyed reading


AmiBroker Tips newsletter. Issue 13/2001. Copyright (C)2001 Tomasz Janeczko. All back issues available from: http://www.amibroker.com/newsletter/