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
Section titled “The scenario”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.
Symptoms
Section titled “Symptoms”- 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.
The one distinction that organises the whole search
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?
- Is the pane still executing?Repaint counter climbing, or title clock advancing
- No → the PAINT clock stoppedWindow minimised, pane on an inactive sheet, refresh disabled, load factor extreme, formula erroring
- Yes → the DATA clock stoppedFeed, plugin, subscription, session, filtering, or replay
- Then: is it every symbol, or one?The Real-Time Quote window answers this in seconds
The evidence AmiBroker actually exposes
Section titled “The evidence AmiBroker actually exposes”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.
In the interface
Section titled “In the interface”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.
From AFL
Section titled “From AFL”| 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.
The task
Section titled “The task”Work these out before reading on. Write your answers down; the discipline of committing to an order is most of the value.
- 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.
- Name the single observation that separates “the whole feed has stopped” from “this one symbol has stopped”.
- Name the observation that separates “the data really has stopped” from “the data is fine and the chart is not repainting”.
- Predict: if the plugin status area reads SHUT, what will happen if you do nothing for another hour? What if it reads ERR?
- 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.
Solution
Section titled “Solution”Step 1: which clock stopped
Section titled “Step 1: which clock stopped”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.
Step 2: everything, or one symbol
Section titled “Step 2: everything, or one symbol”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.
Step 3: is it the session
Section titled “Step 3: is it the session”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.
Step 4: is it replay
Section titled “Step 4: is it replay”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.
Step 5: read the connection state
Section titled “Step 5: read the connection state”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.
Step 6: recover, then repair the gap
Section titled “Step 6: recover, then repair the gap”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.
Root cause
Section titled “Root cause”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.
A stale-data monitor you can keep
Section titled “A stale-data monitor you can keep”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 formula
Section titled “Complete formula”Complete runnable 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 inactiveRtUpdate = 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();How it works
Section titled “How it works”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.
Key functions
Section titled “Key functions”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 whenais 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.
Expected result
Section titled “Expected result”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.
Test it
Section titled “Test it”You do not need a feed failure to test it, which is the point.
- 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.
- 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.
- 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 thatTools → Preferences → Alertshas “custom indicators” ticked under “Enable alerts from” — alerts from indicators are disabled there independently of your code. - 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.
Common errors
Section titled “Common errors”- 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.
Extension
Section titled “Extension”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.
If you have no live feed
Section titled “If you have no live feed”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
Sources for this lesson
10 verified · checked 2026-08-31
- 01AmiBroker User's Guide — How to work with real-time data plugins§ Connection status displayamibroker.com/guide/h_rtsource.html2026-08-31
- 02AmiBroker User's Guide — Troubleshooting guideamibroker.com/guide/x_troubleshoot.html2026-08-31
- 03AmiBroker User's Guide — Performance tuning tips§ Performance monitoringamibroker.com/guide/x_performance.html2026-08-31
- 04AmiBroker User's Guide — Real-time quote windowamibroker.com/guide/w_rtquote.html2026-08-31
- 05AmiBroker User's Guide — Time and Sales windowamibroker.com/guide/w_timesales.html2026-08-31
- 06AmiBroker User's Guide — Bar Replayamibroker.com/guide/w_barreplay.html2026-08-31
- 07AFL Function Reference — Statusamibroker.com/guide/afl/status.html2026-08-31
- 08AFL Function Reference — AlertIfamibroker.com/guide/afl/alertif.html2026-08-31
- 09AmiBroker User's Guide — Using formula-based alertsamibroker.com/guide/h_alerts.html2026-08-31
- 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.