Skip to content
Level 5 · Real-Time AmiBroker UserLessonPart 22 · page 1 of 228 min Professional edition Live feed
28Minutes
6AFL functions
15Sources
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 here6

Quote Fields and the Real-Time Quote Window

A daily bar contains five numbers and every one of them is finished. A streaming quote contains two dozen and not one of them is finished: each is the most recent value that one vendor’s server thought was true at the moment it last sent your machine a message. Treating the second kind of number as though it were the first is the specific mistake this lesson exists to prevent.

By the end you should be able to name every quote field AmiBroker documents, say where each of them has to come from, predict which ones your particular data source will leave permanently empty, and write a formula that distinguishes a field that is fresh from one that is stale and from one that was never supplied at all.

Everything you have analysed so far in this course lives in the database: an array of bars, each with an open, high, low, close and volume, indexed by time. AmiBroker owns it, your formulas index into it, and a bar that closed an hour ago will still be there tomorrow.

Quote fields are a different kind of object entirely. They live in the data plugin, not in the database. There is exactly one value per field per symbol — the current one — and GetRTData() returns a single number, not an array. Nothing is stored, so nothing can be backfilled: there is no way to ask what the bid was twenty minutes ago, and no way to backtest against a field. If you want a history of bid prices you have to sample the field yourself on each refresh and accumulate it, which is a Part 23 exercise.

That difference has a practical consequence worth stating before anything else. A bar is evidence about a period that has ended. A quote field is a claim about now whose accuracy you cannot verify from inside AmiBroker, because AmiBroker is not the exchange. Everything that follows is really about learning to hold those two kinds of number differently.

The GetRTData() reference page lists the fields that a streaming source may report. It is a closed list — these are the names AmiBroker recognises, and there are no others.

Field name What the documentation says it holds
"Last" Last trade price
"TradeVolume" Last trade volume
"TotalVolume" Total today’s volume
"Bid" Current best bid price
"Ask" Current best ask price
"BidSize" Current bid size
"AskSize" Current ask size
"Open" Current day’s open price
"High" Current day’s high price
"Low" Current day’s low price
"Prev" Previous day close
"Change" Change since yesterday’s close
"OpenInt" Current open interest
"52WeekHigh" / "52WeekLow" The 52-week extremes
"52WeekHighDate" / "52WeekLowDate" The dates of those extremes, in datenum form
"EPS" Earnings per share
"Dividend" Last dividend value
"DivYield" Dividend yield
"Shares" Total number of shares
"ChangeDate" / "ChangeTime" Datenum and timenum of the last data change
"UpdateDate" / "UpdateTime" Datenum and timenum of the last data update

Four things about that list are worth noticing immediately, because each of them has tripped somebody up.

There is no "Close". The field you probably want is "Last", and the field you probably want when the market is shut is "Prev". There is no "Volume" either: "TotalVolume" is the running session total and "TradeVolume" is the size of the most recent print, and confusing the two produces a number several orders of magnitude wrong.

Nothing on the list exposes market depth. There is no documented AFL access to a level 2 book, to individual orders, or to the Time & Sales stream that the next lesson describes. "BidSize" and "AskSize" are the sizes at the best prices, and that is the whole of what AFL can see of the order book.

The date and time fields are not DateTime values. They come back in the datenum and timenum formats, so comparing them with Now(5) or with DateTime() without converting them first produces nonsense. DateTimeConvert() is the documented bridge.

Finally, the reference page prints "AskSize " and "BidSize " with a trailing space inside the quotation marks. The same paragraph also prints YYYMMDD where it plainly means an eight-digit date, so this reads as a typesetting slip rather than a real name. Write "AskSize". If your sizes never appear, the quote window will tell you whether the field name or your vendor is the problem — which is the subject of the next two sections.

Reading the list by where the number comes from

Section titled “Reading the list by where the number comes from”

The documentation gives you names and meanings but not provenance, and provenance is what determines which fields your feed will actually populate. Grouping them by where the number must physically originate is not something the manual does; it is an inference from what each field contains, and it is the most useful way to hold the list.

Quote-driven fieldsBid, Ask, BidSize, AskSize — come from the quotation stream: messages the venue publishes whenever the best prices or the displayed sizes change. In an active instrument these change far more often than trades occur. They exist only while a market is quoting, which is why they are the first fields to look empty outside trading hours.

Trade-driven fieldsLast, TradeVolume, and the running TotalVolume, High, Low, Open and Change — derive from the trade stream. Note that the session aggregates are somebody’s accumulation of that stream, and the interesting question is whose. The vendor usually accumulates them centrally; your plugin separately accumulates your bars. The two do not have to agree, and further down this page is the list of reasons they sometimes do not.

Reference fieldsPrev, OpenInt, Shares, and the two 52-week pairs — are not streamed continuously at all. They are values the vendor sets, typically once per session or once per day. A vendor that supplies excellent quote data may supply these badly or not at all, and there is no way to tell from within AFL other than looking.

Vendor-supplied company dataEPS, Dividend, DivYield — does not come from the exchange in any sense. It comes from whatever fundamental data set your vendor licenses, on their update schedule, with their definitions. Treat them as convenience fields rather than as a fundamental data source: AmiBroker handles fundamental data through a separate mechanism documented in its own chapter of the User’s Guide, and if these numbers are going to influence a decision they deserve a source you chose deliberately.

Housekeeping fieldsChangeDate, ChangeTime, UpdateDate, UpdateTime — are the feed talking about itself. They are the only fields on the list that tell you anything about the health of what you are looking at, which makes them disproportionately useful and disproportionately ignored.

Where a quote field comes from

  1. VenuePublishes quote and trade messages under its own rulesnot yours
  2. Vendor serversConsolidate, accumulate session totals, add reference and company dataentitlements apply
  3. Local vendor clientIQConnect, eSignal Data Manager, TWS — the program the plugin talks tomust be running
  4. AmiBroker data pluginMaps whatever arrives onto AmiBroker’s field names
  5. Quote window and GetRTData()Two consumers, refreshed at very different rates

The documentation states the practical rule plainly in Note 3 of the GetRTData() page: availability of data depends on the underlying data source, and the way to find out is to look at the Real-Time Quote window and see whether the field is populated. That is not a cop-out on AmiBroker’s part. AmiBroker cannot know what your vendor sends.

Three documented examples show how wide the variation is.

The DDE universal plugin makes the point most vividly, because with DDE you configure the mapping yourself. Its Configure dialog presents twelve entry boxes, one per field — Open, High, Low, Last, LastSize, Volume, Ask, AskSize, Bid, BidSize, Time and Req — and you fill in the DDE topic and item for each one according to your vendor’s documentation. Anything you do not map is not populated, and the guide is explicit that without setting the fields up for your specific vendor the plugin will not work at all. There is no backfill through DDE either, so a chart needs at least three bars of accumulated data before it appears.

Interactive Brokers shows a subtler limitation. The guide states that TWS streaming data is not tick-by-tick but 0.2 to 0.3 second snapshots. The fields are populated, but Last and TradeVolume are samples of a stream rather than the stream itself, and a formula that counts prints by watching TradeVolume change will undercount. This is a property of the source, not of AmiBroker, and no setting fixes it.

IQFeed is described in AmiBroker’s own vendor directory as an unfiltered feed, with the explicit note that you may therefore see a lot of bad ticks. That is a deliberate trade-off — nothing is suppressed — but it means the High and Low your database accumulates can be contaminated by prints that the vendor’s own session statistics may treat differently.

The bid and the ask are the two prices you can actually trade against right now, and Part 1 established why the gap between them is a cost rather than a detail. What the quote fields add is a size on each side, and size is where the over-reading starts.

BidSize and AskSize report the quantity displayed at the best bid and the best ask. Three qualifications matter, and the first two are properties of markets rather than of AmiBroker.

Displayed quantity is not committed intent. An order that is showing can be withdrawn at any moment before you reach it, and nothing obliges anyone to leave it there. A size you can see is an invitation, not a promise.

Displayed quantity is not all the quantity. Reserve and iceberg order types display a fraction of their true size in venues that support them, and volume that never rests in a public book at all does not appear in these fields under any circumstances. The next lesson returns to this, because it is the same problem that undermines tape reading.

And the two sizes are the fastest-changing numbers on the whole list. By the time a formula on a three-second refresh has read them, they have typically been superseded several times. Using them as a state — “there is a wall of buyers at this level” — asserts a persistence that the field does not have.

Day high, day low and day volume: the same name, two numbers

Section titled “Day high, day low and day volume: the same name, two numbers”

This is the section that catches experienced users, because the problem is invisible until you compare two things you assumed were identical.

GetRTData("High") is the vendor’s running session high, accumulated on their servers from the trade stream they saw, under their definition of the session. High in your AFL array is what your plugin accumulated into the current bar in your database, under the regular-trading-hours definition you set in Intraday Settings. There are at least five reasons those can differ, and every one of them turns up in practice.

A disconnection loses ticks. Your database has a gap; the vendor’s session total does not. After you reconnect the plugin will backfill bars, but the vendor’s running aggregate was never wrong in the first place, so the two converge only if the backfill is complete.

Bad ticks are filtered differently. An unfiltered feed puts an erroneous print straight into your bar high, and the vendor’s own session statistics may or may not include it. The documented remedy inside AmiBroker is Force backfill from the plugin’s status-area context menu, which re-downloads the intraday history in the hope that the vendor has since cleaned the data — the guide says this works well for eSignal, which it describes as genuinely fixing bad ticks after the event. Note what that implies: your bar high is a number that can change retrospectively, while the running session high you saw at the time cannot.

Session definitions differ. If your Intraday Settings restrict regular trading hours more narrowly than your vendor’s session, extended-hours prints will be inside their High and outside yours.

Corrections arrive late. Exchanges bust and adjust trades. A vendor may reflect that in their session aggregates; your already-written bar will not change unless you force a backfill.

And your database simply may not go back far enough or fine enough. TotalVolume is a number the vendor maintains; your session volume is a sum over the bars you happen to hold.

The Real-Time Quote window is a streaming watch list. The guide describes it as providing real-time streaming quotes and some basic fundamental data for the symbols you add to it, and the real-time data-plugin chapter gives the menu path: Window → Realtime Quote.

You populate it by double-clicking a symbol in the symbol tree, or through the right-click menu’s “Add to Real-Time Quote”. The window’s own context menu offers Time & Sales, Easy Alerts, Add Symbol, Add watchlist, Type-in symbols as a comma-separated list, Insert empty line as a separator for grouping, Remove Symbol, Remove All and Hide. From version 5.10 you can drag symbols to re-order the list.

Two properties make it the single most useful diagnostic surface in real-time AmiBroker.

It refreshes at least ten times per second — far more often than any chart formula — so it shows you the feed with the least interpretation in the way. And because it displays whatever the plugin reports, an empty column in the quote window is direct evidence that your vendor does not supply that field, which is exactly the check the GetRTData() documentation tells you to make before relying on a field in code.

Version 5.90 added a graphical column showing the direction of the ten most recent changes in bid and ask. The right-most box is the newest, and boxes shift left as new quotes arrive. If bid and ask do not change, no new box is added — and the documentation notes that the column works only when real-time quotes are actually streaming, which is to say when the market is open.

The colour scheme encodes six conditions. Since colour alone is a poor way to carry meaning, here they are as text.

Condition Colour
Bid rose or ask rose Dark green
Bid rose and ask rose Bright green
Bid fell or ask fell Dark red
Bid fell and ask fell Bright red
Ask fell and bid rose (the quote narrowed) Red/green box
Ask rose and bid fell (the quote widened) Green/red box

The last two rows are the interesting ones. A narrowing quote and a widening quote are genuinely informative about how willing the market is to trade at all, and they are the part of this column least likely to be misread as a direction signal.

The quote window is hard-capped. The plugin chapter states that AmiBroker will automatically rotate symbols in the Data Manager when you add more tickers than your subscription allows — dropping the least recently used, adding the new one, and backfilling — but that this rotation mechanism does not apply to the Real-Time Quote window, which cannot hold more symbols than your subscription limit. On top of that, the Standard edition limits the window to ten streaming symbols regardless of subscription.

The same chapter warns against exceeding your subscription significantly in the symbol tree either: it works, but it is asking your vendor’s servers to service a rotation cycle per new symbol, and vendors take a view on that.

This is the most common real-time complaint, and it is documented behaviour rather than a fault.

The quote window refreshes at least ten times a second. A chart formula sees a new value only when the pane re-executes, and by default AmiBroker refreshes charts in real-time mode every three seconds — a Preferences setting on the Intraday tab. So the bid in your panel is, on default settings, up to three seconds behind the bid in the quote window, every single time, by design.

You have three levers. You can lower the Preferences interval, which affects every chart. You can call RequestTimedRefresh() in the formula, which re-executes that pane on its own timer and works whether or not a plugin is attached. Or, on Professional only, you can set the intraday chart refresh interval to zero, which refreshes charts on every arriving trade — provided the formulas execute fast enough; when they do not, AmiBroker throttles itself to keep average CPU use below fifty per cent. The documentation is explicit that Standard will not accept a zero here.

Three failures look identical on screen — an empty or unchanging field — and have entirely different causes. Being able to tell them apart is most of what practical real-time troubleshooting consists of.

What you observe Likely cause How to confirm
A field is empty in the quote window for every symbol The vendor does not supply it Check the vendor’s field documentation; nothing in AmiBroker will change this
Fields are populated but frozen; no new bid/ask trend boxes The market is closed, or nothing is trading The trend column is documented as working only while quotes stream
The whole window stops; plugin status is red ERR or purple SHUT The connection is broken, or a required local client is not running The plugin status area, lower-right of the main window
The window is fine but GetRTData() returns nothing in AFL Standard edition, or no plugin on this database The edition table; GetRTData() returns Null for all fields on Standard
Your panel lags the window by a second or three Normal refresh asymmetry Compare against the Preferences refresh interval
Age or countdown values misbehave outside trading hours The plugin is not sending update timestamps Documented for IQFeed, which sends update timestamps only inside regular trading hours

Two documented traps deserve to be pulled out of that table.

Status("lastrtupdate") returns the time of the last update sent by the real-time plugin, and Status("lastbartimeleftrt") builds a countdown from it. Both depend on the plugin delivering correct update timestamps. The reference page names the failures directly: most data sources send odd, non-current timestamps at weekends, and the IQFeed plugin sends them only within regular trading hours. A staleness monitor built on these will misreport outside the session, and you should expect that rather than debug it.

And there is no documented sentinel for “no data”. The GetRTData() page says the function works only where the data source is a real-time plugin, and that Standard returns Null. It does not promise that a disconnected plugin returns zero, or the last close, or anything else. Write code that treats Null and zero alike as absent, and do not invent a rule the documentation does not state.

Build it: a panel that admits what it does not know

Section titled “Build it: a panel that admits what it does not know”

Goal. A chart pane that shows the quote fields for the selected symbol and labels every single row with where that number came from — the live feed, arithmetic on your own bars, or nowhere. It should be equally useful with a feed and without one, because the offline behaviour is what teaches you which fields have no substitute.

Complete formula.

Complete runnable AFL

quote-field-panel.afl
// Quote field panel
// Part 22 - "Quote Fields and the Real-Time Quote Window"
//
// Shows the documented real-time quote fields for the selected symbol and states,
// on every row, where that number came from: the streaming feed, or your own bars.
//
// ASSUMPTIONS - read these before trusting anything the panel prints:
//
// 1. GetRTData() is documented as PROFESSIONAL edition only. On the Standard
// edition it returns Null for every field without raising an error. On any
// database that is not fed by a streaming real-time plugin there is no field
// data for it to report at all.
// 2. The official documentation promises no particular value for the "nothing
// was supplied" case, so this formula treats Null and exact zero alike as
// absent rather than assuming a sentinel. A genuine zero bid size is rare,
// and printing "not supplied" for one is safer than printing a price of 0.00
// for a symbol whose feed has died.
// 3. The fallback numbers are computed from the bars already in your database.
// They are NOT quotes, and the panel labels them so you cannot confuse the
// two. Bid, ask and the two sizes have no bar-derived equivalent whatsoever,
// so they stay blank offline - which is itself the lesson.
// 4. Session boundaries are detected with Day(). That is correct for a database
// whose bar time stamps are already in the exchange's local time (Part 20).
_SECTION_BEGIN( "Quote field panel" );
RefreshSeconds = Param( "Refresh interval (seconds)", 5, 1, 60, 1 );
StaleLimit = Param( "Call the feed stale after (seconds)", 30, 5, 600, 5 );
ShowFallback = ParamToggle( "Show bar-derived fallback", "No|Yes", 1 );
// Re-executes this pane on a timer. Documented to work with or without a data
// plugin, which is what makes the offline behaviour of this panel testable.
RequestTimedRefresh( RefreshSeconds );
// ---------------------------------------------------------------- live fields
// Every string below appears verbatim in the documented GetRTData field list.
RtLast = GetRTData( "Last" );
RtBid = GetRTData( "Bid" );
RtAsk = GetRTData( "Ask" );
RtBidSize = GetRTData( "BidSize" );
RtAskSize = GetRTData( "AskSize" );
RtHigh = GetRTData( "High" );
RtLow = GetRTData( "Low" );
RtVolume = GetRTData( "TotalVolume" );
RtPrev = GetRTData( "Prev" );
function IsSupplied( FieldValue )
{
return NOT IsNull( FieldValue ) AND FieldValue != 0;
}
// One row of the panel. The suffix is the whole point: a reader must never have
// to guess whether a number on screen came from the market or from arithmetic.
function ResolveText( LiveValue, BarValue, Digits, AllowFallback )
{
if( IsSupplied( LiveValue ) )
{
RowText = NumToStr( LiveValue, Digits ) + " [live field]";
}
else
{
if( AllowFallback AND NOT IsNull( BarValue ) )
RowText = NumToStr( BarValue, Digits ) + " [from bars - not a quote]";
else
RowText = "not supplied";
}
return RowText;
}
// ------------------------------------------------------------- feed staleness
// Status("lastrtupdate") reports the time of the last update sent by the plugin.
// DateTime values may only be compared reliably with == and !=, so test against
// zero rather than asking whether it is "greater than" anything.
LastUpdate = Status( "lastrtupdate" );
if( LastUpdate != 0 )
{
AgeSeconds = DateTimeDiff( Now( 5 ), LastUpdate );
UpdateText = DateTimeToStr( LastUpdate );
if( AgeSeconds > StaleLimit )
StaleText = "STALE - " + NumToStr( AgeSeconds, 1.0 ) + " s since the plugin last spoke";
else
StaleText = "fresh - " + NumToStr( AgeSeconds, 1.0 ) + " s since the plugin last spoke";
}
else
{
AgeSeconds = -1;
UpdateText = "none reported";
StaleText = "unknown - no real-time update has been reported to this formula";
}
// --------------------------------------------------- bar-derived substitutes
// A running session high, low and volume, computed without looking forward.
NewSession = Day() != Ref( Day(), -1 );
SessionHigh = HighestSince( NewSession, High );
SessionLow = LowestSince( NewSession, Low );
CumVolume = Cum( Volume );
SessionVol = CumVolume - ValueWhen( NewSession, CumVolume - Volume );
BarLast = LastValue( Close );
BarHigh = LastValue( SessionHigh );
BarLow = LastValue( SessionLow );
BarVolume = LastValue( SessionVol );
BarPrev = LastValue( ValueWhen( NewSession, Ref( Close, -1 ) ) );
// ------------------------------------------------------------------- the rows
FeedLooksLive = IsSupplied( RtLast ) OR IsSupplied( RtBid );
LastText = ResolveText( RtLast, BarLast, 1.2, ShowFallback );
BidText = ResolveText( RtBid, Null, 1.2, ShowFallback );
AskText = ResolveText( RtAsk, Null, 1.2, ShowFallback );
BidSzText = ResolveText( RtBidSize, Null, 1.0, ShowFallback );
AskSzText = ResolveText( RtAskSize, Null, 1.0, ShowFallback );
HighText = ResolveText( RtHigh, BarHigh, 1.2, ShowFallback );
LowText = ResolveText( RtLow, BarLow, 1.2, ShowFallback );
PrevText = ResolveText( RtPrev, BarPrev, 1.2, ShowFallback );
VolText = ResolveText( RtVolume, BarVolume, 1.0, ShowFallback );
// A spread needs both sides. Half a spread is not a number worth printing.
if( IsSupplied( RtBid ) AND IsSupplied( RtAsk ) )
SpreadText = NumToStr( RtAsk - RtBid, 1.4 ) + " [live field]";
else
SpreadText = "cannot be computed - at least one side is missing";
// Bar Replay is the offline stand-in for a moving market, so say when it is on.
PlaybackAt = GetPlaybackDateTime();
if( PlaybackAt )
ReplayText = "Bar Replay : ACTIVE, playback position " + DateTimeToStr( PlaybackAt );
else
ReplayText = "Bar Replay : not active";
SourceText = WriteIf( FeedLooksLive,
"Streaming quote fields are being reported for this symbol.",
"NO LIVE QUOTE FIELDS. Anything below marked [from bars] is arithmetic on your database." );
// ------------------------------------------------------------------ the panel
Plot( Close, "Close", colorDefault, styleCandle );
Title =
"Quote field panel - " + Name() + " (" + Interval( 2 ) + " bars)\n" +
SourceText + "\n" +
"Plugin last update: " + UpdateText + "\n" +
"Staleness : " + StaleText + "\n" +
ReplayText + "\n" +
"\n" +
"Last : " + LastText + "\n" +
"Bid : " + BidText + " size " + BidSzText + "\n" +
"Ask : " + AskText + " size " + AskSzText + "\n" +
"Spread : " + SpreadText + "\n" +
"Day high : " + HighText + "\n" +
"Day low : " + LowText + "\n" +
"Prev close : " + PrevText + "\n" +
"Day volume : " + VolText;
_SECTION_END();

Download quote-field-panel.afl158 lines

How it works. The formula has four sections. It reads the nine most commonly used fields by their documented names. It then decides, per field, whether a value was actually supplied — treating Null and exact zero alike as absent, and explaining in a comment why it makes that conservative choice. It computes bar-derived substitutes for the fields that have one, using a running session high, low and volume built from Day() boundaries so that nothing looks forward. Finally it assembles a Title in which every row carries the suffix [live field], [from bars - not a quote] or not supplied.

The design decision that matters is what happens to bid, ask and the two sizes offline: they are passed Null as their fallback, so they print not supplied. That is deliberate. There is no honest way to reconstruct a bid from bars, and a panel that quietly showed you the close instead would be teaching the exact confusion this lesson is about.

Key functions. GetRTData() reads one named field for the selected symbol and returns a single number, not an array. Status("lastrtupdate") returns the plugin’s last update time as a DateTime; because DateTime values compare reliably only with == and !=, the formula tests it against zero rather than asking whether it is greater than anything. DateTimeDiff() converts the gap between that and Now(5) into seconds. RequestTimedRefresh() re-executes the pane on a timer whether or not a plugin exists, and GetPlaybackDateTime() returns the Bar Replay position, or zero when replay is not running — which is why the formula guards it before printing.

Expected result. With a streaming feed: a panel whose rows all read [live field], with a staleness of a few seconds at most during active trading, and a spread that changes as you watch. Without a feed: the same panel, with Last, day high, day low, previous close and day volume marked [from bars - not a quote], bid and ask and both sizes reading not supplied, and the staleness line reporting that no real-time update has been reported to the formula.

Test it. Two checks that would catch it being wrong. First, apply it to a symbol you know your vendor does not carry and confirm every row falls back rather than showing a stale value from the previously selected symbol. Second, disconnect the plugin from the status-area context menu with the market open and watch the staleness figure climb past your threshold — if it does not climb, your plugin is not reporting update timestamps and you have just learned something important about your feed.

Common errors. Setting the refresh interval to one second on a layout that already has several live panes, then blaming the panel for a sluggish machine. Reading "Volume", which is not a field name, instead of "TotalVolume". Comparing Status("lastrtupdate") with > — it is a bitset and only equality comparisons are documented as reliable. Expecting the bar-derived day volume to match the vendor’s TotalVolume, for all the reasons set out earlier on this page.

Extension. Add a second symbol to the panel using GetRTDataForeign(), which takes the field name and a ticker. The documentation states it is much faster than combining SetForeign() with GetRTData(), and Part 23 builds a multi-symbol dashboard on exactly that basis. Keep the fallback logic: a two-symbol panel that lies about one of them is worse than a one-symbol panel that does not.

Everything above can be learned without a subscription, and the formula was written with that in mind.

Run the panel on your end-of-day database now. It will report no live fields and fall back to bar arithmetic. That is not a degraded experience; it is the lesson made concrete. Look at which rows have substitutes and which do not, and notice that the four quote-driven fields are precisely the ones that cannot be reconstructed from any amount of historical data. That is the difference between a bar and a quote, visible on your own screen.

Use Bar Replay to make the fallback move. Bar Replay plays back data for all symbols at once at a user-defined speed, truncating everything past the playback position — so your running session high, low and volume update step by step exactly as they would in a live session, without your knowing what comes next. Press Play or Pause to enter playback mode; press Stop or close the window to restore the full data set. The panel’s Bar Replay line reports the playback position while it runs.

Understand staleness without a plugin. Set the panel’s stale threshold low and watch the staleness line report that no update has been received — which is exactly the state you would be in if a live plugin had silently died. A formula that behaves correctly in that state is a formula you can trust when it matters.

Check field availability the day you do get a feed. The one thing you genuinely cannot do offline is discover which fields your future vendor supplies. Note the procedure now: open the Real-Time Quote window, add a handful of symbols, and read the columns. Anything blank there will be blank in AFL, and no code will fix it.

A bar is a finished record and a quote field is an unfinished claim, and AmiBroker keeps them in different places for that reason. You now have the closed list of field names, the knowledge that Last rather than Close and TotalVolume rather than Volume are the ones you want, and a way of thinking about the list — quote-driven, trade-driven, reference, company, housekeeping — that predicts which fields a given vendor will leave empty.

You know that the Real-Time Quote window is the documented place to check field availability, that it refreshes ten times a second while your formula does not, and that it is capped by your subscription and by your edition. You know the five documented reasons a vendor’s session high can differ from your own bar high, and you have a panel that will never let you confuse a live number with a derived one.

The next lesson takes the same feed one level deeper, to the stream of individual prints — and asks a harder question: what, exactly, does that stream establish?

Check your understanding

Question 1. A formula reads `GetRTData("Volume")` and always gets nothing back. What is wrong?
DayVol = GetRTData( "Volume" );
Show the answer and why

Answer: "Volume" is not one of the documented field names

The documented names are "TotalVolume" for the running session total and "TradeVolume" for the size of the most recent print. There is no "Volume" field, so nothing can populate it. Reading the field list before writing the call is the whole defence here.

Question 2. Your panel shows a bid of 41.20 while the Real-Time Quote window shows 41.23 for the same symbol at the same moment. What has happened?
Show the answer and why

Answer: The quote window and the formula refresh at different rates, so they legitimately disagree

The quote window refreshes at least ten times per second; a chart formula sees a new value only when its pane re-executes, which by default happens every three seconds in real-time mode. A small disagreement at any instant is expected behaviour, not a fault.

Question 3. Which of these cannot be reconstructed, even approximately, from historical bars? Select all that apply.
Show the answer and why

Answer: Current best bid, Current ask size

Bars record trades, not quotations. A previous close and a running session high are both computable from bar data. A bid price and a displayed size at the top of the book leave no trace in a bar at all, which is why the panel prints "not supplied" for them offline rather than substituting something plausible.

Question 4. A staleness monitor built on Status("lastrtupdate") reports absurd ages every Saturday. What is the most likely explanation?
Show the answer and why

Answer: Many data sources send non-current timestamps when the market is closed, which the reference page documents

The Status reference notes that most data sources send odd, non-current datetime stamps at weekends, and that one major plugin sends update timestamps only inside regular trading hours. Expect it and handle it, rather than treating it as a bug in your formula.

Sources for this lesson

15 verified · checked 2026-08-31

  1. 01AmiBroker AFL Function Reference — GetRTDataamibroker.com/guide/afl/getrtdata.html2026-08-31
  2. 02AmiBroker AFL Function Reference — GetRTDataForeignamibroker.com/guide/afl/getrtdataforeign.html2026-08-31
  3. 03AmiBroker User's Guide — Real-time quote windowamibroker.com/guide/w_rtquote.html2026-08-31
  4. 04AmiBroker User's Guide — How to work with Real-Time data pluginsamibroker.com/guide/h_rtsource.html2026-08-31
  5. 05AmiBroker User's Guide — About AmiBroker Editionsamibroker.com/guide/versions.html2026-08-31
  6. 06AmiBroker User's Guide — Preferences§ Intraday tabamibroker.com/guide/w_preferences.html2026-08-31
  7. 07AmiBroker AFL Function Reference — Statusamibroker.com/guide/afl/status.html2026-08-31
  8. 08AmiBroker AFL Function Reference — RequestTimedRefreshamibroker.com/guide/afl/requesttimedrefresh.html2026-08-31
  9. 09AmiBroker AFL Function Reference — GetPlaybackDateTimeamibroker.com/guide/afl/getplaybackdatetime.html2026-08-31
  10. 10AmiBroker AFL Function Reference — DateTimeConvertamibroker.com/guide/afl/datetimeconvert.html2026-08-31
  11. 11AmiBroker User's Guide — Multi-threadingamibroker.com/guide/h_multithreading.html2026-08-31
  12. 12AmiBroker User's Guide — How to use AmiBroker with DDE dataamibroker.com/guide/h_dde.html2026-08-31
  13. 13AmiBroker User's Guide — How to use AmiBroker with Interactive Brokersamibroker.com/guide/h_ib.html2026-08-31
  14. 14AmiBroker User's Guide — How to get quotes from various markets§ Page is self-dated 2 March 2023amibroker.com/guide/h_quotes.html2026-08-31
  15. 15AmiBroker User's Guide — Bar Replay windowamibroker.com/guide/w_barreplay.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.