// warmup-guard.afl
// Part 8 - Null Values, Nz() and Warm-Up Periods
//
// Purpose:  make the warm-up period visible, show that empty values spread
//           through comparisons as well as arithmetic, and demonstrate two
//           independent defences against a condition array that is silently
//           empty at the start of the data.
// Assumes:  a symbol with clearly more than SlowPeriod bars of history, so
//           that the warm-up is a small part of the chart rather than all
//           of it.
// Apply:    Formula Editor -> Apply indicator, then scroll to the very
//           beginning of the history and compare the two shaded rows.

_SECTION_BEGIN( "Warm-up Guard" );

// ---------------------------------------------------------------------------
// Settings
// ---------------------------------------------------------------------------

SlowPeriod = 200;
FastPeriod = 20;

// ---------------------------------------------------------------------------
// Ingredients, and the empty bars they come with
// ---------------------------------------------------------------------------

SlowMA = MA( Close, SlowPeriod );
FastMA = MA( Close, FastPeriod );

// NullCount() with mode 1 reports how many consecutive empty values sit at the
// FRONT of an array. It is the cheapest way to see a warm-up as a number
// rather than as a suspicion.
SlowWarmUp = NullCount( SlowMA, 1 );
FastWarmUp = NullCount( FastMA, 1 );

// ---------------------------------------------------------------------------
// The condition, written the way most people write it first
// ---------------------------------------------------------------------------

// On every warm-up bar SlowMA is empty, so each comparison is empty too - not
// false. The AND of two empty values is empty as well. RawSignal therefore has
// a run of empty bars at the front where a reader would expect zeros.
RawSignal = Close > SlowMA AND FastMA > SlowMA;

// ---------------------------------------------------------------------------
// Two defences, either of which is enough on its own
// ---------------------------------------------------------------------------

// 1. Refuse to answer until the slowest input has enough bars behind it.
//    BarIndex() is zero-based, so bar number SlowPeriod is the first bar with
//    a complete window behind it.
HasHistory = BarIndex() >= SlowPeriod;

// 2. Turn anything still empty into an explicit zero.
Signal = Nz( RawSignal ) AND HasHistory;

// ---------------------------------------------------------------------------
// Drawing
// ---------------------------------------------------------------------------

Plot( Close,  "Close",                   colorDefault, styleCandle );
Plot( SlowMA, "MA(" + SlowPeriod + ")",  colorBlue,    styleLine | styleThick );
Plot( FastMA, "MA(" + FastPeriod + ")",  colorOrange,  styleLine );

// An array is only drawn where it has a value, so RawSignal simply stops
// existing over the warm-up while Signal is a definite zero there.
Plot( RawSignal, "RawSignal", colorRed,
      styleHistogram | styleOwnScale | styleNoLabel );
Plot( Signal, "Signal", colorGreen,
      styleHistogram | styleOwnScale | styleNoLabel );

Title = StrFormat(
    "{{NAME}} {{DATE}}   %g bars   empty at front: MA(%g) %g, MA(%g) %g   RawSignal %g   Signal %g",
    BarCount, SlowPeriod, SlowWarmUp, FastPeriod, FastWarmUp, RawSignal, Signal );

_SECTION_END();
