AFL Scripting Host

IMPORTANT NOTE: Since the introduction of native looping and flow control statements like if-else and while in version 4.40 the significance of scripting has been greatly reduced. Currently most of the tasks requiring scripting in previous versions could be handled in native AFL. What's more AFL loops are 3-6 times faster than JScript/VBScript.

Basics

AFL scripting host is an interface between AFL engine and JScript/VBScript engines (aka. Active Scripting technologies) available as a part of Internet Tools & Technologies platform provided by Microsoft.
It allows you to build the formulas that are have parts in AFL code and parts in JScript/VBScript.

Requirements

Microsoft JScript/VBScript engines come installed with Windows.

JScript/VBScript documentation can be found on official scripting page at:
http://msdn.microsoft.com/scripting/

Enabling AFL Scripting Host

If you want to use scripts within your formulas you have to call EnableScript() function
in the beginning of your formula. The function takes one input parameter - engine name:

EnableScript("jscript");

or

EnableScript("vbscript");

From then on, you will be able to embody parts written in scripting language in your formulas. The begin and the end of the script must be marked with <% and %> sequences, as shown in the example below:

EnableScript("vbscript");

// "normal" AFL statements
buy = cross( macd(), 0 );
sell = cross( 0, macd() );

<%
..... your script code here.....
%>

// "normal" AFL statements
buy = ExRem( buy, sell );

Using variables

Currently the only way to exchange the information between "normal" AFL part and script part is to use variables. AFL scripting host exposes one object (predefined, no creation/initialization needed)
called AFL.

The AFL object has one (default) parametrized property called Var( varname ) that can be used to access AFL variables from the script side:

// example in VBScript
       <%
buyarrayfromscript = AFL.Var("buy") 
       ' get the buy array from AFL to the script-defined variable
AFL.Var("buy") = buyarrayfromscript 
       ' set the buy array in AFL from the script-defined variable
%>


Since Var is default property you can omit its name and write simply AFL( varname ) as shown in the example below:

<%
buyarrayfromscript = AFL("buy") 
       ' gets the buy array from AFL to the script-defined variable
AFL("buy") = buyarrayfromscript 
       ' sets the buy array in AFL from the script-defined variable
%>

In AFL there are three data types possible: array (of floating point numbers), a number (floating point) and a string. The VBScript and JScript engines use variant data type that can hold any type of the variable including three used by AFL. As in AFL, you don't declare variables in scripting languages, the type is determined by the first assignment. In case of VBScript you can get/set AFL variables of any supported type using syntax shown above. But in JScript, due to the fundamental difference in handling arrays in JScript (array elements in JScript are implemented as dynamic properites of an array object) you need to use the following code to get the value of AFL array into JScript array:

// example in JScript
<%
function GetArray( name )
{
   return VBArray( AFL( name ) ).toArray();
}
myJScriptArray = GetArray( "close" );
%>

The GetArray() function shown above makes it easy to convert automation-type safe array into JScript array. This example shows also how to define and use functions in JScript;

Assigning AFL variables from script-side arrays is much more simple, AFL scripting host detects JScript arrays and can get their contents directly:

// example in JScript
<%
   AFL("buy") = myJScriptBuyArray;
%>

All other data types are handled the same in JScript and VBScript

// example in VBScript
ticker = name();
<%
  tickerstring = AFL("ticker")
  AFL("ticker") = "new name"
%>

or in JScript:

// example in JScript
ticker = name();
<%
   tickerstring = AFL("ticker");
   AFL("ticker") = "new name";
%>

Iterating through arrays

One of the most basic task that everyone would probably do is to iterate through array. In VBScript this can be done using For..To..Next statement, in JScript using for(;;) statement. Both these constructs need to know array size or number of elements in the array. In VBScript you should use UBound( arrary) function to get the upper bound of the array, in JScript you just use length property of the array. The following examples show this. (Please remember that in both VBScript and JScript arrays are zero-based.)

// example in VBScript
<%
myArray = AFL("close")
sum = 0
for i = 0 to UBound( myArray )
sum = sum + myArray( i )
next
%>

or in JScript:

// example in JScript
<%
function GetArray( name )
{
   return VBArray( AFL( name ) ).toArray();
}
myArray = GetArray( "close" );
sum = 0;
for( i = 0; i < myArray.length; i++ )
{
       sum += myArray[ i ];
}
%>

Examples

a) Indicator example - Exponential moving average:

EnableScript("jscript");
<%

close = VBArray( AFL( "close" ) ).toArray();
output = new Array();
// initialize first element
output[ 0 ] = close[ 0 ];
// perform the loop that calculates exponential moving average
factor = 0.05;

for( i = 1; i < close.length; i++ )
{
  output[ i ] = factor * close[ i ] + (1 - factor) * output[ i - 1 ];
}

AFL.Var("graph0") = close;
AFL.Var("graph1") = output;
%>
WriteVal( graph1 );
 

b) Profit-target stop example

Here comes the example of the formula that realizes profit-target stop at the fixed 10% percentage from the buy price. Note that buy condition is met when the price reaches a new high, so it happens multiple times after initial buy. Therefore ValueWhen( buy, close ) can not give you initial buy price and that kind of trading rule could not be implemented in AFL itself. But, with scripting there is no problem...

EnableScript("VBScript");
hh = HHV( close, 250 );
// buy when prices reaches a new high
buy = Close == HHV( close, 250 ); 

// ensure that sell is an array, 
// sell = 0 would set the type to number
sell = buy; <% close = AFL("close") buy = AFL( "buy" ) sell = AFL("sell")
 	' this variable holds last buying price
    ' if it is zero it means that no trade is open
    lastbuyprice = 0
 	' iterate along the array
    for i = 0 to UBound( close )
       sell( i ) = 0
       ' Remove Buy signals if trade was already initiated
       if( lastbuyprice > 0 ) then
       	  buy( i ) = 0
       end if
       ' if there is no open trade and buy signal occurs 
	   ' get the buying price
       if ( lastbuyprice = 0 ) AND (buy( i ) = 1) then
          lastbuyprice = close( i )
       end if
       ' if trade is open and sell condition is valid 
       ' generate sell signal
       ' and close the trade
       if (lastbuyprice >0 ) AND ( close( i ) > ( 1.1 * lastbuyprice ) ) then
       	  sell( i ) = 1
          lastbuyprice = 0
       end if
    next
    AFL("buy") = buy
    AFL("sell") = sell
%>
buy = buy;

Further information

More scripting samples are available at the AFL on-line library at: http://www.amibroker.com/library/list.php

In case of any further questions, comments and suggestions please use customer support page at http://www.amibroker.com/support.html . Please note that AFL scripting is fairly advanced topic and you should play a little bit with AFL first before going too deep into scripting.