Skip to content
Level 5 · Real-Time AmiBroker UserChallengePart 21 · page 4 of 435 min Professional edition Live feed
35Minutes
10AFL functions
10Sources
Professional + live feedRequires

This page needs the Professional edition and a real-time data feed. Every gated part of this course ships a Level A path that uses Bar Replay and historical data instead — look for it below.

AFL functions taught here10

Challenge: The Chart That Stopped Updating

A frozen chart is the only fault in this whole course that is dangerous because it is quiet. Everything else announces itself: a formula error prints in the pane, a bad import shows up as a spike, a broken backtest produces absurd numbers. A stopped feed produces a chart that looks completely normal and is simply no longer true.

This challenge gives you a scenario, the list of evidence AmiBroker actually exposes, and a task. Work it before reading the solution. What you take away is a procedure you can run in ninety seconds, and a monitor formula that makes the whole procedure unnecessary next time.

The scenario and every observation in it are constructed for teaching. No quote values appear anywhere, and none of the times below are measurements from a real session.

You are running the three-window layout from the previous lab against a live feed. Everything was normal at the open. It is now the middle of the session, and you notice something is wrong when your own status strip says the newest bar was stamped an hour ago while the clock on the same line says the current time. The 5-minute chart shows a flat, unmoving last bar. The daily context window looks fine, because on a daily chart nothing is expected to change intraday anyway.

  • The price pane has not drawn a new bar for what feels like a long time.
  • The repaint counter in the status strip is still climbing.
  • The countdown to bar completion has gone negative, or is stuck.
  • The volume pane’s last bar is unchanged.
  • No error message appears anywhere. Nothing has crashed.
  • Another symbol on a different window shows the same behaviour, though you are not yet sure whether you checked carefully enough.
Section titled “The one distinction that organises the whole search”

Everything in this part has been building to a single decision at the top of the tree: has the paint clock stopped, or has the data clock stopped? Those two branches share almost no causes and almost no fixes, and answering the question first removes most of the search space.

First branch: which clock stopped?

  1. Is the pane still executing?Repaint counter climbing, or title clock advancing
  2. No → the PAINT clock stoppedWindow minimised, pane on an inactive sheet, refresh disabled, load factor extreme, formula erroring
  3. Yes → the DATA clock stoppedFeed, plugin, subscription, session, filtering, or replay
  4. Then: is it every symbol, or one?The Real-Time Quote window answers this in seconds
Answer the first question before collecting any other evidence.

This is the complete list of what you can inspect. Nothing here is invented, and where the documentation is thin or inconsistent that is stated rather than papered over.

The plugin status area, lower right of the main window. The documented states are OK (green light) for a healthy connection; WAIT (yellow) while a connection is being set up or when the plugin is connected to only some of several servers, usually transient; ERR (red) for a broken connection — bad username or password, or a required third-party component not running — which recovers automatically once the cause is fixed; and SHUT (purple) for a serious problem after which the plugin will not attempt to reconnect at all. On any change AmiBroker beeps and shows a bubble tooltip with more detail, which auto-hides after two seconds; hover over the area to bring it back.

The plugin context menu, from right-clicking that status area. Plugins differ, but most offer at least Reconnect, Shutdown (Disconnect) and Force backfill. For the eSignal plugin the troubleshooting chapter names an additional “Fixup data for symbol” item that re-downloads a symbol’s whole intraday history.

The status-bar performance indicator, rightmost. For real-time databases this shows a percentage load factor; for offline, intraday and end-of-day databases it shows free virtual memory instead. Which of the two you are looking at is itself diagnostic: a load factor means AmiBroker considers this a real-time database. Above 100% a warning tooltip appears once, saying what the cause is; above 300% it reappears every minute.

The Real-Time Quote window (Window → Realtime Quote). Documented as refreshing at least ten times per second, which makes it far more responsive than any chart. If quotes move here and not on your chart, the feed is fine and the problem is downstream. Since version 5.90 it also carries a Bid/Ask Trend column showing the direction of the ten most recent bid and ask changes — and the documentation notes explicitly that this column works only while real-time quotes are streaming, which is precisely the signal you want.

The Time & Sales window, from the quote window’s right-click menu. Every bid, ask and trade arrives as a row. Since 5.30 it shows recent statistics including the number of trades and the average trades per second, resettable from its own Reset Stats menu item. The statistics cover only what has been displayed since the window was opened or last reset — they are not a session total. Note the edition limit: Standard is restricted to one Time & Sales window, Professional to an unlimited number.

The Quote Editor. It is documented as showing every bar, and as the exception to intraday filtering — so if bars are present here but absent from the chart, the cause is filtering rather than a missing feed. Two limits apply on a plugin-fed database: you can edit one-minute and higher intervals only, only for fully backfilled symbols, and never the last three bars, because those are cached inside the plugin.

The Information window for the symbol. The ASCII importer marks symbols it adds that were not already in the database with “use only local database for this symbol”, which excludes them from real-time updates. That flag is visible here, and it is a genuine documented reason for exactly one symbol never updating while everything else is fine.

Tools → Preferences → Miscellaneous carries a “Display plugin activity” option. The Preferences chapter names the setting but does not describe what it displays, so treat it as something to switch on and look at rather than something this course can tell you the output of.

The Bar Replay dialog. Bar Replay truncates data for all symbols at the playback position and affects charts and Analysis alike, and PAUSE is a fully active state rather than a neutral one. A forgotten replay session is indistinguishable from a frozen feed by eye.

What you want to know How to ask
Is this pane still executing? A counter in a static variable, incremented each execution
What triggered this execution? Status("redrawaction") — 0 regular, 1 timer
When did the plugin last send anything? Status("lastrtupdate")
When does the newest bar end? Status("lastbarend") — time-based bars only
How long has the forming bar to run? Status("lastbartimeleft"), or Status("lastbartimeleftrt") to measure against the stream rather than the PC clock
Is the database time shift what I think? Status("timeshift"), in seconds
Is Bar Replay running? GetPlaybackDateTime() — non-zero means yes
How stale is that? DateTimeDiff( Now(5), stamp )

Two further cautions about Status("lastrtupdate"), both documented on the function page. It depends entirely on the plugin sending correct update timestamps: most data sources send non-current stamps at weekends, and the IQFeed plugin sends them only inside regular trading hours. A staleness monitor built on it will therefore shout, correctly and pointlessly, every evening.

Work these out before reading on. Write your answers down; the discipline of committing to an order is most of the value.

  1. Order the evidence. List the checks you would make, in sequence, and for each one say what result would send you down which branch. Aim for a procedure that reaches a conclusion in five or six observations, not twenty.
  2. Name the single observation that separates “the whole feed has stopped” from “this one symbol has stopped”.
  3. Name the observation that separates “the data really has stopped” from “the data is fine and the chart is not repainting”.
  4. Predict: if the plugin status area reads SHUT, what will happen if you do nothing for another hour? What if it reads ERR?
  5. Design the check you would rather not have to run at all — that is, decide what a permanent monitor would need to measure, which reference clock it would compare against, and what it should say when it has nothing to measure.

Hint 1. You already built the instrument that answers question 3 in the previous lesson, and you have been looking at it the whole time. What does a climbing repaint counter beside a frozen bar timestamp rule out?

Hint 2. Two windows in AmiBroker refresh far faster than any chart, and one of them is documented as refreshing at least ten times per second. Neither of them cares about your formulas. If they are moving and your chart is not, you have already halved the problem.

Hint 3. The four connection states are not equivalent. Two of them recover without you. One of them explicitly does not, and it is the one that produces exactly these symptoms: a chart that kept repainting for an hour while no quote arrived.

The repaint counter is climbing, so the pane is executing and redrawing. That single observation eliminates the entire paint-clock branch: not a minimised window, not an inactive sheet, not a refresh setting, not a load factor so extreme that redraws have stalled, not a formula error. The fault is on the data side.

Two seconds of evidence removed half the tree. This is why the counter belongs in the layout permanently.

Open the Real-Time Quote window and look at several symbols, and check whether the Bid/Ask Trend column is producing new boxes. In this scenario nothing moves anywhere, and no new boxes appear. So it is not the documented symbol-rotation behaviour, where adding more tickers than your subscription allows causes AmiBroker to keep the most recently used symbols active and drop older ones from the Data Manager. It is not one symbol; it is the connection.

Had a single symbol been frozen while others updated, the branch would have been quite different: subscription limits, the “use only local database for this symbol” flag in the Information window, or a symbol that simply has not traded.

Before blaming software, confirm the market is open and that you are looking at a session your intraday settings display. Filtering hides data rather than deleting it, so the Quote Editor settles this immediately: bars present in the editor but missing from the chart mean filtering, not a feed failure. In this scenario the newest bar in the editor matches the newest bar on the chart, so nothing is being hidden.

GetPlaybackDateTime() returns zero, and the status strip is pale blue rather than orange. Bar Replay is not running. This check is trivially cheap and catches an embarrassing failure mode, so it goes early rather than late.

The status area reads SHUT in purple. That is the answer. SHUT is documented as a serious problem after which the plugin will not attempt to reconnect automatically — so the prediction in task 4 is that another hour of doing nothing produces another hour of a repainting chart with no data. Had it read ERR, the plugin would reconnect by itself once the underlying cause was fixed, so the correct action there is to fix the cause — credentials, or a third-party component that is not running — rather than to click anything.

Right-click the status area and choose Reconnect. The troubleshooting chapter’s documented sequence for a disconnection is Disconnect and then Connect, and if that does not help, restart AmiBroker.

Reconnecting resumes the stream. It does not necessarily fill the hole. Normally the plugin detects missing quotes between the last available bar and the current time and backfills by itself. If a gap remains, Force backfill from the same context menu re-downloads the entire intraday history for the symbol. Remember two documented details while you do it: forcing a backfill is also the right response after enlarging “number of bars to load”, and the last three bars of an intraday symbol cannot be hand-edited in the Quote Editor because the plugin caches them — so do not try to patch the gap manually.

The connection dropped into a state the plugin does not recover from on its own, and nothing in the charting layer noticed, because the charting layer’s job is to draw the array it is given. AmiBroker did signal the change — it beeped and popped a bubble tooltip — but the tooltip auto-hides after two seconds, and a beep during a working session is easy to attribute to something else.

The deeper cause is structural, and it is the reason this challenge exists: the layout had no instrument that measured data freshness. Everything on screen measured either price or the health of the drawing code. Nothing measured the gap between now and the last time anything arrived. That is a gap you close once, in a formula, and never think about again.

One pane, in every layout, that answers “how long since data last moved?” continuously; that says UNKNOWN rather than FRESH when it has nothing to measure; that works with a plugin, without a plugin and under Bar Replay; and that can raise exactly one alert on the transition into staleness rather than one per refresh.

Complete runnable AFL

stale-data-monitor.afl
_SECTION_BEGIN( "Stale data monitor" );
/* Stale data monitor - Part 21, Real-Time Charts.
WHAT IT DOES
Answers one question, continuously and visibly: how long has it been
since data last moved? It reports FRESH, STALE or UNKNOWN, shows the
age in seconds, names which clock and which data stamp it used, and
can raise one alert on the transition into staleness.
WHY "UNKNOWN" IS A STATE
A monitor that says FRESH when it has nothing to measure is worse
than no monitor. If neither a plugin update stamp nor a time-based
bar end is available, this formula says so instead of guessing.
WHICH CLOCK, WHICH STAMP
Reference clock:
Bar Replay position when replay is active, otherwise Now( 5 ).
Data stamp, in order of preference:
1. Status( "lastrtupdate" ) - the plugin's own last-update time.
Preferred, because it moves on every update rather than once
per bar. Not used during Bar Replay, where the playback clock
and the live plugin clock are unrelated.
2. Status( "lastbarend" ) - the end of the newest bar. Available
on any time-based interval with or without a feed, which is
what makes this formula work at Level A.
ASSUMPTIONS AND LIMITS - read before relying on it
- A bar-end age is naturally as old as one bar, so when the bar end
is the stamp the tolerance has one whole interval added to it. A
plugin stamp gets no such allowance.
- Status( "lastrtupdate" ) depends on the plugin sending correct
update timestamps. The documentation warns that most sources send
non-current stamps at weekends and that the IQFeed plugin sends
them only inside regular trading hours. Outside those hours this
monitor will report STALE, correctly and uselessly.
- Status( "lastbarend" ) and the countdown need the database time
shift set correctly, and work on time-based bars only.
- Now( 5 ) is the PC clock. A wrong PC clock produces a wrong age.
- DateTime values are compared with == and != only; ordering goes
through DateTimeDiff().
- Alerts from a custom indicator reach the Alert Output window only
if Tools -> Preferences -> Alerts has "custom indicators" ticked
under "Enable alerts from".
- This detects that data stopped. It cannot tell you why, and no AFL
function reports the plugin connection status.
*/
ToleranceSeconds = Param( "Stale after (seconds)", 90, 5, 3600, 5 );
RefreshSeconds = Param( "Check every (seconds)", 2, 1, 60, 1 );
RaiseAlert = ParamToggle( "Alert on going stale", "No|Yes", 0 );
// False so the monitor keeps checking while the main window is minimised.
RequestTimedRefresh( RefreshSeconds, False );
Playback = GetPlaybackDateTime(); // zero when Bar Replay is inactive
RtUpdate = Nz( Status( "lastrtupdate" ) );
BarEnd = Nz( Status( "lastbarend" ) );
BarSecs = Interval( 0 );
if( Playback != 0 )
{
RefNow = Playback;
ClockText = "Bar Replay position";
}
else
{
RefNow = Now( 5 );
ClockText = "system clock";
}
UsingBarEnd = False;
if( RtUpdate != 0 AND Playback == 0 )
{
LastData = RtUpdate;
StampText = "plugin update stamp";
}
else
{
if( BarEnd != 0 AND BarSecs > 0 )
{
LastData = BarEnd;
StampText = "end of newest bar";
UsingBarEnd = True;
}
else
{
LastData = 0;
StampText = "none available";
}
}
// A bar-end stamp only moves once per bar, so allow one whole interval.
if( UsingBarEnd )
Allowance = BarSecs + ToleranceSeconds;
else
Allowance = ToleranceSeconds;
if( LastData == 0 )
{
AgeSeconds = 0;
StateText = "UNKNOWN";
StateColor = colorLightGrey;
AgeText = "nothing to measure";
}
else
{
AgeSeconds = DateTimeDiff( RefNow, LastData );
AgeText = NumToStr( AgeSeconds, 1.0 ) + " s since last movement, tolerance "
+ NumToStr( Allowance, 1.0 ) + " s";
if( AgeSeconds > Allowance )
{
StateText = "STALE";
StateColor = colorRose;
}
else
{
StateText = "FRESH";
StateColor = colorPaleGreen;
}
}
// One alert on the transition into staleness, not one per refresh.
// The state is kept per symbol and per pane, so two panes do not fight.
StateKey = "p21_stalestate_" + Name() + "_" + NumToStr( GetChartID(), 1.0, False );
WasStale = Nz( StaticVarGet( StateKey ) );
IsStale = StateText == "STALE";
if( RaiseAlert AND IsStale AND WasStale == 0 )
{
LastBarOnly = BarIndex() == LastValue( BarIndex() );
// Flags 1 + 2 only: write to the Alert Output window and beep. The
// built-in repeat suppression (flags 4 and 8) is deliberately left off,
// because the static variable above already does that job and does it
// per pane rather than per symbol.
AlertIf( LastBarOnly, "", "Data for " + Name() + " has not moved for "
+ NumToStr( AgeSeconds, 1.0 ) + " seconds", 8, 1 + 2 );
}
StaticVarSet( StateKey, IsStale );
SetChartOptions( 2, chartWrapTitle );
SetChartBkColor( StateColor );
Title =
EncodeColor( colorBlack ) + "DATA " + StateText + " | " + Name()
+ " | " + Interval( 2 ) + "\n"
+ AgeText + "\n"
+ "Clock: " + ClockText + " | Stamp: " + StampText;
_SECTION_END();

Download stale-data-monitor.afl154 lines

The formula chooses a reference clock and a data stamp, subtracts, and compares against a tolerance. Each of those four steps has a decision in it.

Reference clock. If GetPlaybackDateTime() is non-zero, Bar Replay is active and the playback position is the only sensible “now” — comparing replayed bars against your wristwatch would report years of staleness. Otherwise the reference is Now(5), the PC clock.

Data stamp, in order of preference. Status("lastrtupdate") is used when a plugin stamp exists and replay is not running, because it moves on every update rather than once per bar. Otherwise the formula falls back to Status("lastbarend"), the end of the newest bar, which exists on any time-based interval with or without a feed. That fallback is what makes this formula work at Level A, and it is a deliberate design choice rather than a degradation.

Tolerance. A bar-end stamp only moves once per bar, so when the fallback is in use the tolerance has one whole interval added to it via Interval(0). Without that adjustment a 15-minute chart would report STALE for fourteen minutes out of every fifteen. A plugin stamp gets no such allowance, because it should move continuously.

Three states, not two. If neither stamp is available — a tick chart with no plugin, for instance, where Status("lastbarend") is documented as not working — the formula reports UNKNOWN. A monitor that reports FRESH when it has nothing to measure is worse than no monitor at all, because you will believe it.

The alert is gated twice. AlertIf is called only on the transition from not-stale to stale, tracked in a static variable keyed by symbol and chart ID, and it is called with flags 1 + 2 only — write to the Alert Output window and beep — deliberately dropping the built-in repeat suppression flags 4 and 8, because the static variable already does that job and does it per pane rather than per symbol. The type argument is 8, a value outside the predefined buy/sell/short/ cover set, so this alert cannot collide with the de-duplication state of a trading alert on the same symbol.

  • Status("lastrtupdate") — the date and time of the last update sent by the real-time plugin.
  • Status("lastbarend") — the end time of the newest bar. A 5-minute bar at 09:00 ends at 09:04:59. Time-based bars only.
  • DateTimeDiff( a, b ) — the difference in seconds, positive when a is later. It exists because DateTime values are a bitset and ordinary > and < comparisons on them are documented as unreliable.
  • AlertIf( condition, command, text, type, flags, lookback ) — with an empty command it writes to the Alert Output window. Flag 1 displays the text, 2 beeps, 4 suppresses repeats of the same type and 8 suppresses repeats with the same timestamp.
  • SetChartBkColor( color ) — the pane background, used here as a second channel alongside the word FRESH, STALE or UNKNOWN so nothing depends on colour alone.

A pale green pane reading DATA FRESH, the age in seconds, the tolerance being applied, and which clock and which stamp were used. When data stops for longer than the tolerance the pane turns pale rose and reads DATA STALE, and — if alerting is enabled — one line appears in the Alert Output window and one beep sounds. When data resumes the pane returns to green and re-arms itself for the next episode.

You do not need a feed failure to test it, which is the point.

  1. Provoke staleness deliberately. Set the tolerance to 5 seconds on a database with no feed attached. The pane should go STALE within a few seconds and stay there. That proves the detection path.
  2. Provoke the reverse. Start Bar Replay at speed 1 with a step interval equal to your base interval. The stamp switches to the replay clock and the pane should read FRESH while playback runs, then go STALE within the tolerance after you press PAUSE. That proves the replay path and the re-arming.
  3. Check the alert fires once. Enable alerting, let it go stale, and count the lines in Window → Alert Output. There should be exactly one per episode, not one per refresh. If there are none at all, check that Tools → Preferences → Alerts has “custom indicators” ticked under “Enable alerts from” — alerts from indicators are disabled there independently of your code.
  4. Check the UNKNOWN path. Switch a pane to a tick interval, where Status("lastbarend") is documented as unavailable, and confirm the monitor reports UNKNOWN rather than a number.
  • Believing it outside trading hours. Documented behaviour: most sources send non-current timestamps at weekends, and the IQFeed plugin sends update stamps only inside regular trading hours. The monitor will report STALE overnight, correctly and uselessly. Either accept that or gate the alert on a session filter — Part 20 has the machinery.
  • A tolerance shorter than the interval, with the bar-end fallback in use. The formula adds one interval automatically, but if you then set the tolerance to 5 seconds on a 15-minute chart you are asking for an alarm every bar.
  • A wrong PC clock or a wrong time shift. Both produce a confident, wrong age. The two-clock panel from the previous lesson prints the shift; check it before you trust any number here.
  • Reading STALE as “the connection is down”. It means data stopped. The connection status lives in the status area, and no AFL function reports it.

Record the longest stale episode of the session in a second static variable and display it, so that at the close you know whether you had one interruption or eleven. A second, larger tolerance that switches the pane’s text to a stronger wording is easy to add, and more useful than an alert that fires twice.

Every diagnostic step above except reading the plugin status area can be practised at Level A, and the monitor itself is fully functional without a subscription.

  • Reproduce the fault deliberately. On an intraday database of historical bars, start Bar Replay and press PAUSE. Data now stops while the paint clock continues — which is exactly the scenario, produced on demand. Run your procedure against it: repaint counter climbing, bar timestamp frozen, and this time GetPlaybackDateTime() non-zero, which is the observation that identifies replay as the cause.
  • Practise the discrimination. Alternate PLAY and PAUSE and watch the monitor move between FRESH and STALE. Time how long it takes you to name the cause from the evidence rather than from memory of having pressed PAUSE.
  • Learn the connection table anyway. OK, WAIT, ERR, SHUT — and the single fact that matters most: SHUT never reconnects by itself.

Diagnose a frozen chart by asking which clock stopped, because that single answer eliminates half the possible causes. Then decide whether it is one symbol or everything, using the Real-Time Quote window and its Bid/Ask Trend column, which are far more responsive than any chart. Then rule out the cheap and embarrassing causes — session, filtering, Bar Replay — before reading the connection state, where ERR recovers by itself and SHUT never does. Recover with Reconnect, and repair the gap with Force backfill rather than by hand.

Then make the procedure unnecessary. The monitor measures the gap between a reference clock and the last time data moved, prefers the plugin’s own stamp when there is one, falls back to the newest bar’s end when there is not, allows a whole interval for that fallback, reports UNKNOWN when it has nothing to measure, and raises one alert per episode. It works with a feed, without a feed and under replay, and it costs one thin pane.

Check your understanding

Question 1. A pane’s repaint counter is climbing and the newest bar timestamp has not changed for forty minutes. Which causes have you just eliminated? Select all that apply.
Show the answer and why

Answer: The main window is minimised with onlyvisible left at True, The pane is on an inactive chart sheet, A run-time error is stopping the formula from completing

A climbing counter proves the pane executes and repaints, so every paint-clock cause is out. A dropped connection is entirely consistent with what you observed — it is on the other branch, and is now more likely rather than less.

Question 2. Why does the monitor add one whole chart interval to the tolerance when it is using Status("lastbarend") rather than the plugin stamp?
Show the answer and why

Answer: Because a bar-end stamp only advances once per bar, so an age approaching one interval is normal rather than a fault

The bar-end stamp moves once per bar by construction. Without the allowance, a 15-minute chart would spend almost every minute of every bar reporting STALE. A plugin update stamp moves continuously, so it gets no allowance.

Question 3. The plugin status area reads ERR in red. What is the documented behaviour?
Show the answer and why

Answer: The connection is broken — for example bad credentials or a required third-party component not running — and the plugin will reconnect automatically once the cause is fixed

ERR means a broken connection with a cause you must remove, after which the plugin retries by itself. SHUT is the state that will not retry and needs a manual reconnection or a restart. Confusing the two leads to unnecessary restarts in one case and an hour of stale data in the other.

Question 4. Which of these can a chart formula determine on its own?
Show the answer and why

Answer: How long it has been since the plugin last sent an update

Status("lastrtupdate") reports the time of the last plugin update, so elapsed time is computable. The connection state is a user-interface display with no AFL equivalent, AlertIf returns nothing, and backfill is a context-menu action. Building tools that respect that boundary is what keeps a monitor honest.

Sources for this lesson

10 verified · checked 2026-08-31

  1. 01AmiBroker User's Guide — How to work with real-time data plugins§ Connection status displayamibroker.com/guide/h_rtsource.html2026-08-31
  2. 02AmiBroker User's Guide — Troubleshooting guideamibroker.com/guide/x_troubleshoot.html2026-08-31
  3. 03AmiBroker User's Guide — Performance tuning tips§ Performance monitoringamibroker.com/guide/x_performance.html2026-08-31
  4. 04AmiBroker User's Guide — Real-time quote windowamibroker.com/guide/w_rtquote.html2026-08-31
  5. 05AmiBroker User's Guide — Time and Sales windowamibroker.com/guide/w_timesales.html2026-08-31
  6. 06AmiBroker User's Guide — Bar Replayamibroker.com/guide/w_barreplay.html2026-08-31
  7. 07AFL Function Reference — Statusamibroker.com/guide/afl/status.html2026-08-31
  8. 08AFL Function Reference — AlertIfamibroker.com/guide/afl/alertif.html2026-08-31
  9. 09AmiBroker User's Guide — Using formula-based alertsamibroker.com/guide/h_alerts.html2026-08-31
  10. 10AFL Function Reference — DateTimeDiffamibroker.com/guide/afl/datetimediff.html2026-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.