Skip to content
Level 3 · AFL DeveloperLessonPart 11 · page 3 of 528 min
28Minutes
9AFL functions
9Sources
StandardRequires
AFL functions taught here9

Include Files and Building a Library

AmiBroker gives you two ways to reuse a piece of AFL, and they are not alternatives.

Code snippets are a Formula Editor feature: you select some text, save it under a name and a key trigger, and afterwards type @trigger or drag it from the Code Snippets window to paste it into a formula. What lands in the formula is a copy. Snippets are excellent for boilerplate you are about to modify - the skeleton of a for loop, the shape of an exploration.

Include files are the opposite. The #include directive does not paste anything into your saved formula; it tells the AFL preprocessor to merge the contents of a file into the program at the moment it runs. Change the file and every formula that includes it changes. That is what makes a library a library.

This lesson is about the second mechanism: how to write the directive, where AmiBroker looks, what the preprocessor does with the result, and how to organise files so that a library you keep adding to does not become a liability.

The official page documents two spellings.

A literal path, in double quotes:

Fragment — not a complete formula

#include "C:\AmiBroker\Formulas\Custom\course-library.afl"

Or a bare file name in angle brackets, which is looked up in the standard include path:

Fragment — not a complete formula

#include <course-library.afl>

The angle-bracket form is the one to prefer for your own library, for the reason the documentation gives: it “makes much shorter to write includes and you can move include folder now without changing all AFL codes using #includes”.

The standard include path is a preference, set under Tools → Preferences → AFL. The documentation gives a worked example: with the path set to C:\AFL\MyIncludes, the directive #include <common.afl> loads C:\AFL\MyIncludes\common.afl.

What the online documentation does not state is what that setting contains on a fresh install. This course therefore does not tell you a default path - open Tools → Preferences → AFL on your own machine and read it, then either use that folder or point it at one you prefer.

Wherever you point it, do not point it at the Formulas folder that ships with AmiBroker. The official FAQ is unambiguous about what happens to files there: formulas supplied with AmiBroker “will be overwritten” by the next upgrade, and the recommendation is to save your own work “under a new name or (better) in your own custom subfolder”. A library folder of your own, backed up with the rest of your work, is the right home.

The preprocessor runs before your formula executes and is, in the words of the #pragma page, “responsible for inclusion of external files via #include command”. The result is one merged text, which the AFL engine then compiles and runs.

From two files to one program

  1. You press Apply, or a chart refreshesAmiBroker takes the formula text as saved
  2. The preprocessor reads any #pragma optionsThese must appear before the includes they affect
  3. Each #include is replaced by the contents of its fileAt the position of the directive, in order
  4. One merged program existsIncluded text now sits above your own code
  5. The AFL engine executes itOnce per pane, per symbol, per Analysis step
Nothing is written back to your saved formula: the merge happens on every run.

Three practical consequences follow from that picture.

Includes go at the very top. A function definition must precede its call, and the merged text is what determines “precede”. An include placed halfway down a formula makes its functions unavailable to everything above it.

Scope is decided on the merged text. The rule from the previous lesson - that a name is local or global depending on where it first appears - operates on the merged program, not on the file you are looking at. If your library assigns a global at the top, every later mention of that name in your own formula refers to the library’s variable. This is the whole argument for prefixes.

Caching is on by default. The documentation says AmiBroker “tries to include only once and cache pre-processed text”, and warns separately that using #include “may slow down formula execution”. While you are actively editing a library, the cache can serve you a stale copy. The documented switch is:

Fragment — not a complete formula

#pragma nocache
#include <course-library.afl>

Two rules on that directive, both from the official page: it must appear before any #include commands, and “between #pragma and nocache there must be exactly SINGLE space”. A second space or a tab silently does nothing. Turn it on while you are editing the library, and take it out again afterwards, because disabling caching “may slow down execution of the formula (especially in indicators)”.

The function reference index lists #include_once as “preprocessor include (once) command (AFL 2.70)”. Its detail page is behind the licensed-customer login on amibroker.com, so this course states only what can be confirmed from sources it could read: the directive exists, it dates from AFL 2.70, and its purpose is to include a file only if it has not already been included. The 5.10 release notes separately confirm “unlimited nesting of #include and #include_once statements”.

The situation it is for is easy to describe. Suppose you write a second library that itself includes the first, and a formula includes both. Without protection, the first library’s text is merged twice, and every function in it is defined twice.

Pseudocode — not valid AFL

formula.afl
includes analysis-helpers.afl
which includes course-library.afl <- first copy
includes course-library.afl <- second copy

Using #include_once for library files that other library files might also pull in removes that possibility. Given that its parameters are not publicly documented, the safe pattern is the conservative one: use it exactly as you would use #include, with the same two path forms, and keep your libraries shallow enough that you would notice if it behaved differently.

Historically #include failed silently. The current behaviour is documented on the same page - “#include now reports file(s) not found in regular error message box” - and the published error is Error 42: the include failed because the file does not exist, with the file name and the current working directory in the message.

Read that message rather than guessing. It tells you both what AmiBroker looked for and where it was standing when it looked, which between them identify almost every path mistake: a typo, a doubled backslash, a file saved with a .txt extension by an editor, or an angle-bracket include with no standard include path set.

The multithreading chapter documents an initialisation idiom: wrapping first-symbol setup in if( Status( "stocknum" ) == 0 ). AmiBroker “detects such a statement and runs the very first symbol in one thread only, waits for completion, and only after completion does it launch all other threads”.

The page then gives an explicit caveat: that statement must not be placed inside #include. The detection happens on the main formula. Setup code that must run once, before the other threads start, belongs in the formula itself, not in your library.

This matters more than it sounds, because “run this once at the start” is exactly the kind of helper people are tempted to move into a library.

A library that grows without a shape becomes a place where things are hard to find, which is how duplicate definitions get written. The structure this course uses is deliberately flat:

File Contents
course-library.afl The functions. Definitions only, one prefix, no side effects beyond a version guard.
course-library-test.afl A formula that calls every function and checks the ones with a knowable answer.
chart-defaults.afl A separate small include for chart housekeeping, with its own prefix.

Two rules keep it navigable. One prefix per file, so you can tell from a call site which file a function came from. One purpose per file, so that a formula which needs only the chart helpers does not drag in everything else.

Resist the urge to create a file called utilities.afl. Files named after what they contain stay useful; files named after the fact that they contain something become the drawer everything ends up in.

Your library will change, and formulas written against an older version will outlive the change. Three cheap habits handle almost all of the consequences.

A version number the code can read. A one-line function returning a number lets a formula state its requirement:

Fragment — not a complete formula

#include <course-library.afl>
if( LibVersion() < 1.00 )
{
_TRACE( "This formula needs course-library 1.00 or later" );
}

A changelog in the file header. Date each release and say what changed, particularly when a function’s meaning changes rather than its name. A function that quietly starts returning a percentage instead of a fraction is the kind of change that breaks charts silently.

An AmiBroker version guard. Version( minrequired ) returns the running version number, and the documentation notes that passing a minimum “will issue an error message when running the formula on AB earlier than” that version. If your library uses something recent - StDev’s Population argument, added in 6.20, is the case in this part’s library - say so in code rather than in a comment nobody reads.

If you send someone a .chart file, AmiBroker stores the contents of any include files inside it and attempts to recreate them on the target machine. The documentation describes the collision handling: if a different file already exists at the target, AmiBroker asks whether to replace it, and makes a .bak backup if you agree. Files included with angle brackets are restored into the target machine’s standard include folder “even if the standard include folder path is different on the source machine”.

This is a good reason to use the angle-bracket form and to keep your library file names distinctive. course-library.afl will not collide with anything; utils.afl might.

Before building the real library, it is worth running the smallest possible include - one file that defines two functions and does nothing else, and one chart formula that uses them. If this pair works on your machine, your paths and your preferences are correct, and the project at the end of this part becomes an exercise in content rather than in configuration.

Fragment — not a complete formula

chart-defaults.afl
// chart-defaults.afl
// ---------------------------------------------------------------------------
// A deliberately tiny include file, used by Part 11 to demonstrate #include
// before the full course library is built.
//
// Version : 1.00
// Requires: AmiBroker 5.30 or later
//
// Every public name here starts with Demo, so this file cannot collide with
// your own variables, with the course library, or with anything AmiBroker
// ships. Nothing in this file executes: it only defines.
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// DemoHeaderText( ExtraText )
// Purpose : One consistent first line for every chart title you write.
// Inputs : ExtraText - STRING appended after the symbol and interval
// Returns : STRING
// Notes : Interval( 2 ) returns the interval's NAME. The official page
// warns never to compare that name in code, because it is
// translated in localised builds - displaying it is fine.
// ---------------------------------------------------------------------------
function DemoHeaderText( ExtraText )
{
local Result;
Result = Name() + " - " + Interval( 2 ) + " - " + ExtraText;
return Result;
}
// ---------------------------------------------------------------------------
// DemoPercentOf( PartArray, WholeArray )
// Purpose : Express one array as a percentage of another without producing
// an infinity when the divisor is zero.
// Inputs : PartArray, WholeArray - ARRAYs
// Returns : ARRAY, percent, Null where the result would not be finite
// ---------------------------------------------------------------------------
function DemoPercentOf( PartArray, WholeArray )
{
local Quotient;
local Result;
Quotient = PartArray / WholeArray;
Result = IIf( IsFinite( Quotient ), 100 * Quotient, Null );
return Result;
}
// End of chart-defaults.afl

Download chart-defaults.afl50 lines

Note what is not in it: no Plot, no Title, no assignments at global level. It defines two functions and stops. An include file with side effects runs those side effects in every formula that includes it, which is rarely what anyone intended.

Complete runnable AFL

chart-with-include.afl
// chart-with-include.afl
// Part 11 - Include Files and Building a Library
//
// GOAL
// Show a formula that is mostly other people's code - specifically, your own
// code, kept in one place. Everything the chart needs beyond price comes from
// chart-defaults.afl.
//
// WHAT IT DRAWS
// The candle body as a percentage of the whole bar's range. A high reading is
// a bar that closed a long way from where it opened relative to how far it
// travelled; a low reading is a bar with long wicks and little net movement.
// It is a description of one bar, not a signal.
//
// PREREQUISITE
// chart-defaults.afl must be reachable. Either put it in the folder named in
// Tools -> Preferences -> AFL as the standard include path and keep the line
// below, or replace the line with a full path in quotes and SINGLE
// backslashes. If you get Error 42, the file is not where you said it is.
#include <chart-defaults.afl>
_SECTION_BEGIN( "Body size" );
Plot( Close, "Close", colorDefault, styleCandle );
BodySize = abs( Close - Open );
BarRange = High - Low;
BodyShare = DemoPercentOf( BodySize, BarRange );
Plot( BodyShare, "Body as % of range", colorBlue, styleLine | styleOwnScale );
_N( Title = DemoHeaderText( "candle body as a percentage of the bar's range" ) + "\n" +
WriteIf( IsNull( BodyShare ),
"No reading at the selected bar: the bar has no range.",
"Selected bar body is " + NumToStr( BodyShare, 1.1 ) + "% of its range." ) );
_SECTION_END();

Download chart-with-include.afl38 lines

The #include line is the first executable thing in the file, so both functions exist by the time anything calls them. DemoPercentOf does the arithmetic and converts a non-finite result to Null, which is what a bar with no range - a limit-locked future, a halted share, a padded non-trading day - would otherwise produce. DemoHeaderText builds the first line of the title, so that every chart you write with this include starts the same way.

  • Interval( 2 ) returns the interval’s name as a string, such as “Daily” or “15-minute”. The official page carries a caveat worth repeating: never compare that string in code, because localised builds translate it. Display it; test Interval() == inWeekly instead.
  • abs( x ) returns the absolute value, used here so that an up bar and a down bar of the same size report the same body share.
  • Version( minrequired ) is the version guard described above.

A candle chart with a second line on its own scale showing the body as a percentage of the range. Values sit between 0 and 100 by construction. Bars with long wicks read low; bars that opened at one extreme and closed at the other read close to 100. The title names the symbol and the interval, then reports the selected bar’s reading in words.

Edit chart-defaults.afl - change the separator in DemoHeaderText from - to | - save it, and refresh the chart. If the title does not change, the preprocessor is serving you a cached copy: add #pragma nocache above the include, with exactly one space, and try again. Put the change back afterwards.

Then deliberately break the path. Rename the include file, refresh, and confirm that you get Error 42 naming the file it could not find. Knowing what that error looks like before you need to diagnose it is worth the thirty seconds.

Symptom Cause
Error 42 The path is wrong, the standard include path is unset, or the file has a different extension
Syntax error at the first call The #include is below the code that uses it
Edits to the include have no effect Preprocessor caching. Add #pragma nocache while editing
#pragma nocache appears to do nothing Two spaces between the words. The documentation requires exactly one
Error 34 after adding a second library Two files define the same name, or a function name collides with one of your globals

Add a third function to chart-defaults.afl that returns the bar’s close position within its range as a percentage, and use it as a second line. Then create a second formula that includes the same file and uses only the header function. Change the header format once and confirm that both formulas change - that is the property you are buying.

#include merges a file into your formula before it runs, which means order matters, scope is decided on the merged text, and a cached copy can lie to you while you edit. The angle-bracket form keeps paths out of your formulas at the cost of one preference setting. Error 42 tells you exactly what could not be found. Keep libraries in a folder AmiBroker’s installer will not overwrite, one prefix per file, with a version number the code can read and a test formula beside it.

Which leaves one question outstanding: what happens when the code inside the library meets data it was not designed for. That is the next lesson.

Check your understanding

Question 1. Which of these is the correct way to include a file by literal path?
Show the answer and why

Answer: #include "C:\AmiBroker\Formulas\lib.afl"

The official note says the include statement needs single backslashes, which is the opposite of normal AFL string parsing where a literal backslash must be doubled. The angle-bracket form is for a bare file name looked up in the standard include path, not for a full path.

Question 2. You edit your library file, save it, and refresh the chart - but the chart behaves exactly as before. What is the documented first thing to try?
Show the answer and why

Answer: Add `#pragma nocache` above the include, with exactly one space between the words

Included files are cached by default. The documented switch is #pragma nocache, which must appear before any include commands, and the page states that exactly one space is required between the two words.

Question 3. Why must an `if( Status( "stocknum" ) == 0 )` initialisation block stay in the main formula rather than in an include file?
Show the answer and why

Answer: AmiBroker detects that statement in the main formula in order to run the first symbol single-threaded, and the official page states it must not be inside an include

The multithreading chapter documents both the detection mechanism and the caveat. AmiBroker looks for that statement to serialise the first symbol, and the page states plainly that it must not be placed inside an include.

Question 4. Which of these belong in an include file intended as a library? Select all that apply.
Show the answer and why

Answer: Function definitions with a common prefix, A changelog and version number in the header comment

Definitions and documentation belong in a library. A Plot at global level runs in every formula that includes the file, and Param adds a control to the Parameters dialog of whichever chart called it - both are side effects the including formula did not ask for.

Sources for this lesson

9 verified · checked 2026-08-31

  1. 01AFL Function Reference -amibroker.com/guide/afl/_include.html2026-08-31
  2. 02AFL Function Reference -amibroker.com/guide/afl/_pragma.html2026-08-31
  3. 03AmiBroker AFL Function Reference index§ #include_once entryamibroker.com/guide/a_funref.html2026-08-31
  4. 04AmiBroker User's Guide - Charts, sheets and layouts§ Portable chart files and include filesamibroker.com/guide/h_sheets.html2026-08-31
  5. 05AmiBroker User's Guide - Drag and drop, formulas and parameters§ Adding your own formulas to the Charts treeamibroker.com/guide/h_dragdrop.html2026-08-31
  6. 06AmiBroker User's Guide - Multithreading§ Initialisation using Status("stocknum")amibroker.com/guide/h_multithreading.html2026-08-31
  7. 07AmiBroker User's Guide - Using code snippetsamibroker.com/guide/h_snippets.html2026-08-31
  8. 08AmiBroker User's Guide - Error and warning messagesamibroker.com/guide/errors2026-08-31
  9. 09AFL Function Reference - Versionamibroker.com/guide/afl/version.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.