Variables, Numbers and Expressions
A formula is mostly expressions, and an expression that computes something other than what you meant is the most expensive kind of bug, because it produces a number rather than an error. This lesson covers what a variable is in AFL, what kinds of number exist, which operators you have, and the one precedence rule that AmiBroker’s own documentation lists among the most common mistakes its users make.
Assignment
Section titled “Assignment”A variable in AFL is a name that holds whatever was last assigned to it.
Fragment — not a complete formula
MaPeriod = 50;Average = MA( Close, MaPeriod );There are no declarations, no types to announce, and no initialisation ceremony. The first assignment brings the name into existence. Reading a name that has never been assigned is Error 29, “Variable used without having been initialized” — a clear message that usually means a typo, since a misspelled name is by definition a name never assigned.
Assignment is itself an expression that has a value, which makes chained assignment work:
Fragment — not a complete formula
Wins = Losses = 0;Both names end up holding zero. This is occasionally useful and rarely necessary. Note the
names: Highest and Lowest would have been the natural words here and are both built-in
functions, so assigning to them raises Error 33, “Identifier already in use”.
Since version 5.00 there is also compound assignment, where op is one of + - * / % & |:
Fragment — not a complete formula
Total = 0;Total += 1; // exactly the same as Total = Total + 1;The documentation describes the compound form as doing the same thing “a little faster”. Use it where it reads better and ignore it where it does not.
= is not ==
Section titled “= is not ==”This is item one on AmiBroker’s official Common Coding Mistakes list, and it earns its
place. = assigns. == compares. They are not interchangeable, and the wrong one usually
compiles.
Fragment — not a complete formula
// WRONG - assigns 10 to Variable, then uses the result as a conditionResult = IIf( Variable = 10, High, Low );
// CORRECTResult = IIf( Variable == 10, High, Low );AmiBroker helps here. Whenever it sees an assignment inside the condition of an if,
while or for, or inside IIf(), it emits Warning 501: “Assignment within conditional.
Did you mean == instead of = ?”. Read your warnings. That warning exists because this
mistake is common enough to have earned its own diagnostic.
There are no integers
Section titled “There are no integers”This surprises people, and it is stated flatly in the official documentation for printf:
“%d or %x will not work because there are no integers in AFL.”
Every number in AFL is floating point. 5 and 5.0 are the same value. There is no
integer division: 7 / 2 is 3.5, not 3. When you need a whole number you have to ask
for one with Int() or Round(), and when you format a number for display you use %g,
%f or %e, never %d.
Two practical consequences follow. Counting works exactly as you would hope — a running
count is just a sum of ones, and nothing overflows or truncates. But equality between
computed values is fragile in the way it is fragile in every floating-point language:
0.1 + 0.2 is not reliably equal to 0.3. Compare computed values with > or <, or
compare a difference against a small tolerance, rather than testing two calculated
quantities for exact equality.
Arithmetic operators
Section titled “Arithmetic operators”The complete set, with the AFL version each arrived in where the documentation states one:
| Operator | Meaning |
|---|---|
+ |
addition, and string concatenation |
- |
subtraction, and unary minus |
* |
multiplication |
/ |
division |
% |
remainder / modulus (AFL 1.7 and later) |
^ |
exponentiation |
& |
bit-wise And (AFL 2.1 and later) |
| |
bit-wise Or (AFL 2.1 and later) |
Note carefully what & and | are and are not. They are bit-wise operators, not logical
ones. Their everyday use in AFL is combining flag constants — styleLine | styleThick
merges two drawing styles, and every combination of AmiBroker’s style, stop and composite
flags is built the same way. The logical operators are AND, OR and NOT, and they are
the subject of lesson seven.
Division and its edge cases
Section titled “Division and its edge cases”Dividing by zero does not raise an error in AFL. It produces an infinite value, which then travels through every subsequent calculation and quietly ruins it. Three tools deal with it:
Fragment — not a complete formula
// Guard the result: Nz() turns Null, NaN and Infinity into 0 (or a value you choose).Ratio = Nz( ( High - Low ) / ( Close - Low ) );
// Or guard the division itself, which says what you meant more clearly.Ratio = SafeDivide( High - Low, Close - Low, 0 );
// Or test explicitly, when the right answer is "do not use this bar".Usable = IsFinite( ( High - Low ) / ( Close - Low ) );SafeDivide( x, y, valueifzerodiv ) arrived in AmiBroker 6.40 and returns the third
argument whenever the divisor is zero. It is the most readable of the three, because the
reader can see what happens in the bad case without working backwards from a repair.
Operator precedence
Section titled “Operator precedence”When there are no parentheses, AFL applies operators in a fixed order. The official table lists twenty-three ranks; here are the ones that decide the shape of ordinary expressions, highest binding first:
[ ]array element^exponentiation-unary minus (negation)*/%+-<><=>===!=&bit-wise And|bit-wise OrNOTANDOR=and the compound assignments
Three of those rankings routinely catch people.
Multiplication before addition. The official guide gives the example itself: H + L / 2
means H + ( L / 2 ), not ( H + L ) / 2. If you want the midpoint of the bar, the
parentheses are not optional.
Fragment — not a complete formula
MidPrice = ( High + Low ) / 2; // the midpointNotMidPrice = High + Low / 2; // High plus half the Low. A different number entirely.Exponentiation before unary minus. ^ sits above negation, so -2^2 parses as
-( 2^2 ), which is -4. If you want 4, write ( -2 )^2.
Comparisons before logic. AND, OR and NOT all bind looser than the comparison
operators, which is exactly what you want: a > b AND c > d groups as ( a > b ) AND ( c > d ) without any help. But AND binds tighter than OR, and that one is a trap big
enough to have its own place on the official mistakes list. Lesson seven takes it apart.
Parentheses cost nothing
Section titled “Parentheses cost nothing”AmiBroker evaluates the innermost parentheses first, always. There is no performance penalty for redundant ones, and there is no prize for remembering rank 8 versus rank 9. The house rule for this course is simple: if an expression mixes two kinds of operator, parenthesise the grouping you mean, even when the default happens to be right. A reader should not have to consult a precedence table to know what your rule says.
Reassignment, and the built-in arrays
Section titled “Reassignment, and the built-in arrays”A name holds whatever was last assigned to it, and reassignment is normal and useful:
Fragment — not a complete formula
Signal = Close > MA( Close, 200 );Signal = Signal AND Volume > MA( Volume, 50 ); // narrow the same ideaBut two forms of reassignment deserve care.
Reassigning a built-in price array. Open, High, Low, Close, Volume, OpenInt
and Avg are ordinary variables. Assigning to one changes what every later line sees,
including the inside of built-in functions:
Fragment — not a complete formula
Close = MA( Close, 5 ); // legal, and rarely what anyone meantAverage = MA( Close, 50 ); // now a 50-bar average of a 5-bar averageThere are legitimate uses — the obsolete graphNstyle documentation notes that to draw
something other than the close price you have to assign new values to the predefined
arrays — but it should always be deliberate and commented. The same applies, on a much
larger scale, to TimeFrameSet(), which replaces all of them at once with time-compressed
bars until you call TimeFrameRestore(). Part 14 covers that.
Reassigning inside a block. Because braces do not create scope in AFL, a variable first
assigned inside an if block still exists afterwards. What it holds depends on whether the
block ran, which on a formula of any size is a genuinely hard question to answer by reading.
Assign a default before the block and let the block overwrite it:
Fragment — not a complete formula
WarmUpBars = 0; // a definite starting valueif( BarCount > 200 ){ WarmUpBars = 200;}Building an expression you can read
Section titled “Building an expression you can read”Everything above collapses into three habits.
Name the intermediate steps. AFL costs you nothing for extra variables, and a named intermediate is a place to put a comment and a thing you can plot when the answer is wrong.
Fragment — not a complete formula
// Hard to read, hard to debug, and the precedence needs checking.Signal = Close > MA( Close, 50 ) AND 100 * ATR( 20 ) / Close < 3;
// Same rule. Each step can be named, commented, plotted and checked.Average = MA( Close, 50 );AtrPercent = 100 * ATR( 20 ) / Close; // volatility as a percentage of priceAboveTrend = Close > Average;CalmEnough = AtrPercent < 3;Signal = AboveTrend AND CalmEnough;The second version is five lines instead of one and is better in every way that matters. It also foreshadows the debugging method in lesson nine: when a signal is wrong, you plot the intermediates and find out which one lied.
Break long expressions across lines, aligning the operators so the structure is visible.
Put the settings at the top. Any number a reader might want to change belongs in a named variable at the head of the formula, not buried at the end of an expression twenty lines down.
A variable is a name holding whatever was last assigned; reading one that was never assigned
is Error 29. Assignment is =, comparison is ==, and AmiBroker warns you when it suspects
you meant the other one. Every number is floating point — there are no integers, %d does
not work, and exact equality between computed values is unreliable. & and | are bit-wise
flag operators, not logic. Precedence follows a published table in which * beats +, ^
beats unary minus, and NOT binds looser than every comparison; parentheses cost nothing
and remove the question. And the built-in price arrays are assignable, so reassigning one
silently rewrites the rest of the formula.
The next lesson is the one this part exists for.
Check your understanding
Sources for this lesson
6 verified · checked 2026-08-31
- 01AmiBroker User's Guide — AFL Reference Manual§ Operators and precedenceamibroker.com/guide/a_language.html2026-08-31
- 02AmiBroker User's Guide — Common Coding Mistakesamibroker.com/guide/a_mistakes.html2026-08-31
- 03AFL Function Reference — printfamibroker.com/guide/afl/printf.html2026-08-31
- 04AFL Function Reference — SafeDivideamibroker.com/guide/afl/safedivide.html2026-08-31
- 05AFL Function Reference — Nzamibroker.com/guide/afl/nz.html2026-08-31
- 06AmiBroker User's Guide — AFL error listamibroker.com/guide/errors2026-08-31
Every technical claim on this page was checked against the official AmiBroker documentation on the date shown. Where the course disagrees with folklore, the source is how you can tell which one to trust.