Bar counting

7 functions

BARSLAST(COND)

Bars since COND was last true. 0 on the bar itself.

COND(condition)
The event to measure back to.
// bars since the last golden cross
AGE: BARSLAST(CROSS(MA5, MA20));

// let a signal expire after 20 bars
FRESH := AGE <= 20;

// combine with REF to fetch the price at that event
ENTRY: REF(CLOSE, AGE);
BARSLASTS(COND, N)

Bars since the N-th most recent time COND was true. N may be a series.

COND(condition)
The event to measure back to.
N(integer)
Which occurrence, counting back — 1 is the most recent.
// spacing between the last two crossovers — a rough read
// on how choppy the market has become
GAP: BARSLASTS(CROSS(MA5, MA20), 2) - BARSLASTS(CROSS(MA5, MA20), 1);
CHOPPY: GAP < 5;
BARSLASTCOUNT(COND)

Length of the current unbroken run of true bars.

COND(condition)
The condition whose run length is counted. Resets to 0 the moment it fails.
// how many bars this up-run has lasted
UPRUN: BARSLASTCOUNT(CLOSE > OPEN);

// how long price has held above the average —
// unlike BARSLAST this resets on every break
HOLD: BARSLASTCOUNT(CLOSE > MA(CLOSE, 20));
DRAWNUMBER(HOLD >= 10 AND REF(HOLD, 1) < 10, LOW, HOLD, 0);
BARSSINCE(COND)

Bars since COND was true for the first time ever.

COND(condition)
The event to measure from. Only its FIRST occurrence counts.
// age of the instrument's first listed high —
// BARSLAST would track the most recent one instead
SINCEFIRST: BARSSINCE(HIGH > 0);

// only start drawing once enough history exists
READY := BARSSINCE(CLOSE > 0) > 250;
BARSSINCEN(COND, N)

Bars since COND was first true within the last N bars.

COND(condition)
The event to measure from.
N(integer)
How far back to look for its first occurrence.
// first breakout inside the last 60 bars, and how long ago —
// a bounded version of BARSSINCE
FIRSTBREAK: BARSSINCEN(HIGH > HV(HIGH, 20), 60);
BARSCOUNT(X)

Number of bars for which X has held a valid value.

X(series)
The series to measure.
// guard a long-period indicator: MA250 is meaningless
// until there are 250 bars to average
ENOUGH := BARSCOUNT(CLOSE) > 250;
MA250: IF(ENOUGH, MA(CLOSE, 250), DRAWNULL), COLORYELLOW;
BARSNEXT(COND)

Bars until COND next becomes true — a forward-looking function.

COND(condition)
The future event to count towards.
// research only: how long did it take for each signal
// to reach its exit? never put this in a live signal
WAIT: BARSNEXT(CROSS(MA20, MA5));
AVGWAIT: MA(WAIT, 20), COLORYELLOW;