AFL is a special programming language used to define and create custom indicators, scans, explorations, backtests and guru commentaries.
This chapter describes the different categories of wordlike units (tokens) recognized by the AFL language interpreter.
Whitespace is the collective name given to spaces (blanks), tabs, new line characters and comments. Whitespace can serve to indicate where tokens start and end, but beyond this function, any surplus whitespace is discarded.
Comments are pieces of text used to annotate a program. Comments are
for the programmer's use only; they are stripped from the source code before
parsing. The are two ways to delineate comments: Clike comments and C++ like
comments. A Clike comment is any sequence of characters placed after the symbol
pair /*. The comment terminates at the first occurrence of the pair */ following
the initial /*. The entire sequence, including the four commentdelimiter symbols,
is replaced by one space. A C++ like comments are singleline comments that
start by using two adjacent slashes (//) in any position within the line and
extend until the next new line.
AFL does not allow nested comments.
AFL recognizes five classes of tokens:
Identifiers are arbitrary names of any length given to functions and
variables. Identifiers can contain the letters (az, AZ), the underscore character
("_"), and the digits (09). The first character must be a letter.
AFL identifiers are NOT case sensitive.
Constants are tokens representing fixed numeric or character values.
Numeric constants consist of decimal integer and optionally: decimal point and
decimal fraction part. Negative numeric constants have unary minus () prefixed.
String constants, also known as string literals, form a special category
of constants used to handle fixed sequences of characters and are written as
a sequence of any number of characters surrounded by double quotes:
"This is literally a string"
The null (empty) string is written "". The characters inside the double quotes can include escape sequences ("\n"  a new line escape sequence).
A Constant expression is an expression that always evaluates to a constant. They are evaluated just as regular expressions are.
Punctuator (also known as separator) in AFL is one of the following
characters:
( ) , ; = .
Parentheses (open ( and close ) ) group expressions, isolate conditional
expressions and indicate function calls and function parameters:
d = c * ( a + b ) /* override normal precedence */
a= (b AND c) OR (d AND e) /* conditional expression */
func() /* function call no arguments */
The comma (,) separates the elements of a function argument list
The semicolon (;) is a statement terminator. Any legal AFL expression
followed by a semicolon is interpreted as a statement, known as expression statement.
The expression is evaluated and its value
is discarded (except Guru Commentaries where string values are written to output
window)
The dot (.) is a member access operator. It is used to call COM object methods. If myobj variable holds the object, using dot operator we can call the methods (functions) of myobj object:
myobj.Method();
The equal sign (=) separates variable declarations from initialization
lists:
x = 5;
It also indicates the default value for a parameter (see builtin function description):
macd( fast = 12; slow = 26 ) /* default values for fast and slow arguments)
Each formula in AFL contains of one or more expression statements. Each statement MUST be terminated by semicolon (;). In this way you are able to break long expressions into several physical lines (in order to gain clarity) and AmiBroker will still treat it like a single statement until terminating semicolon. Examples:
x = ( y + 3 ); /* x is assigned the value of y + 3 */
x = y = 0; /* Both x and y are initialized to 0 */
proc( arg1, arg2 ); /* Function call, return value discarded */
y = z = ( f( x ) + 3 ); /* A functioncall expression */
my_indicator = IIf( MACD() > 0,
Close  MA(Close,9),
MA( Close, 9 )  Close );
/* one statement in several lines */
Identifiers in AFL are used to identify variables and functions.
There are some predefined identifiers referencing builtin arrays and functions.
The most important are price array identifiers. They identify specific
price fields that the formula should operate on. The valid price array identifiers
are open, high, low, close,
volume, openint, average.
Price array identifiers can be abbreviated as shown in the following table.
Note that these are not casespecific.
Long name  Abbreviation  Comment 
Open  O  
High  H  
Low  L  
Close  C  
Volume  V  
OpenInt  OI  
Avg  <none available>  (High+Low+Close)/3  so called "typical price" 
Examples of the use of price array identifiers in formulas are shown below.
MA( Close, 10 ); IIf( H > Ref(H,1), MA(H,20), MA(C,20)
);
Comparision operators are divided into two types:
Symbol  Meaning 
<  Less than 
>  Greater than 
<=  Less than or equal to 
>=  Greater than or equal to 
==  Equal to 
!=  Not equal to 
These operators give true (1) or false (0) value as a result of comparison.
Symbol  Meaning 
=  Store the value of the second operand in the object specified by the first operand (“simple assignment”). 
The assignment operator assigns a value to a variable:
result = expression;
where result is variable identifier and expression is any numerical, array or text expression.
As the = operator behaves like other operators, expressions using it have
a value in addition to assigning that value into variable. This means that
you can chain assignment operators as follows:
j = k = l = 0;
j, k, and l equal zero after the example statement is executed.
Attention: please DO NOT confuse assignment operator (=) with equality check (==)
These are two different operators and you must not use assignment (=) to check for equality.
if( Name() = "MSFT" ) // WRONG !!!  variable assignment operator
used instead of equality check
{
}
if( Name() == "MSFT" ) // CORRECT  equality operator used properly
{
}
This is one of common coding mistakes listed here.
Formulas can contain the following mathematical operators:
Symbol  Meaning 
+  Addition 
  Subtraction (or negative value) 
*  Multiplication 
/  Division 
%  Modulus (or remainder) (AFL 1.7+) 
^  Exponentiation (raising to a power) 
  Bitwise "Or" (AFL 2.1+) 
&  Bitwise "And" (AFL 2.1+) 
The following formulas illustrate the use of operators in a formula:
var1 = ( H + L ) / 2;
var2 = MA(C,10)MA(C,20) / (H + L + C);
var3 = Close + ((1.02 * High)High);
Symbol  Meaning 
NOT  Logical "Not"  gives "True" when operand is equal to false 
AND  Logical "And"  gives "True" result if BOTH operands are true at the same time 
OR  Logical "Or"  gives "True" result if ANY of operands is true 
If a formula requires multiple conditions, you can combine the conditions with AND and OR operators. For example, maybe you'd like to plot a +1 when the MACD is greater than zero and the RSI is greater than 70:
Condition = MACD() > 0 AND RSI(14) > 70;
You can add as many conditions within a formula as you like.
Introduced in version 5.00, the compound operatos are specifeid in the form of:
destinvar op= expr;
where destinvar is the variable, expr is the expression, and op is one of the following artithmetic operators: +, , *, /, %, &, 
The destinvar op= expr form behaves as:
destinvar = destinvar op expr;
This is shortcut form for common assignment statements like k = k + 2; so you can write it shorter as:
k += 2;
and it will work the same but little faster.
Full list of available assignment operators is here:
No  Symbol  Meaning 
1  =  Store the value of the second operand in the object specified by the first operand (“simple assignment”). 
2  *=  Multiply the value of the first operand by the value of the second operand; store the result in the object specified by the first operand. 
3  /=  Divide the value of the first operand by the value of the second operand; store the result in the object specified by the first operand. 
4  %=  Take modulus of the first operand specified by the value of the second operand; store the result in the object specified by the first operand. 
5  +=  Add the value of the second operand to the value of the first operand; store the result in the object specified by the first operand. 
6  –=  Subtract the value of the second operand from the value of the first operand; store the result in the object specified by the first operand. 
7  &=  Obtain the bitwise AND of the first and second operands; store the result in the object specified by the first operand. 
8  =  Obtain the bitwise inclusive OR of the first and second operands; store the result in the object specified by the first operand 
The typeof operator is used in the following way:
typeof (operand)
The typeof operator returns a string indicating the type of the *unevaluated*
operand. operand is the string, variable, function identifier, or object for
which the type is to be returned.
When supplying identifier, it should be provided alone, without arithmetic
operators, without extra arguments and without braces.
If you want to check the type of value returned by the function, you must first
assign the return value to a variable and then use
typeof( variable ).
Possible return values are:
if( typeof(
somevar ) == "undefined" )
{
/// when somevar is undefined the code here will execute
}
The following sample COMMENTARY code shows the output of
typeof() in some common situations:
x = MACD();
y = LastValue( x );
function testfun()
{ return 1;
};
printf( typeof(
test ) + "\n" ); //
the undefined variable
printf( typeof( 1 )
+ "\n"); //
literal number
printf( typeof( "checking" )
+ "\n"); //
literal string
printf( typeof(
x ) + "\n"); //
array variable
printf( typeof(
y ) + "\n"); //
scalar variable
printf( typeof( MACD )
+ "\n"); //
function identifier
printf( typeof(
testfun ) + "\n" ); //
user function identifier
AFL supports parentheses in formulas.
Parentheses can be used to control the operation precedence (the order in which the operators are calculated). AmiBroker always does operations within the innermost parentheses first. When parentheses are not used, the precedence is as follows (higher precedence listed first):
No  Symbol  Meaning 
1  ++  Postincrement/preincrement (i++ works like i = i + 1) 
2    Postdecrement/predecrement 
3  [ ]  Array element (subscript) operator 
4  ^  Exponentiation 
5    Negation  Unary minus 
6  *  Multiplication 
7  /  Division 
8  %  Reminder (Modulo operator) 
9  +  Addition 
10    Subtraction 
11  <  Less than 
12  >  Greater than 
13  <=  Less than or equal to 
14  >=  Greater than or equal to 
15  ==  Equal to 
16  !=  Not equal to 
17  &  Bitwise "And" (AFL 2.1+) 
18    Bitwise "Or" (AFL 2.1+) 
19  NOT  Logical "Not" 
20  AND  Logical "And" 
21  OR  Logical "Or" 
22  =  Variable assignment operator 
23  *= /= %= += = & = = 
Compound assignment 
The expression
H + L / 2;
(without parenthesis) would be calculated by AmiBroker as "L / 2" plus "H", since division has a higher precedence. This would result in a much different value than
(H + L)/2;
A few words about increment/decrement operators. There are two kinds of them: postfix and prefix.
The unary operators (++ and ) are called “prefix” increment or decrement operators when the increment or decrement operators appear before the operand. Postfix increment and decrement has higher precedence than prefix increment and decrement operators. When the operator appears before its operand, the operand is incremented or decremented and its new value is the result of the expression.
i = 5;
j = ++i; // i will be incremented first and
result (number 6) will be assigned to j.
The result of the postfix increment or decrement operation is the value of the postfixexpression before the increment or decrement operator is applied. The type of the result is the same as that of the postfixexpression but is no longer an lvalue. After the result is obtained, the value of the operand is incremented (or decremented).
i = 5;
j = i++; // j will be assigned the value of
5 (before incrementation) and then i will be incremented to 6.
An array identifier followed by an expression in square brackets ([ ]) is a subscripted representation of an element of an array object.
arrayidentifier [ expression ]
It represents the value of expressionth element of array.
BarCount constant gives the number of bars in array (such as Close, High, Low, Open, Volume, etc). Array elements are numbered from 0 (zero) to BarCount1. BarCount does NOT change as long as your formula continues execution, but it may change between executions when new bars are added, zoom factor is changed or symbol is changed.
To get the first bar you can use array[ 0 ], to get the last bar of array you can use array[ BarCount  1 ];
For example:
Close[ 5 ]
;
Represents the sixth element (bar) of the close array.
Close[ 0 ];
Represents the very first available bar of the close array.
High[ BarCount  1 ];
Represents the last bar of High array.
Matrices are twodimensional arrays of numbers.
To create a matrix use:
my_var_name = Matrix( rows, cols, initvalue);
To access matrix elements, use:
my_var_name[ row ][ col ];
where
row is a row index (0... number of rows1)
and
col is a column index (0... number of columns1)
Matrices and their elements support all scalar (elementwise) arithmetic and logical operations.
All these standard operators are performed on matrices elementwise. For that reason for example to add two matrices they must be the same size (the number of rows and columns must be the same). If they are not the same it is up to you how to perform calculation on each element via loop.
So you can for example add, subtract, multiply, divide two matrices if they have same dimensions with one call.
x = Matrix( 5, 6, 9 ); //
matrix 5 rows 6 columns, initial value 9
y = Matrix( 5, 6, 10 ); //
matrix 5 rows 6 columns, initial value 10
z = y  x; // will give you matrix 5 rows and 6 columns
filled with elements holding value 1 (difference between 10 and 9).
All those operations are performed ELEMENTWISE.
You can also apply any arithmetic and logical operation on matrix AND scalar
value. This would perform elementwise
operation on each element of source matrix and given scalar value.
m = Matrix( 10, 10, 0 ); //
m will be 10x10 matrix filled with zeros
z = m; // z is now also a matrix
for( i = 0;
i < 10; i++ )
{
z[ i ][ 4 ] = i; //
fill z with some other values, note that m will remain unaffected.
}
for( i = 0;
i < 10; i++ )
_TRACEF( "%g = %g,
%g, %g\n", i, m[i][1], m[ i][4],
z[ i][4]);
// scalar addition (element wise)
z += 3;
m += 5;
for( i = 0;
i < 10; i++ )
_TRACEF( "%g = %g,
%g, %g\n", i, m[i][1], m[ i][4],
z[ i][4]);
There is one special operator that works only on matrices  it is matrix
product. The operator for matrix product is @ (the
'at' sign). Matrix product is the linear algebra way to multiply matrices.
If you write C = A @ B, it multiplies matrix A(n,k) by matrix B(k,m) to produce
matrix C(n,m) so the number of columns in matrix A must be equal to number
of rows in matrix B. For more info see: https://en.wikipedia.org/wiki/Matrix_multiplication The
precedence of matrix product @ operator is the same as * (so it has higher
precedence than addition and subtraction).
A = Matrix( 1, 3 );
B = Matrix( 3, 2 );
// matrix A = [ 1, 4, 6 ]
// matrix B =
// [ 2, 3 ]
// [ 5, 8 ]
// [ 7, 9 ]
A[ 0 ][ 0 ] = 1;
A[ 0 ][ 1 ] = 4;
A[ 0 ][ 2 ] = 6;
B[ 0 ][ 0 ] = 2;
B[ 0 ][ 1 ] = 3;
B[ 1 ][ 0 ] = 5;
B[ 1 ][ 1 ] = 8;
B[ 2 ][ 0 ] = 7;
B[ 2 ][ 1 ] = 9;
X = A @ B;
_TRACEF("%g %g",
X[ 0 ][ 0 ], X[ 0 ][ 1 ]
);
A compound statement consists of zero or more statements enclosed in curly braces ({ }). A compound statement can be used anywhere a statement is expected. Compound statements are commonly called “blocks.”
{
statement1;
....
statementN;
}
(this is 'borrowed' from C language, users of other programming languages are used to use BEGIN for { and END for } )
if(
Amount > 100 )
{
_TRACE("Amount
above 100");
Balance = Balance + Amount;
}
else
Balance = Balance  Amount;
In addition to mathematical operators, AmiBroker contains over 70 builtin functions that perform mathematical operations.
The following formula consists of a single function that gives the square roots of the closing prices:
sqrt( Close );
The following formula consists of a single function that gives a 14period RSI indicator:
Graph0 = RSI(14);
The following formula consists of two functions. The result is the difference between the MACD indicator and a 9period exponential moving average of the MACD:
Graph0 = MACD()  EMA(MACD(),9);
All function calls must consist of function identifier (name) followed by a pair of parentheses.
As has been eluded to in earlier examples, a function can be "nested" within a function. The nested function can serve as the main function's data array parameter. The following examples show functions nested within functions:
MA( RSI(15), 10 );
MA( EMA( RSI(15), 20), 10 );
The first example calculates a 10period simple moving average of a 15period Relative Strength Index (RSI). The second example calculates a 20period exponential moving average of a 15period RSI, and then calculates a 10period simple moving average of this moving average.
The iif() function is used to create conditional assignments. It contains three parameters as shown in the following example.
dynamicrsi = IIf( Close > MA(C,10), RSI(9), RSI(14) );
The above "iif" statement reads (in English) as follows: If today's close is greater than today's 10day simple moving average of the close, then assign a 9day RSI to the dynamicrsi variable, otherwise, assign a 14day RSI. The next formula assigns “positive volume” to volresult variable if the close is greater than the median price. Otherwise, "negative volume" is assigned.
volresult = IIf( Close > (High+Low)/2, Volume, Volume );
If you simply want an expression to be evaluated as either true or false, it can be done without the use of the iif() function. The following formula will result in either a 1 (true) or a 0 (false):
result = RSI(14) > 70;
The same done with iif() gives the same results, but the formula is longer.
result = IIf(RSI(14) > 70, 1, 0 );
Please note that IIF is a function  so the result of evaluation is returned by that function and should be assigned to some variable.
IIf always evaluates both TRUE_PART and FALSE_PART, even though it returns only one of them. Because of this, you should watch for undesirable side effects. IIF function is NOT a flowcontrol statement. If you need flow control (conditional execution of some code parts) you should look for ifelse conditional statement described later in this document.
The following example shows one common error made with IIF function:
IIf( condition, result = 7, result = 9 ); // THIS IS WRONG
Correct usage is:
result = IIf( condition, 7, 9 );
/* 7 or 9 is *returned* and assigned to result variable depending on condition */
In order to shorten, simplify, enhance, and make the maintenance of complex formulas easier, you may want to use variables. In fact using variables you can significantly improve formula calculation speed. So it is strongly recommended to use variables and there is no limit on number of variables you can define.
A variable is an identifier that is assigned to an expression or a constant. The number of variables used in a formula is not limited. Variables must be assigned before the variable is used in the formula. Variables cannot be assigned within a function call.
Userdefined variable names (identifiers) cannot duplicate names already used by functions (e.g., ma, rsi, cci, iif, etc.) or predefined array identifiers (e.g., open, high, low, close, simple, o, c, l, h, s, a).
AmiBroker uses some reserved variable names in its formulas, for example in AutoAnalysis window you have to assign values to 2 variables named 'buy' or 'sell' to specify the conditions where "buy" and "sell" conditions occur. For example (system that buys when MACD rises above 0 line, and sells when MACD falls below 0 line)
Buy = Cross( MACD(), 0 );
Sell = Cross( 0, MACD() );
AmiBroker uses the following reserved variable names. Please note that variables marked as obsolete should NOT be used in new coding. They are left for backward compatibility only and new formulas should use modern functions like Plot() to plot indicators and AddColumn() to define exploration columns.
Variable  Usage  Applies to 
buy  defines "buy" (enter long position) trading rule  Automatic Analysis, Commentary 
sell 
defines "sell" (close long position) trading rule 
Automatic Analysis, Commentary 
short  defines "short" (enter short position  short sell) trading rule  Automatic Analysis 
cover  defines "cover" (close short position  buy to cover) trading rule  Automatic Analysis 
buyprice  defines buying price array (this array is filled in with the default values according to the Automatic Analyser settings)  Automatic Analysis 
sellprice  defines selling price array (this array is filled in with the default values according to the Automatic Analyser settings)  Automatic Analysis 
shortprice  defines short selling price array (this array is filled in with the default values according to the Automatic Analyser settings)  Automatic Analysis 
coverprice  defines buy to cover price array (this array is filled in with the default values according to the Automatic Analyser settings)  Automatic Analysis 
title  defines title text (overrides any graphNname)  Indicators 
tooltip  Obsolete in 5.40. Use Data window instead or use Plot() with styleHidden if you want to add your custom values to data tooltip. 
Indicators 
graphxspace  defines percentage extra space added at the top and the bottom of the chart  Indicators 
graphzorder  GraphZOrder variable allows to change the order of plotting indicator lines. When GraphZOrder is not defined or is zero (false)  old ordering (last to first) is used, when GraphZOrder is 1 (true)  reverse ordering is applied.  Indicators 
exclude  If defined, a true (or 1) value of this variable excludes current symbol from scan/exploration/back test. They are also not considered in buy and hold calculations. Useful when you want to narrow your analysis to certain set of symbols.  Automatic Analysis 
roundlotsize  defines round lot sizes used by backtester (see explanations below)  Automatic Analysis (new in 4.10) 
ticksize  defines tick size used to align prices generated by builtin stops (see explanations below) (note: it does not affect entry/exit prices specified by buyprice/sellprice/shortprice/coverprice)  Automatic Analysis (new in 4.10) 
pointvalue  allows to read and modify future contract point value (see
backtesting futures) CAVEAT: this AFL variable is by default set to 1 (one) regardless of contents of Information window UNLESS you turn ON futures mode (SetOption("FuturesMode", True )) 
Automatic Analysis (new in 4.10) 
margindeposit  allows to read and modify future contract margin (see backtesting futures)  Automatic Analysis (new in 4.10) 
positionsize 
Allows control dollar amount or percentage of portfolio that is invested into the trade (more information available in the "Tutorial: Backtesting your trading ideas") 
Automatic Analysis (new in 3.9) 
positionscore  Defines the score of the position. More details: "Tutorial: Portfolio Backtesting")  Automatic analysis 
numcolumns  Exploration only: defines the number of your own columns (excluding predefined ticker and date columns) and assign the column value to the variable  Automatic Analysis 
filter  Exploration only: controls which symbols/quotes are accepted.
If "true" (or 1) is assigned to that variable for given symbol/quote
it will be displayed in the report.
So, for example, the following formula will accept all symbols with closing prices greater than 50 :

Automatic Analysis 
columnN (obsolete) 
Exploration only: defines Nth column value. Example:

Automatic Analysis 
columnNformat (obsolete) 
Exploration only: allows you to define the formatting applied to numbers. By default all variables are displayed with 2 decimal digits, but you can change this by assigning a different value to this variable: 1.5 gives 5 decimal digits, 1.0 gives no decimal digits. So, in our example, typing:
will give closing prices displayed with 4 decimal digits. 
Automatic Analysis 
columnNname (obsolete) 
Exploration only: allows you to define the header name. Assigning
will change the name of the first custom column from the default "Column 0" to more appropriate "Close". 
Automatic Analysis 
maxgraph (obsolete) 
specifies maximum number of graphs to be drawn in custom indicator window (default=3)  Indicators 
graphN (obsolete) 
defines the formula for the graph number N (where N is a number 0,1,2,..., maxgraph1)  Indicators 
graphNname (obsolete) 
defines the name of Nth graph line. This will appear in the title of the chart pane  Indicators 
graphNcolor (obsolete) 
defines the color index of Nth graph line (color indexes are related to the current palette  see Preferences/Color) colorCustom1 = 0 colorBlack = 16 colorDarkRed = 24 colorRed = 32 colorPink = 40 colorRose = 48 
Indicators 
graphNbarcolor (obsolete) 
defines the array that holds palette indexes for each bar drawn  Indicators 
graphNstyle (obsolete) 
defines the style of Nth graph. Style is defined as a combination (sum) of one or more following flags: styleLine = 1  normal (line) chart (default) Not all flag combinations make sense, for example (64+1) (candlestick
+ line) will result in candlestick chart (style=64) 
Indicators 
graphNbarcolor (obsolete) 
defines the array of color indexes for the bars and candlesticks in Nth graph ine (color indexes are related to the current palette  see Preferences/Color)  Indicators 
SEE ALSO: