Boolean Arrays: Close > MA(Close, 50)
Write this line and read it aloud:
Fragment — not a complete formula
Trend = Close > MA( Close, 50 );Most people read it as a question with a single answer: is the close above its fifty-bar
average? It is not. It is the same question asked separately of every bar on the chart, and
Trend holds every one of the answers. On a chart with four thousand bars, that line asked
four thousand questions and stored four thousand answers.
This lesson is the previous one applied to comparisons. It is short on new syntax and long on consequences, because nearly every rule you will ever write ends up as a Boolean array, and almost every confusing result later in the course traces back to treating one as if it were a single yes or no.
True is 1 and false is 0
Section titled “True is 1 and false is 0”AFL has no separate Boolean type. Comparison operators — <, >, <=, >=, ==, != —
produce “a true (1) or false (0) value”, in the guide’s own words, and the official Knowledge
Base article on constants says the same thing: True is 1 and False is 0.
That is not an implementation detail you are supposed to ignore. It is the design, and it is what makes Booleans useful. A comparison produces numbers, so you can add them, average them, plot them and count them with the ordinary arithmetic you already have.
It also means these two lines are equivalent, and the shorter one is the idiom the documentation itself recommends:
Fragment — not a complete formula
Overbought = IIf( RSI( 14 ) > 70, 1, 0 ); // works, but says nothing extraOverbought = RSI( 14 ) > 70; // the same array, written plainlyIf you find yourself writing IIf( something, 1, 0 ), delete the IIf. The comparison
already produced the ones and zeros.
One comparison, one answer per bar
Section titled “One comparison, one answer per bar”Here is Close > MA( Close, 3 ) on the ten bars this part has been using, with the average
written out so you can check each answer yourself.
Trend = Close > MA( Close, 3 )
| Bar | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|
Close | 1.23 | 1.26 | 1.24 | 1.28 | 1.25 | 1.25 | 1.31 | 1.30 | 1.32 | 1.28 |
MA( Close, 3 ) | Null | Null | 1.243 | 1.260 | 1.257 | 1.260 | 1.270 | 1.287 | 1.310 | 1.300 |
Trend | Null | Null | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 |
Read across the bottom row. It is not “the trend is up”. It is a record of what was true on each individual bar: unknown, unknown, no, yes, no, no, yes, yes, yes, no.
Two features of that row will matter for the rest of the course.
The first two entries are Null, not 0. The three-bar average does not exist on bars 0
and 1, and a comparison against something that does not exist cannot produce an answer. It
produces Null, which is neither true nor false. This is the whole subject of lesson eight,
and it is the difference between a rule that counts correctly and one that quietly does not.
The row can be plotted. Because it holds only 1 and 0, drawing it gives a square wave — a visual record of exactly when the condition held. This is the single fastest way to check whether a condition means what you think, and the formula at the end of this lesson does it.
What a Boolean array is not
Section titled “What a Boolean array is not”Three things you might expect it to be, and are not:
It is not a signal. Trend is true on every bar where the close is above the average,
which in a sustained move is hundreds of consecutive bars. If you hand that to the backtester
as a Buy array it will attempt to buy on all of them. Turning a state into an event is a
distinct step with its own lesson in Part 9.
It is not usable as a condition for if. This is the most common runtime error in AFL,
and AmiBroker names it explicitly. if( Close > Open ) raises Error 6, “Condition in
IF/WHILE/FOR must be Numeric or Boolean”, and the official explanation is exactly the right
one: there would be no way to decide whether to execute the statement, “if for example the
array was [True,True,False,…,False,True]”. Lesson seven covers what to write instead.
It is not a count. Trend does not tell you how often the condition held. It tells you
where. Counting is a separate operation, and it is the next section.
Counting and summing Booleans
Section titled “Counting and summing Booleans”Because true is 1 and false is 0, counting how often a condition held is just adding the array up. Three functions do it, and choosing the right one is choosing what question you are asking.
Fragment — not a complete formula
Trend = Close > MA( Close, 50 );
TrueSoFar = Cum( Nz( Trend ) ); // running total from the first barTrueLast20 = Sum( Nz( Trend ), 20 ); // rolling total over the last 20 barsFractionUp = Sum( Nz( Trend ), 20 ) / 20; // proportion of the last 20 barsCum( array ) is the cumulative sum from the first bar in the array; Sum( array, periods )
is a rolling sum over a fixed window that includes the current bar. Both return arrays: the
running total as at each bar, not a single grand total.
Counting a Boolean array two different ways
| Bar | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|
Trend | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 |
Cum( Trend ) | 0 | 0 | 0 | 1 | 1 | 1 | 2 | 3 | 4 | 4 |
Sum( Trend, 3 ) | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 2 | 3 | 2 |
Notice Nz() wrapped around Trend in the code above. It replaces empty values with zero.
Without it, the warm-up Null values travel into the total and the count becomes unusable —
which is exactly the failure lesson eight is about. Get into the habit now: when you count a
Boolean array, say what the unknown bars should count as.
Reading a single value out
Section titled “Reading a single value out”Sometimes you genuinely want one number: is the condition true now?
Fragment — not a complete formula
Trend = Close > MA( Close, 50 );TrendNow = LastValue( Trend ); // 1 or 0 - a single numberLastValue() returns the value at the last bar. SelectedValue() returns the value at the
bar the selection line sits on, which is what you want in a chart title. Both collapse the
column to a scalar, and both are perfectly legitimate when a scalar is what you need — a
title, a message, a condition for an if statement.
There is also IsTrue( array ), whose documentation says it returns 1 where a value is
not {empty} AND not zero.
It is the honest way to ask “is this definitely true here”, collapsing both Null and 0 to
0 in one step, and it is worth remembering when you inherit a formula whose arrays might
hold anything.
The arithmetic temptation
Section titled “The arithmetic temptation”Because Booleans are numbers, you can do arithmetic with them, and there is a whole folklore of clever tricks built on it. Most of them are fragile, and AmiBroker’s own Knowledge Base uses one as a cautionary example:
Fragment — not a complete formula
// The official example of what NOT to do.Shape = Buy * shapeUpArrow + Sell * shapeDownArrow;The idea is that only one of Buy and Sell will be 1 on any bar, so the sum picks out the
right shape constant. On the bar where both happen to be true, the two constants add together
and produce a third, unintended shape. The recommended form states the intent instead of
encoding it:
Fragment — not a complete formula
Shape = IIf( Buy, shapeUpArrow, IIf( Sell, shapeDownArrow, shapeNone ) );The general lesson generalises well beyond shapes. Multiplying by a Boolean to “switch
something off” — Position = Size * Trend; — works only while you are certain the array
holds exactly 1 and 0, and Boolean arrays acquire Null at their warm-up and can acquire
other values when they pass through functions. Write what you mean.
Watch it happen
Section titled “Watch it happen”This formula plots a Boolean array directly on the chart, so you can see the ones and zeros as a shape rather than trust a description of them, and reports a running count in the title.
Complete runnable AFL
// boolean-count.afl// Part 8 - Boolean Arrays//// Purpose: show that a comparison between two arrays answers the question// once per bar, not once for the whole chart, and then count how// often the answer was true.// Assumes: any symbol and interval with more than MaPeriod bars of history.// Apply: Formula Editor -> Apply indicator. The green blocks are the bars// on which the comparison came out true.
_SECTION_BEGIN( "Boolean Arrays" );
// ---------------------------------------------------------------------------// Settings// ---------------------------------------------------------------------------
MaPeriod = 50;
// ---------------------------------------------------------------------------// One comparison, one answer per bar// ---------------------------------------------------------------------------
Average = MA( Close, MaPeriod );
// Trend is not "yes" or "no". It is an array the same length as Close, holding// 1 where the close was above the average and 0 where it was not - and empty// values over the warm-up, where the average does not exist yet.Trend = Close > Average;
// Nz() replaces those empty warm-up values with 0 so that they count as// "not true" rather than poisoning the running total. Lesson 8 of this part// explains exactly why the total would otherwise be unusable.TrueBars = Cum( Nz( Trend ) );TotalBars = Cum( 1 );
// ---------------------------------------------------------------------------// Drawing// ---------------------------------------------------------------------------
Plot( Close, "Close", colorDefault, styleCandle );Plot( Average, "MA(" + MaPeriod + ")", colorBlue, styleLine | styleThick );
// Because Trend only ever holds 1 or 0, plotting it directly gives a square// wave. That square wave is the visible proof that the comparison produced a// column of answers rather than a single answer.Plot( Trend, "Close > MA", colorGreen, styleHistogram | styleOwnScale | styleNoLabel );
Title = StrFormat( "{{NAME}} {{DATE}} Trend %g true on %g of %g bars so far (%.1f%%)", Trend, TrueBars, TotalBars, 100 * TrueBars / TotalBars );
_SECTION_END();How it works. One moving average, one comparison, and two counters. Trend is the
comparison — a full-length array of 1s and 0s with Null over the warm-up. TrueBars is a
running count of the true bars, with Nz() deciding that unknown counts as not-true.
TotalBars is Cum( 1 ), the running bar number, which is the standard idiom for “how many
bars have we seen so far”. The final Plot() draws Trend itself on its own scale, which
turns it into a square wave sitting behind the price.
Key functions. Cum( array ) — cumulative sum from the first bar, returning an array.
Nz( x ) — replaces empty, not-a-number and infinite values with zero. Sum( array, periods )
is its fixed-window sibling, used in the fragments above but not in this formula.
Test it. Click on a bar where the green block starts. The title should read Trend 1, and
the candle should be the first one whose close is above the blue line. Click the bar
immediately before it: Trend 0. If the block’s edges do not line up with the line crossings,
you are plotting a different array from the one you think.
Common errors. If the price chart collapses into a flat line, the styleOwnScale flag has
been dropped from the Trend plot, so a series of 1s and 0s is being drawn on the price axis.
If the percentage in the title stays at 100%, you have removed Nz() and the count has been
poisoned by the warm-up. If the block covers every bar, check that you compared with > and
not with something like >= against zero.
Extension. Add TrueLast20 = Sum( Nz( Trend ), 20 ); and plot it. You now have two
descriptions of the same condition: an on-off record, and a count of how many of the last
twenty bars it held. Compare them during a choppy stretch of the chart. The count is the more
informative of the two, and it is the shape of measure that Parts 13 and 16 are built on.
A comparison in AFL evaluates once per bar and returns a full-length array of 1s and 0s, with
Null wherever an input was unknown. True is 1 and false is 0, which is why counting a
condition is just summing it — cumulatively with Cum(), or over a window with Sum() — and
why IIf( condition, 1, 0 ) is always redundant. LastValue() and SelectedValue() collapse
such an array to a single number, which is what a title or an if statement needs and what a
per-bar rule must never contain. And a Boolean array is a state, not a signal: it says where
the condition held, not when something happened.
The next lesson combines these arrays with AND, OR and NOT, and shows how to choose a
different value on every bar without writing a loop.
Check your understanding
Sources for this lesson
8 verified · checked 2026-09-01
- 01AmiBroker User's Guide — AFL Reference Manual§ Comparison operatorsamibroker.com/guide/a_language.html2026-08-31
- 02AmiBroker Knowledge Base — What are constants in AFL and how they workamibroker.com/kb/2014/10/05/what-are-constants-in-afl-and-how-they-work2026-08-31
- 03AmiBroker User's Guide — Understanding how AFL worksamibroker.com/guide/h_understandafl.html2026-08-31
- 04AFL Function Reference — Cumamibroker.com/guide/afl/cum.html2026-08-31
- 05AFL Function Reference — Sumamibroker.com/guide/afl/sum.html2026-08-31
- 06AFL Function Reference — LastValueamibroker.com/guide/afl/lastvalue.html2026-08-31
- 07AFL Function Reference — IsTrueamibroker.com/guide/afl/istrue.html2026-08-31
- 08AmiBroker User's Guide — Error 6, condition must be numeric or booleanamibroker.com/guide/errors/6.html2026-09-01
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.