AmiBroker CBT
Intensive
AmiBroker CBT Intensive - Matt Radtke 1
Course Objectives
This course is designed for traders who want to use
AmiBroker to create complex back tests and optimizations
using the Custom Backtest (CBT) interface.
AmiBroker CBT Intensive - Matt Radtke 2
Course Objectives
At the completion of this course, you will be able to:
• Determine when to use each of the three levels of
the Custom Back Tester
• Add custom trade metrics via the Custom Back
Tester
• Add custom portfolio metrics via the Custom Back
Tester
• Exercise complete control over the processing of
entry and exit signals
• Enter, modify, and exit trades at will
• Perform auxiliary functions like hedging
AmiBroker CBT Intensive - Matt Radtke 3
Class Preparation
By the time we start the class, you should have
accomplished the following tasks:
• AmiBroker version 6.0 or later installed. Version 6.20 or
later is preferred.
• Installed a data source and configured it to work with
AmiBroker.
• Have basic familiarity with AFL, including the ability to
create and execute back tests and optimizations with
AmiBroker’s standard back test engine.
AmiBroker CBT Intensive - Matt Radtke 4
Overview
The CBT Intensive will be presented in three sessions of approximately
one hour each. We have a lot of material to cover, so we’ll be moving
along at a healthy pace. To maximize the benefit of the training, please
consider the following:
1. Ask Questions! A friend has a T-Shirt proclaiming “I can explain it to
you, but I can’t make you understand.” If something doesn’t make
sense to you, there’s a good chance someone else is scratching
their head as well and explaining it a different way will benefit the
entire group. If you’re watching the recording of this session, then
send your questions to quantforhire@[Link].
2. Practice! No training in the world is a substitute for creating
something of your own. Do the homework. Experiment with your own
strategies. Break things and fix them again. Help someone else (this
one is huge). Ask more questions.
3. Network! I cannot overstate the benefit of having a trading buddy, a
mastermind group, a trading club, or some other collection of like-
minded people with whom you can share ideas, challenges, and
victories.
AmiBroker CBT Intensive - Matt Radtke 5
Session 1
AmiBroker CBT Intensive - Matt Radtke 6
Agenda
1. AmiBroker Framework
• Execution Phases 1 & 2
• Multithreading
• Number of Bars
• Pad & Align
• Backtester Settings
2. Data Constructs
• Static Variables
• Matrices vs. Arrays
3. User Functions
• Definition
• Scope
• Execution
4. Object Model
• Backtester
• Signal
• Trade
• Stats
• Collections and iteration
AmiBroker CBT Intensive - Matt Radtke 7
AmiBroker Execution Framework
AmiBroker CBT Intensive - Matt Radtke 8
AFL Execution
Your AFL file is a script that AmiBroker executes from top to bottom. AFL can be
executed in different contexts:
• Analysis (Scan, Explore, Backtest, Optimization)
• Debugger (similar but not identical to Backtest)
• Parameters
• Chart
• See Status(“ActionEx”) for additional examples
Phase 1: When running any Analysis task, your AFL will be executed once for
each symbol in the watchlist**. If you’re using the S&P 500 watchlist, then your
AFL gets executed 500 times.
Phase 2: During a Backtest, your AFL and AB’s backtest engine will be
executed one additional time to process all the signals generated in Phase 1.
AmiBroker CBT Intensive - Matt Radtke 9
Multithreading
Phase 1
• When the AFL is executed for the first symbol in the watchlist, only one
thread will be used. This condition can be recognized with the code below
and is the best time to perform initialization and other one-time tasks like
ranking.
if (Status(“stocknum” == 0)
• All additional symbols in the watchlist will be processed in parallel, up to the
number of threads supported by your CPU (generally double the number of
cores).
• If not using P&A, you may have fewer bars of data if the current symbol’s
history starts after the start date of your analysis range.
Phase 2
• Always executes in a single thread
AmiBroker CBT Intensive - Matt Radtke 10
Number of Bars
General
• Bars are numbered from 0 to BarCount-1
• The number of bars always corresponds to the number of elements in each
AmiBroker array, even compressed arrays
Phase 1
• Baseline: number of bars corresponds to data elements in your analysis
date range
• AmiBroker will add bars from before the start date to allow indicators to be
properly calculated. For example, using MA(C,200) will result in at least 200
extra bars of data, if available.
• If not using P&A, you may have fewer bars of data if the current symbol’s
history starts after the start date of your analysis range.
Phase 2
• Number of bars corresponds to data elements in your analysis date range
• No “extra” historical bars
AmiBroker CBT Intensive - Matt Radtke 11
Pad & Align
Pad & Align guarantees that each symbol will have the
same number of bars in Phase 1. Built-in arrays may have
values of Null.
Imperative when ranking with StaticVarGenerateRanks().
Generally useful in nearly all situations, because it makes
the Phase 2 bars more predictable.
AmiBroker CBT Intensive - Matt Radtke 12
Backtester Settings
SetCustomBacktestProc()
The function that will allow us to specify that we want to
use a custom backtest procedure (CBT).
SetBacktestMode()
Determines how much signal filtering AmiBroker does
• BacktestRegular
• BacktestRegularRaw
AmiBroker CBT Intensive - Matt Radtke 13
Data Constructs
AmiBroker CBT Intensive - Matt Radtke 14
Static Variables
Static variables are the most efficient way to store symbol-
specific data from Phase 1 for use in Phase 2 (CBT).
Functions:
• StaticVarSet() / StaticVarGet()
• StaticVarSetText() / StaticVarGetText()
• StaticVarRemove()
Develop a standard and stick to it! For example:
ATR10 = ATR(10);
StaticVarSet(Name()+”ATR10”, ATR10);
AmiBroker CBT Intensive - Matt Radtke 15
Arrays
AmiBroker’s array (vector) processing abilities are one of it’s greatest
strengths, and the key to execution speed. Array processing is also one of
the areas that new AFL developers struggle with the most.
Think of an array as a single column in a spreadsheet, with the elements
(cells) numbered from 0 to BarCount-1. Compressed arrays still have
BarCount elements, but some elements will contain Null values.
When you perform an operation on an array or multiple arrays, the
operation is actually applied to each element in parallel (at least
conceptually).
Many AB functions accept arrays as arguments and also return arrays.
AmiBroker CBT Intensive - Matt Radtke 16
Matrices
Recent versions of AB introduced the concept of the Matrix:
a two-dimensional array with the number of rows and
columns specified by the user. A matrix can be visualized
as an entire spreadsheet instead of just one column.
myMatrix = Matrix(100, 3, -1);
Matrices have their own set of functions for performing
operations like Transpose, Sum, Inverse, Sort, etc.
They also provide the ability to create a data structure with
more elements than an array.
AmiBroker CBT Intensive - Matt Radtke 17
User Functions
AmiBroker CBT Intensive - Matt Radtke 18
Introduction
A function is a reusable piece of code that performs some task. AmiBroker
provides hundreds of built-in functions including:
• Indicators: RSI(), MA(), ATR(), ADX()
• Math: sqrt(), round(), sin()
• Array Manipulation: ValueWhen(), TimeFrameCompress()
• Helper Functions: SetPositionSize()
• Environment: Status(), SetOption()
• Many, many others: See the categorized list in the AFL Help files
AmiBroker also allows you to create your own functions. We will use this
feature repeatedly throughout the course.
AmiBroker CBT Intensive - Matt Radtke 19
Definition
A User Function must be defined before it can be used. The basic structure of a
function is:
function MySquare(paramVal)
{
sqr = paramVal * paramVal;
return sqr;
}
• function is an AmiBroker keyword. It tells AB that we’re defining our own
function. Notice there is no semi-colon at the end of this line.
• MySquare is the name of our function. It’s how we will call the function later.
• paramVal is an input parameter (argument). Multiple parameter names are
separated by commas.
• return is an AmiBroker keyword that tells AmiBroker to assign the value of
sq to a variable which was assigned the function name, e.g.
square = MySquare(3);
AmiBroker CBT Intensive - Matt Radtke 20
Scope
Function parameter names (paramVal) and variable names that are defined
within the function definition (sqr) have Local Scope. They can only be
referenced within the function definition.
The AmiBroker global keyword allows you to give a variable Global Scope so
that it is visible outside the function definition. This is generally discouraged, as
it somewhat defeats the purpose of having a function. However, there are times
that this is an appropriate mechanism to use.
Functions can also reference any global variables that were defined before the
function definition. However, this introduces dependencies that make it harder
to reuse your functions in other AFL files.
AmiBroker CBT Intensive - Matt Radtke 21
Execution
The code within a function is executed when we call it:
square = MySquare(3);
If your function doesn’t return a value (or even if it does and you don’t care
about the return), you can call it without assigning it to a variable:
ProcessEntries(bar);
If the function definition is a cookie recipe, then calling the function is the act of
combining the ingredients and baking the cookies.
AmiBroker CBT Intensive - Matt Radtke 22
Object Model
AmiBroker CBT Intensive - Matt Radtke 23
Overview
In software engineering terms, an Object is a construct
which encapsulates both data (Properties) and functionality
(Methods).
The definition of an object is called a Class. If the Class is a
blueprint, the Object is a house. We often have many
instances of the same Object, all built from the same Class
definition, but with each Object holding different data.
Similar Object instances are often grouped together into a
Collection.
AmiBroker CBT Intensive - Matt Radtke 24
AmiBroker Object Model
Find and bookmark this page in the AmiBroker Help file:
Porfolio Backtester Interface Reference Guide
Yes, the ‘t’ is missing in “Portfolio”. Deal with it. This page is
going to be your new favorite reading material.
AmiBroker CBT Intensive - Matt Radtke 25
AmiBroker Objects
AmiBroker has four classes of Objects:
1. Backtester
• The top-level object that represents the backtest process and data
• One instance
2. Signal
• Represents each entry, exit, and scale-in signal
• One instance per symbol per signal per bar
3. Trade
• Represents an open or closed trade
• One instance per symbol per trade entry
• Scale-ins and outs affect a single trade object
4. Stats
• Provides access to the built-in AB metrics after completion of the
backtest
• One Instance
AmiBroker CBT Intensive - Matt Radtke 26
Collections and Iteration
AmiBroker maintains collections of the following types of objects:
1. Signals
2. Open Trades
3. Closed Trades
Sometimes we can search for a specific member of a collection, for example
with the Backtester Object method FindOpenPos():
trade = [Link]([Link]);
More frequently, we iterate through an entire collection:
for (sig = [Link](bar); sig; sig = [Link](bar))
This allows us to access each object in the collection, one after the other,
without knowing the underlying details of how the collection is maintained.
AmiBroker CBT Intensive - Matt Radtke 27
Homework
AmiBroker CBT Intensive - Matt Radtke 28
Homework
1. Read this page in the AmiBroker Help file:
Porfolio Backtester Interface Reference Guide
2. Read it again after Session 2, and yet another time after
Session 3. No, really.
3. Define and call a function. It can be as trivial as
calculating your own simple moving average. Call it with
different parameters. Use an Exploration to compare the
output of your function with a built-in AB function.
4. Create a Matrix with at least three columns. Fill it with
values, and use _TRACE(), the AB debugger, or an
Exploration to verify that the values are assigned as you
expected.
AmiBroker CBT Intensive - Matt Radtke 29