Lab: Build an Intraday Market Database
By the end of this lab you will have an intraday database you can defend line by line: a base interval you chose for a stated reason, settings you understand, real bars in it, and three verification passes that prove what is actually there.
There are two routes. Route A uses a real-time plug-in and needs a subscription. Route B builds the same thing from historical intraday files and needs nothing beyond AmiBroker and one CSV file. Route B is not a lesser version: it produces a genuine intraday database with the same base interval, the same settings, the same session behaviour and the same maintenance problems. Everything after the “Verify” heading applies to both.
Before you start: three decisions, written down
Section titled “Before you start: three decisions, written down”Open the text file you started in Part 3 and answer these before you touch a dialog. Guessing here is what the whole part has been arguing against.
- What is the finest measurement your rules will make? Not the finest chart you might look at. If the answer is “the first one-minute close beyond the opening range”, your base interval is 1-minute. If it is “the fifteen-minute trend”, 5-minute is ample and costs a fifth of the storage.
- How many symbols, and which ones? An intraday database should be small and deliberate. Ten to forty instruments you actually watch. Not a market.
- How much history do you need, in sessions? Say the number. “Sixty sessions” is a plan; “as much as possible” is how databases end up at 2 GB and too slow to work in.
Route A: a plug-in-fed intraday database
Section titled “Route A: a plug-in-fed intraday database”Follow this only if you have a working subscription and the vendor’s client software installed and connected. Otherwise skip to Route B.
A1. Create the database. File → New → Database. Type or browse to a new
folder — put it outside the AmiBroker program folder so that reinstalling never
touches it — and click Create. The Data source half of the dialog becomes
usable only after you click Create.
A2. Choose the data source. Pick your plug-in from the Data source combo. The list printed in the User’s Guide is dated and omits several real plug-ins, so trust the combo in front of you rather than any list.
A3. Local data storage: Enable. Documented as required for most real-time sources, and it is what makes the bars persist between sessions.
A4. Base time interval. Set it to the value you decided above. This is the decision this part exists for. On the Standard edition your floor is 1-minute; tick and N-second intervals require Professional.
A5. Number of bars to load. Take your target session count, multiply by a realistic bars-per-session figure for your feed, add about twenty per cent, and enter that. Then read the days-equivalent AmiBroker prints beside the field. If it disagrees with your target, one of your assumptions is wrong — find out which before continuing.
A6. Intraday settings. Set the filtering mode and the day-session trading
hours in your own local time zone, set the time shift if your bar timestamps
need moving, and decide about Allow mixed EOD/Intraday data. If your plug-in
supports mixed mode and you want daily bars in the same database, tick it now:
the IQFeed walkthrough ticks it during setup rather than afterwards.
A7. Configure the plug-in. Configure opens the vendor-specific dialog —
credentials, symbol counts, backfill options. Set the symbol count to your actual
subscription entitlement, not higher.
A8. Add symbols. Symbol → New accepts a comma-separated list. Nothing is
downloaded yet: backfill happens on first access.
A9. Backfill everything. In the Formula Editor write Buy = 1;, press Send
to Analysis, set Apply to to All symbols, Range to 1 recent bar,
open the Settings split-button menu and tick Wait for backfill, then
press Scan. On Interactive Brokers use the different documented route
instead: add the symbols to the Real-Time Quote window, choose a Backfill
length from the plug-in status context menu, then Backfill All RT quote
window symbols.
Then go to Verify.
Route B: an intraday database from historical files
Section titled “Route B: an intraday database from historical files”This route needs one thing the course cannot give you: a file of intraday bars. Everything else is in AmiBroker already.
B0. Getting an intraday file
Section titled “B0. Getting an intraday file”Be realistic about scope. One symbol and five trading sessions is enough to complete every step of this lab — that is roughly 1,950 rows at one-minute bars. You do not need a market, and you do not need years.
Places such a file legitimately comes from:
- A platform you already use. Most broker and charting platforms let account holders export intraday bars to CSV. This is the most common route and the only one this course can be confident about, because it depends on your own arrangements rather than on a third party’s current terms.
- AmiQuote’s own sources. AmiQuote ships with the AmiBroker installer and is licensed separately. Its official Read Me lists historical end-of-day and intraday FOREX from FinAm among the built-in sources; that intraday source is noted as available to the registered version.
- A user-defined AmiQuote source. AmiQuote 4.x can be pointed at any source
that returns CSV over HTTP, and example definitions ship in the
DataSourcessubfolder — including Tiingo Intraday IEX and AlphaVantage. Both need your own API key from the vendor.
Your file needs, per row: a ticker (or a file named after the ticker), a date, a time, open, high, low, close and volume. Something like this, which is the shape the format definition below expects:
AAA,2026-08-24,09:30,20.00,20.08,19.97,20.06,4200AAA,2026-08-24,09:31,20.06,20.14,20.03,20.11,3100AAA,2026-08-24,09:32,20.11,20.12,20.02,20.04,2700Those three rows are synthetic, and they exist only to show the column order.
B1. Create the database
Section titled “B1. Create the database”File → New → Database. Choose a folder outside the AmiBroker program directory
and click Create. Leave Data source as (local).
B2. Set the base interval and the intraday settings
Section titled “B2. Set the base interval and the intraday settings”Base time interval: the value you decided at the top of this lab, and it must be no coarser than your file. One-minute bars cannot be imported into a five-minute database; five-minute bars import perfectly well into a one-minute database, because they are simply bars stamped five minutes apart.
Then Intraday settings:
- Filtering: start with
Show 24 hours trading (no filtering). Filtering hides bars, and while you are learning what is in the file you want to see everything. Tighten it later. - Trading hours: enter the session your instrument actually trades, in your own local time zone.
- Time shift: leave it at zero for now. If your file’s timestamps are in the exchange’s time zone and you want them shown in yours — or the reverse — you have two ways to deal with it, and choosing between them is step B4.
B3. Write the format definition
Section titled “B3. Write the format definition”The Import Wizard (File → Import Wizard) is the friendly route, and for
intraday work it is the wrong one. The documented list of field types it offers
is Ticker, YMD, DMY, MDY, Open, High, Low, Close and Volume —
with no time field. The wizard is described in the guide as offering a subset
of the importer’s features, “for novice users only”. Intraday import needs the
full ASCII importer and a format definition file.
Create a plain text file named intraday-1min.format in the Formats
subdirectory of your AmiBroker working directory, containing:
; intraday-1min.format; Ticker, ISO date, HH:MM time, OHLC, volume, comma separated, one header row.$FORMAT Ticker, Date_YMD, Time, Open, High, Low, Close, Volume$SEPARATOR ,$SKIPLINES 1$AUTOADD 1$CONT 1$DEBUG 1What each line does, and why it is there:
$FORMATdeclares the order and type of the fields.TimeacceptsHH:MM:SS,HH:MM,HHMMorHHMMSS. UseSkipfor any column you want ignored — there is no positional “omit”.$SEPARATOR ,is not optional. The importer’s default separator is a space, and forgetting this line is the classic first failure.$SKIPLINES 1discards a header row. Set it to0if your file has none.$AUTOADD 1creates symbols that do not yet exist. The default is0, which silently imports nothing into an empty database.$CONT 1marks newly added symbols as continuously quoted, which is what enables candlestick charts. Without it the symbol is treated as price-fixing.$DEBUG 1logs errors toimport.login AmiBroker’s main directory. Turn it on for the first import of any new file shape.
If your timestamps need shifting, $TIMESHIFT <hours> moves them at import time
and accepts fractional and negative values — $TIMESHIFT -11.5 shifts eleven and
a half hours backwards. That is a different mechanism from the Time shift in
Intraday Settings, which shifts on display. Pick one and record which; using both
is how people end up two hours out and unable to say why.
B4. Import
Section titled “B4. Import”File → Import ASCII. Your format now appears in the Files of type combo
under its description. Select your file — Ctrl and Shift multi-select works — and
import.
If nothing appears, work through these in order:
import.login the AmiBroker main directory, if you set$DEBUG 1.- The separator. Space is the default; a comma-separated file without
$SEPARATOR ,produces a file of one unparseable column. $AUTOADD. Without it, unknown tickers are skipped rather than created.- The ticker. If no field in
$FORMATnames the ticker, the file name without path or extension is used instead.download1.csvcreates a symbol calledDOWNLOAD1. - Silent price repair. Without
$ALLOWNEG 1, the importer quietly fixes rows where the OHLC relationships do not hold — a zero open becomes the close, a high below the body is raised, a zero low becomes the lower of open and close. If your imported prices differ from your file, this is usually why.
B5. Accumulate more history
Section titled “B5. Accumulate more history”An intraday database built from files grows by importing more files. Imports at the same bar interval are additive, so overlapping files repair gaps rather than duplicating bars. If you are downloading daily with AmiQuote, note that its settings distinguish historical files, which are overwritten from daily files, which are appended — appending daily files is precisely how an intraday history accumulates over weeks.
Verify
Section titled “Verify”Three passes, in order. Do not skip to the third.
Verification, cheapest first
- Pass 1: what is this database?Interval, time shift, bars loaded, sessions, Bar Replay state
- Pass 2: is it uniform across symbols?First bar, last bar, bars per session, per symbol
- Pass 3: is each session complete?Holes, late starts, early ends, short sessions
- Write the coverage statementThe earliest date on which every symbol has complete data
Pass 1: the readout
Section titled “Pass 1: the readout”Set a chart to the base interval — the intraday toolbar button marked i — and
apply this indicator.
Complete runnable AFL
// ===========================================================================// Database settings readout// Prints, in the chart title, what this database and this chart pane are// actually configured to do - as opposed to what you believe you configured// when you created them. Nearly every intraday problem in Part 19 is a// mismatch between those two things.//// HOW TO RUN// Formula Editor -> Apply Indicator, in its own small pane.// To read the database's BASE interval rather than some other interval,// switch the chart to the intraday toolbar button marked "i", which means// "the base intraday interval set in File -> Database Settings".//// WHAT IT REPORTS// Chart interval the interval of THIS pane, in seconds and by name// Time shift the database time shift, from Status("timeshift")// Bars loaded how many bars AFL actually received for this symbol// First / Last bar the ends of what was loaded, not of what is stored// Calendar span days between the first and the last bar// Sessions how many distinct calendar days those bars cover// Bars per session loaded bars divided by sessions// Bar Replay whether playback is truncating the data right now//// ASSUMPTIONS, STATED SO THEY CAN BE CHECKED// - "Bars loaded" is not "bars stored". AmiBroker may hand a formula fewer// bars than the database holds, because of the Analysis range, because of// QuickAFL, or because Bar Replay is active. The Quote Editor is the only// window documented to always show every stored bar.// - A "session" here means a distinct calendar date, which is not the same// as an exchange session for instruments that trade overnight. On a// 24-hour instrument one exchange session can straddle two dates.// - Interval() returns the interval of the chart, never the base interval// of the database. They are the same number only when the chart is set to// the base interval.// ===========================================================================
_SECTION_BEGIN( "Database settings readout" );
Plot( Close, "Close", colorDefault, styleCandle );
IntervalSeconds = Interval();IntervalName = Interval( 2 );
// Status("timeshift") returns the database time shift in seconds (AmiBroker// 5.60 and later). It is the setting from Database Settings -> Intraday// settings -> Time shift, expressed as seconds rather than hours.TimeShiftSeconds = Status( "timeshift" );TimeShiftHours = TimeShiftSeconds / 3600;
BarNumber = Cum( 1 );BarsLoaded = LastValue( BarNumber );
FirstBarDateTime = LastValue( ValueWhen( BarNumber == 1, DateTime() ) );LastBarDateTime = LastValue( DateTime() );
// DateTimeDiff returns seconds, positive when the first argument is later.SpanDays = DateTimeDiff( LastBarDateTime, FirstBarDateTime ) / 86400;
// A new calendar date starts wherever the day number changes. Cum(1) == 1// forces the very first bar to count, because Ref() has no previous bar there.NewSession = BarNumber == 1 OR Day() != Ref( Day(), -1 );SessionCount = LastValue( Cum( NewSession ) );
BarsPerSession = IIf( SessionCount > 0, BarsLoaded / SessionCount, Null );
// GetPlaybackDateTime() returns the Bar Replay position, or zero when replay// is not active. A forgotten Bar Replay truncates every chart and every// Analysis run in the program, so it is worth showing permanently.PlaybackPosition = GetPlaybackDateTime();
ReplayLine = "Bar Replay: not active";
if ( PlaybackPosition != 0 ){ ReplayLine = "BAR REPLAY ACTIVE - data truncated at " + DateTimeToStr( PlaybackPosition );}
IntervalLine = "Chart interval: " + IntervalName + " (" + NumToStr( IntervalSeconds, 1.0 ) + " s)";
if ( IntervalSeconds >= 86400 ){ IntervalLine = IntervalLine + " - this pane is NOT intraday";}
Title = "DATABASE READOUT - " + Name() + "\n" + IntervalLine + "\n" + "Time shift: " + NumToStr( TimeShiftHours, 1.2 ) + " h" + " (" + NumToStr( TimeShiftSeconds, 1.0 ) + " s)\n" + "Bars loaded: " + NumToStr( BarsLoaded, 1.0 ) + " Sessions: " + NumToStr( SessionCount, 1.0 ) + " Bars per session: " + NumToStr( LastValue( BarsPerSession ), 1.1 ) + "\n" + "First bar: " + DateTimeToStr( FirstBarDateTime ) + " Last bar: " + DateTimeToStr( LastBarDateTime ) + " Span: " + NumToStr( SpanDays, 1.1 ) + " days\n" + ReplayLine;
_SECTION_END();Check three things. Chart interval matches the base interval you chose. Time shift matches what you set, or is zero if you shifted at import time instead. Bar Replay: not active — because if it is active, every number in passes 2 and 3 will be wrong in the same direction and you will spend an hour on it.
Write down the Bars per session figure. That is your real conversion factor between bars and days, and it is the number Route A’s step A5 was guessing at.
Pass 2: history depth across symbols
Section titled “Pass 2: history depth across symbols”Analysis window, Apply to = All symbols, Range = All quotations, Explore.
Complete runnable AFL
// ===========================================================================// History depth report// One row per symbol, answering the question a backfill never answers by// itself: how much history did each symbol actually end up with? Symbols in// the same database, added on different days, from the same feed, routinely// hold very different amounts of history - and nothing on a chart says so// until you scroll back far enough to fall off the end of the data.//// HOW TO RUN// Analysis window: Apply to = All symbols (or a watch list),// Range = All quotations, then Explore.// Run it on an intraday database with the chart interval set to the base// interval, so that "Bars" means base-interval bars.//// WHAT EACH COLUMN MEANS// Bars bars this symbol supplied inside the range// First / Last the ends of the loaded history// Cal.days calendar days between the first and the last bar// Sessions distinct calendar dates covered// Bars/session Bars divided by Sessions// Fullest bars in the busiest single session// Thinnest bars in the emptiest single session// Last bar age h hours between the newest bar and your computer clock//// ASSUMPTIONS, STATED SO THEY CAN BE CHECKED// - A short history is not automatically a fault. A symbol listed last// month cannot have a year of bars, and a vendor's backfill depth is a// limit you were told about in advance. This report tells you what you// have; deciding whether that is wrong is your job.// - A session here is a distinct calendar date. For instruments that trade// overnight, one exchange session spans two dates and the session count// will be roughly double what a trader would say.// - "Last bar age" compares a bar timestamp against your local clock. If// the database time shift is set so that bar times are exchange times// rather than local times, the age is off by the shift. Read the shift// with Status("timeshift") before drawing conclusions from this column.// - Thinnest sessions are frequently real: half-day sessions before public// holidays are short by design, and an illiquid symbol simply prints no// bar in a minute in which nothing traded.// ===========================================================================
Filter = Status( "lastbarinrange" );SetOption( "NoDefaultColumns", True );
BarNumber = Cum( 1 );BarsInRange = LastValue( BarNumber );
FirstBarDateTime = ValueWhen( BarNumber == 1, DateTime() );
// Cum(1) == 1 forces the first bar to open a session, because Ref() has no// previous bar to compare against there.NewSession = BarNumber == 1 OR Day() != Ref( Day(), -1 );SessionCount = Cum( NewSession );
// Bars elapsed since the session opened, counted on every bar.SessionStartBar = ValueWhen( NewSession, BarNumber );BarsInSession = BarNumber - SessionStartBar + 1;
// The last bar of a session is the bar before the next session opens. On the// final bar of the array there is no next bar, so the analysis-range flag is// used to make sure the newest session is still measured.EndOfSession = Nz( Ref( NewSession, 1 ) ) OR Status( "lastbarinrange" );SessionTotal = IIf( EndOfSession, BarsInSession, Null );
// Highest() and Lowest() are running extremes over everything seen so far, so// LastValue() of them is the extreme over the whole loaded history.FullestSession = LastValue( Highest( Nz( SessionTotal ) ) );ThinnestSession = LastValue( Lowest( IIf( EndOfSession, BarsInSession, 999999 ) ) );
CalendarDays = DateTimeDiff( DateTime(), FirstBarDateTime ) / 86400;
// Now(5) returns the current date and time as a DateTime number.LastBarAgeHours = DateTimeDiff( Now( 5 ), DateTime() ) / 3600;
AddTextColumn( Name(), "Symbol", 1.0, colorDefault, colorDefault, 80 );AddColumn( BarsInRange, "Bars", 1.0 );AddColumn( FirstBarDateTime, "First", formatDateTime );AddColumn( DateTime(), "Last", formatDateTime );AddColumn( CalendarDays, "Cal.days", 1.1 );AddColumn( SessionCount, "Sessions", 1.0 );AddColumn( IIf( SessionCount > 0, BarsInRange / SessionCount, Null ), "Bars/session", 1.1 );AddColumn( FullestSession, "Fullest", 1.0 );AddColumn( ThinnestSession, "Thinnest", 1.0 );AddColumn( LastBarAgeHours, "Last bar age h", 1.1 );
// Newest first bar at the top: the symbols with the least history are the ones// that will silently shorten every study you run across this database.SetSortColumns( -3 );Sort by the First column. On Route A, expect variation — symbols added at different times reach back different distances. On Route B, expect uniformity, because every symbol’s history is exactly the file you imported. Either way, the top row of the descending sort is the constraint on every multi-symbol study you will ever run against this database.
Pass 3: session completeness
Section titled “Pass 3: session completeness”Same Analysis settings, with Show only suspect sessions left on for the first run.
Complete runnable AFL
// ===========================================================================// Intraday completeness check// One row per symbol per trading session, answering four separate questions// that an incomplete intraday database confuses with each other://// 1. Are there holes INSIDE the session? (Missing column)// 2. Did the session start late? (Late start column)// 3. Did the session end early? (Early end column)// 4. Is the whole session shorter than this// symbol's own normal session? (Short column)//// It needs no holiday calendar and no hard-coded bar count, because every// session is measured against (a) its own elapsed time and (b) the fullest// session this symbol actually has. That is what makes it portable: it runs// unchanged on any intraday database, local or plug-in fed, at any// time-based base interval, on any exchange.//// HOW TO RUN// Analysis window: Apply to = All symbols (or a watch list),// Range = All quotations.// Set the chart interval to the database's base interval first - the "i"// toolbar button - or you will be auditing compressed bars rather than// stored ones.// Press Explore. Leave "Show only suspect sessions" on for a first pass.//// WHAT EACH COLUMN MEANS// Bars bars stored in that session// Start/End first and last bar time, as TimeNum() codes:// 10000*hour + 100*minute + second, so 09:35:00 reads 93500// Span min minutes between the first and the last bar of the session// Expected Span divided by the bar interval, plus one// Missing Expected minus Bars: bar slots inside the session with no bar// Max gap min the longest interval between two consecutive bars// % fullest Bars as a percentage of this symbol's fullest session//// ASSUMPTIONS, STATED SO THEY CAN BE CHECKED// - A missing bar is not necessarily missing DATA. In an intraday database// a minute in which nothing traded produces no bar at all, so an illiquid// symbol will show Missing > 0 permanently and correctly. Compare a// symbol against itself over time, not against a liquid neighbour.// - Half-day sessions before public holidays are genuinely short. "Short"// flags them, and it is right to: the check cannot tell a holiday from a// truncated backfill, and neither should it pretend to. That is what the// exchange calendar is for.// - Late start and Early end are measured against the earliest start and// the latest end this symbol has anywhere in the loaded range. If the// loaded range contains only truncated sessions, everything looks normal.// Widen the range before trusting a clean result.// - The check reads what AFL was GIVEN, which may be less than what is// stored: an Analysis range, QuickAFL or an active Bar Replay all shorten// it. Confirm with the Quote Editor, which always shows every stored bar.// - Tick and other non-time-based intervals leave Expected, Missing and// Max gap empty by design, because "one bar per interval" has no meaning// when bars are not time based.// ===========================================================================
ShortThreshold = Param( "Short session threshold %", 90, 10, 100, 1 );OnlySuspect = ParamToggle( "Show only suspect sessions", "No|Yes", 1 );
SetOption( "NoDefaultColumns", True );
BarNumber = Cum( 1 );
// Cum(1) == 1 forces the first bar to open a session, because Ref() has no// previous bar there to compare against.NewSession = BarNumber == 1 OR Day() != Ref( Day(), -1 );
// The last bar of a session is the bar before the next session opens. Ref()// with a positive shift looks one bar into the future, which is legitimate in// a data audit and would not be in a trading rule. On the final bar of the// array there is no next bar, so the analysis-range flag catches it.EndOfSession = Nz( Ref( NewSession, 1 ) ) OR Status( "lastbarinrange" );
SessionStartBar = ValueWhen( NewSession, BarNumber );SessionStartDateTime = ValueWhen( NewSession, DateTime() );SessionStartTime = ValueWhen( NewSession, TimeNum() );BarsInSession = BarNumber - SessionStartBar + 1;
// How long the session ran, in seconds, measured from its own first bar.SpanSeconds = DateTimeDiff( DateTime(), SessionStartDateTime );
// Interval() is the interval of the CHART, in seconds. Tick charts return 0// and daily or longer returns 86400 or more; in both cases the bar-slot// arithmetic below is meaningless, so the divisor becomes Null and the// derived columns come out empty rather than wrong.IntervalSeconds = Interval();BarSlotSeconds = IIf( IntervalSeconds > 0 AND IntervalSeconds < inDaily, IntervalSeconds, Null );
ExpectedBars = SpanSeconds / BarSlotSeconds + 1;MissingBars = ExpectedBars - BarsInSession;
// Gap between this bar and the previous one, reset at every session boundary// so that the overnight gap is never counted as a hole.GapSeconds = Nz( DateTimeDiff( DateTime(), Ref( DateTime(), -1 ) ) );GapWithinSession = IIf( NewSession, 0, GapSeconds );LargestGap = HighestSince( NewSession, GapWithinSession );
// This symbol's own reference session: the fullest one in the loaded range,// and the earliest open and latest close it has ever recorded. 999999 is a// sentinel above any possible TimeNum() value, which caps out at 235959.SessionTotal = IIf( EndOfSession, BarsInSession, 0 );FullestSession = LastValue( Highest( SessionTotal ) );EarliestStart = LastValue( Lowest( IIf( NewSession, TimeNum(), 999999 ) ) );LatestEnd = LastValue( Highest( IIf( EndOfSession, TimeNum(), 0 ) ) );
PercentOfFullest = IIf( FullestSession > 0, 100 * BarsInSession / FullestSession, Null );
HasHoles = MissingBars >= 1;StartsLate = SessionStartTime > EarliestStart;EndsEarly = TimeNum() < LatestEnd;IsShort = PercentOfFullest < ShortThreshold;
Suspect = HasHoles OR StartsLate OR EndsEarly OR IsShort;
Filter = EndOfSession AND ( OnlySuspect == 0 OR Suspect );
AddTextColumn( Name(), "Symbol", 1.0, colorDefault, colorDefault, 80 );AddColumn( DateTime(), "Session", formatDateTime );AddColumn( BarsInSession, "Bars", 1.0 );AddColumn( SessionStartTime, "Start", 1.0 );AddColumn( TimeNum(), "End", 1.0 );AddColumn( SpanSeconds / 60, "Span min", 1.0 );AddColumn( ExpectedBars, "Expected", 1.0 );AddColumn( MissingBars, "Missing", 1.0 );AddColumn( LargestGap / 60, "Max gap min", 1.1 );AddColumn( PercentOfFullest, "% fullest", 1.1 );
// Every flag is readable as text, so the report survives being printed in// black and white, read by a screen reader or pasted into a spreadsheet.AddTextColumn( WriteIf( HasHoles, "holes", "-" ), "Holes", 1.0, colorDefault, colorDefault, 60 );AddTextColumn( WriteIf( StartsLate, "late", "-" ), "Late start", 1.0, colorDefault, colorDefault, 70 );AddTextColumn( WriteIf( EndsEarly, "early", "-" ), "Early end", 1.0, colorDefault, colorDefault, 70 );AddTextColumn( WriteIf( IsShort, "short", "-" ), "Short", 1.0, colorDefault, colorDefault, 60 );
// Worst first: most missing bars, then longest internal gap.SetSortColumns( -8, -9 );Interpret it in the order the previous page established: a short session with
Missing near zero on the same date for every symbol is a half-day and is fine.
Missing spread thinly across many sessions on one symbol is illiquidity, not
damage. late or early clustered on specific dates is truncated data, and it
is what you go and fix.
Pass 4 (optional but recommended): the Bar Replay smoke test
Section titled “Pass 4 (optional but recommended): the Bar Replay smoke test”Tools → Bar Replay. Set Start to a date in the middle of your data, set
Step interval to your database’s base interval — which is the guide’s own
recommendation — and press Play at speed 1.
Two things should happen. The chart should advance one bar at a time, and the readout formula’s last line should show the replay warning. Press Stop and everything returns; nothing was written to disk. You have just confirmed that your database can drive the whole of Part 26 without a live feed.
Verification checklist
Section titled “Verification checklist”Do not call the lab finished until every line has an answer.
| # | Check | Where | Pass condition |
|---|---|---|---|
| 1 | Base time interval is the value you chose | File → Database Settings |
Matches your written decision |
| 2 | Intraday chart intervals are enabled | View → Intraday |
Not greyed out |
| 3 | Chart interval on the i button equals the base interval |
Readout, line 1 | Matches check 1 |
| 4 | Time shift is what you intended | Readout, line 2 | Matches your note, or zero by design |
| 5 | Bar Replay is not active | Readout, last line | “not active” |
| 6 | Bars per session measured, not assumed | Readout, line 3 | A number you wrote down |
| 7 | Days-equivalent read before accepting the bar count (Route A) | File → Database Settings |
Consistent with your session target |
| 8 | Every symbol has bars | History depth report | No zero-bar rows |
| 9 | First-bar dates understood | History depth report | You can explain the spread |
| 10 | Coverage statement written | Your notes | One sentence, with a date in it |
| 11 | Suspect sessions triaged | Completeness check | Each cluster classified as fault or not |
| 12 | Quote Editor cross-check on one suspect session | Symbol → Quote Editor |
Confirms hidden versus missing |
| 13 | Candlesticks draw | Any chart | Continuous quotations on |
| 14 | Database folder backed up | Your file system | A copy exists elsewhere |
| 15 | Settings recorded | Your notes | Five lines, listed below |
What to record
Section titled “What to record”Add these five lines to the record you have been keeping since Part 3. Parts 20 to 26 all refer back to them, and reconstructing them from memory in the middle of a session-boundary problem is miserable.
- Database folder path, and whether the data source is
(local)or a plug-in. - Base time interval.
- Number of bars to load, and the days-equivalent AmiBroker displayed — or, for a local database, the date range of the files you imported.
- Session filtering mode and the day-session trading hours you entered.
- Time shift, and where it is applied: Intraday Settings,
$TIMESHIFTat import, or nowhere.
Where this goes next
Section titled “Where this goes next”Part 20 takes the session and time-shift settings you have just entered and shows what happens when they are subtly wrong — an opening range that moves twice a year is the classic symptom. Part 21 puts charts on this database. Part 24 scans it. Part 26 uses Bar Replay on it, which is why pass 4 is worth doing now rather than discovering a problem three parts later.
If you took Route B, none of that changes. The only thing you do not have is a stream of live quotes, and the course tells you plainly, in Parts 22 and 23, exactly which two lessons that limits and what you do instead.
Check your understanding
Sources for this lesson
7 verified · checked 2026-08-31
- 01AmiBroker User's Guide — Database Settings windowamibroker.com/guide/w_dbsettings.html2026-08-31
- 02AmiBroker User's Guide — ASCII importer and format definition filesamibroker.com/guide/d_ascii.html2026-08-31
- 03AmiBroker User's Guide — ASCII Import Wizardamibroker.com/guide/w_impwizard.html2026-08-31
- 04AmiBroker User's Guide — Working with real-time data sourcesamibroker.com/guide/h_rtsource.html2026-08-31
- 05AmiBroker User's Guide — Bar Replayamibroker.com/guide/w_barreplay.html2026-08-31
- 06AmiBroker User's Guide — Symbol Information windowamibroker.com/guide/w_information.html2026-08-31
- 07AmiQuote 4.00 Read Me — supported data sourcesamibroker.com/devlog/wp-content/uploads/2019/05/aqreadme4000.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.