AFL Reference Manual


AFL is a special programming language used to define and create custom indicators, scans, explorations, back-tests and guru commentaries.


Lexical elements

This chapter describes the different categories of word-like 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: C-like comments and C++ like comments. A C-like 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 comment-delimiter symbols, is replaced by one space. A C++ like comments are single-line 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 (a-z, A-Z), the underscore character ("_"), and the digits (0-9). 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:


The equal sign (=) separates variable declarations from initialization lists:
x = 5;
It also indicates the default value for a parameter (see built-in function description):
macd( fast = 12; slow = 26 ) /* default values for fast and slow arguments)

Language structure

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 function-call 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 built-in 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 case-specific.

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

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.

Assignment operator
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.

Arithmetic operators

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)
| Bit-wise "Or" (AFL 2.1+)
& Bit-wise "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);    
Logical operators
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.

Compound assignment operators

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

typeof() operator

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 =
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

Operator precedence and the parentheses

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 ++ Post-increment/pre-increment
(i++ works like i = i + 1)
2 --

(i-- works like i = i - 1 )

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 & Bit-wise "And" (AFL 2.1+)
18 | Bit-wise "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 postfix-expression before the increment or decrement operator is applied. The type of the result is the same as that of the postfix-expression but is no longer an l-value. 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.

Accessing array elements: [ ] - subscript operator

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 expression-th 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 BarCount-1. 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 and Matrix operators

Matrices are two-dimensional 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 ];

row is a row index (0... number of rows-1)
col is a column index (0... number of columns-1)

Matrices and their elements support all scalar (element-wise) arithmetic and logical operations.

All these standard operators are performed on matrices element-wise. 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 - z; // 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 ELEMENT-WISE.

You can also apply any arithmetic and logical operation on matrix AND scalar value. This would perform element-wise
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: 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 ] );

Compound statements (Blocks)

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.”






(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;
    Balance = Balance - Amount;

Built-in Functions

In addition to mathematical operators, AmiBroker contains over 70 built-in 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 14-period RSI indicator:

Graph0 = RSI(14);

The following formula consists of two functions. The result is the difference between the MACD indicator and a 9-period 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 10-period simple moving average of a 15-period Relative Strength Index (RSI). The second example calculates a 20-period exponential moving average of a 15-period RSI, and then calculates a 10-period simple moving average of this moving average.

Conditional function IIF()

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 10-day simple moving average of the close, then assign a 9-day RSI to the dynamicrsi variable, otherwise, assign a 14-day 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 flow-control statement. If you need flow control (conditional execution of some code parts) you should look for if-else 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.

User-defined 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).

Reserved variables

AmiBroker uses some reserved variable names in its formulas, for example in Auto-Analysis 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

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

Obsolete in 5.40. Use Data window instead or use Plot() with styleHidden if you want to add your custom values to data tooltip.

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 built-in 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)

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 :

filter = close > 50;

Automatic Analysis



Exploration only: defines Nth column value. Example:

column0 = Close;

Automatic Analysis



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:

column0format = 1.4;

will give closing prices displayed with 4 decimal digits.
(Note for advanced users: the integer part of this number can be used to pad formatted number with spaces - 6.0 will give no decimal digits but a number space-padded upto 6 characters.)

Automatic Analysis



Exploration only: allows you to define the header name. Assigning

column0name = "Close";

will change the name of the first custom column from the default "Column 0" to more appropriate "Close".

Automatic Analysis



specifies maximum number of graphs to be drawn in custom indicator window (default=3) Indicators
defines the formula for the graph number N (where N is a number 0,1,2,..., maxgraph-1) Indicators
defines the name of Nth graph line. This will appear in the title of the chart pane Indicators

defines the color index of Nth graph line (color indexes are related to the current palette - see Preferences/Color)

colorCustom1 = 0
colorCustom2 = 1
colorCustom3 = 2
colorCustom4 = 3
colorCustom5 = 4
colorCustom6 = 5
colorCustom7 = 6
colorCustom8 = 7
colorCustom9 = 8
colorCustom10 = 9
colorCustom11 = 10
colorCustom12 = 11
colorCustom13 = 12
colorCustom14 = 13
colorCustom15 = 14
colorCustom16 = 15

colorBlack = 16
colorBrown = 17
colorDarkOliveGreen = 18
colorDarkGreen = 19
colorDarkTeal = 20
colorDarkBlue = 21
colorIndigo = 22
colorDarkGrey = 23

colorDarkRed = 24
colorOrange = 25
colorDarkYellow = 26
colorGreen = 27
colorTeal = 28
colorBlue = 29
colorBlueGrey = 30
colorGrey40 = 31

colorRed = 32
colorLightOrange = 33
colorLime = 34
colorSeaGreen = 35
colorAqua = 35
colorLightBlue = 37
colorViolet = 38
colorGrey50 = 39

colorPink = 40
colorGold = 41
colorYellow = 42
colorBrightGreen = 43
colorTurquoise = 44
colorSkyblue = 45
colorPlum = 46
colorLightGrey = 47

colorRose = 48
colorTan = 49
colorLightYellow = 50
colorPaleGreen = 51
colorPaleTurquoise = 52
colorPaleBlue = 53
colorLavender = 54
colorWhite = 55

defines the array that holds palette indexes for each bar drawn Indicators

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)
styleHistogram = 2 - histogram chart
styleThick =4 - fat (thick)
styleDots = 8 - include dots
styleNoLine = 16 - no line
styleLog = 32 - semi-logarithmic scale
styleCandle = 64 - candlestick chart
styleBar = 128 - traditional bar chart
styleNoDraw = 256 - no draw (perform axis scaling only)
styleStaircase = 512 - staircase (square) chart
styleSwingDots = 1024 - middle dots for staircase chart
styleNoRescale = 2048 - no rescale
styleNoLabel = 4096 - no value label
stylePointAndFigure = 8192 - point and figure
(new in 4.20):
styleArea = 16384 - area chart (extra wide histogram)
styleOwnScale = 32768 - plot is using independent scaling
styleLeftAxisScale = 65536 - plot is using left axis scale (independent from right axis)

Not all flag combinations make sense, for example (64+1) (candlestick + line) will result in candlestick chart (style=64)

Note on candlestick/bar charts: these styles use indirectly O, H, L arrays in addition to graphN. So ordinary candlestick price chart formula is graph0=close; graph0style=64;.
But if you want to draw something else than close price you have to assign new values to predefined O,H,L arrays.

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