// replay-clock.afl
// Part 26 - Bar Replay: Mechanics and Honest Limits
//
// Answers one question at a glance: is Bar Replay driving this chart right
// now, and if so, where has it got to? Every other formula in this part
// depends on knowing that, because a chart under replay and a chart showing
// the whole database look identical until you check.
//
// How to run it:
//   Formula Editor -> paste -> name it "Replay clock" -> Apply Indicator.
//   Then open Tools -> Bar Replay, set Start and End, and press PAUSE.
//   The panel should change the moment playback mode is entered.
//
// Assumptions declared up front:
//   - This is a CHART formula. GetPlaybackDateTime() reports the position of a
//     charting feature; there is nothing for it to report inside a backtest,
//     and a backtest run while replay is active is silently truncated instead.
//   - It works on any interval, any database, with or without a data feed.
//   - It reads data and draws. It places no orders and contacts no broker.

_SECTION_BEGIN( "Replay clock" );

ShowCandles    = ParamToggle( "Plot price in this pane", "No|Yes", 1 );
RefreshSeconds = Param( "Timed refresh (seconds, 0 = off)", 0, 0, 60, 1 );

// Bar Replay repaints the chart itself on every step, so a timed refresh is
// NOT needed to follow a replay. It is here only so that the same pane keeps a
// moving clock when it is watching a genuinely updating feed. Leave it at zero
// while you practise, and the pane costs nothing when nothing is happening.
if ( RefreshSeconds > 0 )
{
    RequestTimedRefresh( RefreshSeconds );
}

// GetPlaybackDateTime() returns the playback position as a DateTime number, or
// ZERO when Bar Replay is not active. Zero is a legal-looking number, so it has
// to be tested before it is formatted - printing it unguarded produces a date
// in 1899 and a reader who trusts it.
PlaybackPos  = GetPlaybackDateTime();
ReplayActive = PlaybackPos != 0;

// The last bar AFL can see. Under replay this is the playback position's bar;
// with replay off it is the last bar in the database.
LastBarTime  = LastValue( DateTime() );
LastBarClose = LastValue( Close );

BarSeconds   = Interval();          // bar size in seconds
BarSizeName  = Interval( 2 );       // "Daily", "5-minute", and so on

if ( ReplayActive )
{
    StateLine = "BAR REPLAY ACTIVE - playback position "
              + DateTimeToStr( PlaybackPos );
}
else
{
    StateLine = "Bar Replay is OFF - this chart shows the whole database";
}

// A one-line comparison of the two clocks that matter. When they disagree by
// months, you are practising. When they agree, you are not.
Title = Name() + "   " + BarSizeName + " bars (" + NumToStr( BarSeconds, 1.0 )
      + " s)\n"
      + StateLine + "\n"
      + "Last bar visible to AFL: " + DateTimeToStr( LastBarTime )
      + "   close " + NumToStr( LastBarClose, 1.4 ) + "\n"
      + "System clock: " + Now( 0 );

if ( ShowCandles )
{
    Plot( Close, "Close", colorDefault, styleCandle );
}

// A ribbon rather than a colour change alone: 1 while replay is driving the
// chart, 0 otherwise, with the value written in the pane's legend either way.
// GetPlaybackDateTime() returns a single number, so the flag has to be lifted
// to one value per bar before Plot() will take it.
ReplayRibbon = IIf( BarIndex() >= 0, ReplayActive, 0 );

Plot( ReplayRibbon, "Replay active (1) / off (0)", colorPaleBlue,
      styleArea | styleOwnScale | styleNoLabel, 0, 4 );

_SECTION_END();
