Professional Documents
Culture Documents
AmiBroker Program
AmiBroker Program
AmiBroker
AFL Programming
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
This Book is dedicated to my family members
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
Copyright © 2019 by Ajan K K
All rights reserved
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
Chapter 0
0.1 An Introduction
Before we start learning AFL Programming, certain clarifications have to be
made with regard to whom this course is intended for, the prerequisites and
other requirements, if any.
• The material in this book is intended for the absolute beginner in AFL
Programming. Only the most basic aspects of the AFL programming will
be dealt with in this book. Experienced AFL programmers may not get
anything useful in this book.
• This Book will not teach anything about Technical Analysis.
• No attempt is made in this book to teach Trading Strategies, other than
references to it, when coding examples are required to be furnished.
• To learn AFL, you should have AmiBroker installed in your computer.
• This book focuses only on the AFL programming part. The reader should
know how to load charts, place technical indicators on the chart etc.
These are well described in the User Manual of AmiBroker.
0.2 What is AmiBroker?
AmiBroker is a complete and advanced trading solution. It has many tools
including Charting, Backtesting, Optimizing etc. You can display Charts, add
indicators, create watchlists, create trading strategies and back test these
trading strategies, create portfolios etc. It is not a mere Charting tool. Any one
showing interest in AmiBroker, means that he is showing interest in learning
AFL, or at least should know how to use AFL developed by else body in their
trading decisions.
0.3 Is AFL easy to learn?
This is a difficult question to answer. The answer is Yes and No. If you are
already proficient in any other programming language, then there should not
be any problem. It will be a matter of learning the syntax, keywords, functions
etc of the new language. Everything should follow very easily. Otherwise, it
should take time – there is a learning curve. The fact about AFL is that it is
not a general purpose language like C, Pascal, Python etc but only specific to
deal with financial quotation values like Close, Open, High, Low, Volume,
Open Interest etc. And that AFL is an array programming, will make some
confusions to the beginner programmer. Soon the understanding that an
Array is something like the English collective nouns such as a “Library” of
books, a “Herd” of cattle, a “Panel” of experts etc. will relieve many of the
doubts. An Array is simply a collection of numbers. Anything we do on the
Array means, we are intending to do on every member of the Array and not on
any single member of the Array. By studying carefully and doing lot of
exercises, any beginner can learn AFL and master it.
0.4 The Formula Editor
The program statements are entered into an Editor called the Formula Editor.
Like all Windows programs, Amibroker provides multiple ways of launching
the Formula Editor. From the Analysis Menu Click the Formula Editor…. This
will open the Formula Editor as shown below.
We have successfully written our first AFL program. The formula contains only
one statement, that is a printf( ) function. We will be using the printf function
quite often from next Chapter onward. So let’s look at the function carefully.
The printf function is used to print formatted output to the output window.
Syntax:
printf( formatstr,…)
The printf function formats and prints a series of characters and values to the
output window. If arguments follow the format string, the format string must
contain specifications that determine the output format for the arguments.
• For numbers use %f or %g formatting.
• To print a single % sign use %% in the format string.
• A \n placed inside the format string will print a new line.
Example of a format string:
“The scores in Math AND History of the student are \n%g\n%g”, 78,89
Whatever within the inverted commas is the format string. 78 and 89 are two
arguments that follow the format string. The number of arguments should
match the number of %g specifications inside the format string. The two \n
are given for printing new lines. Place the above format string inside a printf
statement in the Formula window of Chart commentary. Click the
Commentary tab to see the results as shown in Fig. 0.6 below.
Fig. 0.6 Commentary results
To display a decimal number use the %f format. The total width and number
of decimals to be printed can be specified by %w.d f format, where w will be
the total width used for printing the number and d will be the number of digits
after the decimal point.
printf( “%5.2 f”, 25.6462);
The above printf statement results in the following value.
25.65
Note to accommodate a total width of 5, first a space is printed and the
number is rounded and not truncated.
Exercise 0.1
1. What will be the output of the following printf?
printf( “%g,%3.1f”,8,6.2 );
a) 8 6.2
b) 8,6.2
c) 8 6.20
Solution:
b)8,6.2 Whatever string placed within the quotes will be printed out. The
comma ( , ) is necessarily to be printed.
2. Write a printf formula to get the following output.
My Name is :
Jacob
Solution:
printf( “My Name is : \nJacob”);
3. Which formula gives the correct output as given below.
Your percentage score is 50.6%
a) printf( “Your percentage score is %4.1f%%”,50.6);
b) printf( “Your percentage score is %5.1%”,50.6);
c) printf(“ Your percentage score is %5.1%%”,50.6);
Solution:
The correct answer is a). Though the third option c) looks correct, it will print
an extra space between ‘is’ and 50.6.
4. What is wrong with the following printf statement?.
printf( “Heights of the athletes are %4.1f,%4.1f,%4.1f”,6.3,6.1);
Solution:
Three format specifications given. But only two arguments are provided. These
have to be matched. This will report an error.
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
Chapter 1
Introduction to AFL
To learn a new language we must first study its basic building blocks.
Assume that we want to learn the English language. How do we start our
study? We start our learning process by first studying the alphabets of the
language. Simple and common words are then grasped – spelling and
meaning. By using the essential building blocks of words, we learn to make
meaningful sentences. The process continues by learning preposition,
adjectives, nouns, verbs, subject, predicate and the grammar of the language.
When learning a computer programming language like the AFL, the idea to
start is the same. We start studying the building blocks of the language. From
elementary building blocks we make complete sentences (in this case
statements). The syntax of the language is then mastered. So what are the
essential building blocks of the AFL? Let us explore it.
Word-like units used and recognized by the AFL interpreter are known as
Tokens. There are different categories of tokens used in AFL. We can
consider these tokens as the basic building blocks of AFL.
There are five classes of tokens in AFL:
Identifiers
Constants
String literals
Operators
Punctuators (also known as separators)
Identifiers
When a child is born, one of the few things we immediately do is to find out a
suitable name for him/her. Why? This is because without a name he or she
loses his/her identity. This is exactly the case with words used in AFL. Those
have to be appropriately named. These are known as identifiers. Identifiers
are the names given to variables and functions used in AFL. There are certain
rules to coin an identifier:
Identifiers can be of any length
Identifiers can contain upper case or lower case letters of the alphabet
(a-z, A-Z)
It can contain the underscore character (“_”)
It can contain the digits (0-9)
The first character must be a letter
Exercise 1.1
Solution:
1. Legal name
2. Illegal. Cannot start with a number. First character must be a letter.
3. Valid name
4. Legally acceptable
5. Illegal. Must start with a character
6. Acceptable name
7. Special characters are not allowed. First character must be a letter.
8. Acceptable name
9. Legal name.
Constants
String Literals
Let us see a practical example of using Constants and String Literals and use
of identifiers. Suppose that during the course of a computer program, the
account in your balance is found to be Rs. 1200. You want to assign this
constant value to an identifier and wish to be notified. The following program
segment serves the purpose.
myBalance = 1200;
notify = “Your balance is: “;
printf( notify + NumToStr( myBalance ) );
In the above code fragment myBalance and notify are named identifiers.
myBalance is assigned the numeric constant 1200. Thereafter the identifier
myBalance holds the number value 1200. The second identifier notify is
assigned a String Literal “Your balance is: “. The printf () command combines
the two identifiers and the following result is printed.
Your balance is 1200
The above program is now shown just to explain how constants and identifiers
are used in an AFL. In an actual program myBalance will not be assigned this
way, but will be computed and the result of that computation will be assigned
to myBalance.
Punctuator
The following are the punctuators (also known as separator) available in AFL:
Parentheses
The open parenthesis ‘(‘ and the close parenthesis ‘)’ are always used
together. They are used for grouping expressions, isolate conditional
expressions and to indicate function calls and parameters. Parentheses
are also used to override normal precedence in calculations.
Examples:
Y=x*5+6
myFunc()
Comma ,
Examples:
Semicolon ;
Example:
myAverage = MA(Close,20);
Equal Sign =
The equal sign (=) separates variable declarations from its initialization.
X = 20;
In the above example the value 20 is assigned to the variable X and the
equal sign separates the variable declaration and its initialization.
There are numerous built in functions in AFL. Some of these functions
use default values of parameters provided within the function. The
equal sign is used to furnish default values of arguments in functions.
Example:
The macd() function uses two parameters, fast and slow. If nothing is
specified by the user, the default values will be fast = 12 and slow = 26.
The dot .
The dot is a member access operator. We will not be using this in this
book.
Operators
Assignment Operator
result = expression;
Here, ‘result’ is the variable and the value of expression is assigned to the
variable.
Examples:
Total = 5 + 3 + 9;
The sum of the right side of = sign is computed and the value 17 is assigned to
the variable Total.
Heading = “Values are computed as shown”;
The text string on the right of assignment operator is assigned to the variable
Heading.
An array of values is calculated on the right hand side and the result is
assigned to the variable longMA. The Moving Average Function MA() will be
discussed later.
In AFL multiple assignments are possible using =.
A = B = C = 52;
Comparison Operator
Symbol Meaning
< Less Than
> Greater than
<= Less than or equal to
>= Greater than or equal to
Arithmetic Operator
The following are the arithmetic operators which can be used in formulas.
Symbol Meaning
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulus ( or remainder)
^ Exponentiation
| Bitwise OR
& Bitwise AND
Logical Operators
There are three logical operators namely AND, NOT and OR.
Symbol Meaning
NOT Logical ‘NOT’. Gives ‘true’ when operated on a ‘false’
value and ‘false’ when operated on a ‘true’ value.
AND Gives ‘true’ only when both operands are ‘true’
OR Gives ‘false’ only when both operands are ‘false’
destinvar op = expr;
where destinvar is the variable, expr is the expression and op is one of the
following arithmetic operators: +,-,*,/,%,&,|
The destinvar op = expr behaves as destinvar = destinvar op expr.
Example:
Typeof() operator
Example:
//Code fragments
X = MACD(); //MACD() is a built-in function which returns an array
Y = LastValue(Close);
//LastValue() returns a scalar, in this case the last period Close Price value
/* A user defined function follows. More about user defined functions in later
Parts of the book
*/
function myFunc()
{
Return 1;
}
With the above code fragments in mind the typeof() operator can be tested.
Fig. 1.1
Now click the Commentary tab to see the results of the typeof() operators used
in the formula window. Fig1.2 below shows the results.
Fig. 1.2
Note that when the type of MACD() is checked only the name MACD is used
without parenthesis. Otherwise it will report an error.
Whitespace
Spaces (blanks), tabs, new line characters and comments are collectively
called whitespace. They can serve to indicate where tokens start and end.
Whitespaces are ignored by the interpreter.
Comments
Comments are pieces of text to annotate a program. These are for the use of
the programmer or anybody else who happen to read the program. The
comments are stripped from the source code while interpreting and parsing.
Two ways of commenting in AFL are:
Examples:
Example:
/*
All the comments can be
placed here……...
*/
No Symbol Meaning
1 ++ Post increment/pre increment
2 -- Post decrement/pre decrement
3 [] Array element (subscript) operator
4 ^ Exponentiation
5 - Negation – Unary minus
6 * Multiplication
7 / Division
8 % Remainder
9 + Addition
10 - Subtraction
11 < Less than
12 > Greater than
13 <= Less than or equal to
14 >= Greater than or equal to
15 == Equal to. The equality check
16 != Not equal to
17 & Bit-wise AND
18 | Bit-wise OR
19 NOT Logical NOT
20 AND Logical AND
21 OR Logical OR
22 = Variable assignment operator
23 Compound assignment operators
Exercise 1.2
Variable Usage
buy Defines “buy”(enter long position) trading rule
sell Defines “sell”(close long position) trading rule
short Defines “short”(short sell ) trading rule
cover Defines “cover”(close short position) trading rule
buyprice Defines buying price array
sellprice Defines selling price array
coverprice Defines buy to cover price array
filter Used in exploration. Controls which symbols/quotes
are accepted
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
Chapter 2
Array Programming
2.1 Why AFL is called an array programming Language?
What is an Array?
An array (or Vector) is simply a list of numbers. Suppose an array A has the
following values in the list 2,6,8,5. Then a mathematical operation like A*2
will change all the values in the original array to be multiplied by 2 and the
result will be a new array with values 4,12,16,10. Similarly if B is an array
with values 4,5,3,2 then the operation A + B yield a new array with values of
the corresponding array values added together and the result is an array with
values 6,11,11,7.
In AFL there are some predefined built-in price array identifiers. They identify
specific price fields that the formula can operate on. The valid price array
identifiers are open, high, low, close, volume, openint, avg. These
identifiers can be abbreviated as shown in the table below. For example for
identifying the open price we can either use open or O. Also note that the
identifiers are not case sensitive. That is high and HIGH both refer to the same
array.
Long Name Abbreviation
Open O
High H
Low L
Close C
Volume V
OpenInt OI
An AFL array can be thought of as a list of numbers with one number in the
list for each bar in the currently selected chart. What these numbers depends
on the type of Array. For example for the Open array, each number represents
the opening price of the corresponding bar in the chart. MA(Close,50) array
represents the calculated value of moving average for 50 periods for each
corresponding bar. In this case the first 49 bars will not be having moving
average values due to insufficient data, and these will be filled with ‘Null’.
Example of use of price identifiers in AFL formulas:
MA( Close, 10 );
Now the variable ma10 will be an array, and it will have Barcount number of
elements, just as the case of Close. However, the first 10 elements of ma10
will not have values, and will be filled with “NULL”. When we plot ma10 on the
chart, the plot starts only from the 11th element onward.
midValue = (High+Low)/2;
When AFL is evaluating statements like the above one, it does not need to re-
interpret the code for each bar. Instead it takes the High array and Low array
and adds corresponding array elements in single stage. Then the resulting
array elements are divided by 2 in single stage. The resulting array is stored
in the variable midValue.
Let us visualize the Close array as a row of cells. Let there be 7 elements in
the array. The row index starts from 0 and the last index will be 6 and not 7.
Here is how the Close array looks like:
Index 0 1 2 3 4 5 6
Close 10.5 10.6 10.6 10.4 10.3 10.5 10.6
Index 0 1 2 3 4 5 6
For each index the value of open and close will be added and a new array
created will be assigned to the variable A.
Another example:
Index 0 1 2 3 4 5 6
arrayidentifier[ expression ];
The price arrays O, H, L, C etc. are populated from the data of the selected
(displayed) chart. As we change the symbols of stocks and hence the displayed
chart, the array values get changed. How many elements will be in the above
arrays? There will be BarCount number of elements in the arrays. Open the
Guru commentary and type the following code to print the barcount value of
the displayed chart.
Arrays can be created manually by the following method. Let the array to be
created be named A. We then assign elements of the array using the subscript
operator.
A[0] = 2;
A[1] = 3;
A[2] = 5;
A[3] = 7;
A[4] = 6;
The above assignments creates an array A having its first five elements
assigned as above. Does it mean that the array A have only 5 elements? No,
it will have barcount number of elements and barcount will depend on the
number of bars in the selected chart which is currently displayed. The
Typeof(A) will be ‘array’. Now if we multiply A by 2, each element of A will be
multiplied by 2.
B = A*2;
Let C = A + B;
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
Fig. 2.3
Fig 2.4
Fig 2.3 and Fig 2.4 shows the formula and commentary windows for the
example above.
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
Exercise 2:
1. With the value of Array C as computed above what will be the return of
typeof(C)?
a. Array
b. Number
c. Undefined
2. What will be the typeof(C[1])?
a. Undefined
b. Number
c. An error is reported
3. Let O[0],O[1],O[2],O[3] respectively be 455,456,455.6 and 457 and C[0],
C[1], C[2], C[3] respectively be 455.7,455.5.456 and 457.3. What will be the
values of the first 4 elements of the array C > O?
4. On a particular day the Close price is 45.6, Open price is 44.8, Low price is
44.2 and High price is 45.1. Which of the following give a True value?
a) C > O
b) O < L
c) H > C
5. Calculate range of the current trading day.
Solution:
5. The range is defined as the difference between the high price and the
low price. The answer is H – L.
Chapter 3
Functions in AFL
3.1 What are Functions?
User definable functions allow to encapsulate user code into easy to use
modules that can be used in many places without need to copy the same code
over and over again. All functions must have a definition. The function
definition includes the function body, the code that executes when the
function is called. The syntax for function definition is given below:
[return result;]
}
Solution:
Here findSum is the name of the function. Two parameters are num1
and num2. Within the body of the function these are added and
returned. We can call the function such as:
Y = findSum( 5, 8 ); // Gives a value of 13 and assigned to Y
Solution:
function isGreenCandle ( )
{
result = iif( C > O, True, False );
return result;
Unlike some other common programming languages, AFL does not require
variables and its type to be declared ahead of its use. A variable is treated as
local or global depending upon where it is first used. If a given variable first
appears outside a function, it is treated as a global variable. If a variable first
appears inside a function then it is treated as a local variable and confined
within the function. If you try to access the variable outside the function an
error is reported.
function test(a,b)
{
x = 20;
return (a+b);
}
printf(“%g”,x);
In the above program variable x is initialized inside the function and hence is
a local variable. Trying to print x outside the function throws an error as
shown below.
The default behavior of local and global variables can be overridden by global
and local keywords.
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
Chapter 4
The code fragments we saw till now, starts execution at the top of the
program, goes in a progressive manner sequentially until the end of the
program. Real life problems cannot always be made to program this way.
Depending on situations that may come on the way, some sequential breaks
will have to be made. Sometimes certain parts of the program will have to be
executed a certain number of times. The conditional execution of a program
need the ability to check conditions and change the behavior of the program
accordingly. Conditional statements give us this ability.
The if else statement in AFL is used for conditional execution. The if and else
are keywords in AFL and should not be used for variable names.
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
Fig. 4.1 If Logic
Examples:
else
printf(“Division by zero not allowed”);
if ( p%2 == 0 )
printf(“p is even”);
else
printf(“p is odd”);
if (expression1)
statements1
if (expression2)
Statements2
else
Statements3
if (i>0)
{
if (j > i )
x = j;
}
else
x = i;
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
4.3 Use of Arrays in if statement.
You cannot use Arrays directly in if statements. The following code will not
work but throws an error.
But the following code works and checks whether the last candle close was
greater than the open.
Exercise 4.1
Solution:
Solution:
//Leap year check. Let year_check be the variable holding the year to be
//checked
if ( year_check%400 == 0 )
printf( “Is a leap year”);
else
if ( year_check%100 == 0)
printf( “Is not a leap year”);
else
if ( year_check%4 == 0)
printf( “Is leap year”);
else
printf(“Not a leap lear”);
• do
• while
• for
while statement
The while statement lets you repeat a statement until a specified expression
becomes false.
Syntax
Examples:
Solution:
number = 1;
while ( number <= 5 )
{
printf(“%g\n”,number); //%g is the format specifier for printing a
// number ( %d will not work).
number++; //This equivalent to number = number +1
}
Result:
1
2
3
4
5
2. Write a program to print only the even numbers between 1 and 50.
Solution:
i = 1;
while ( i <= 50 )
{
if ( i%2 == 0 ) //Here we check for even number
printf( “%g “,i); //Print only the even number
i++;
}
Result:
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48
50
do-while statement
The do-while statement lets you repeat a statement or compound statement until
a specified expression becomes false.
Syntax:
The expression is evaluated after the body of the statement. Therefor the
statement is always executed at least once.
The logic proceeds as follows:
1. x = 10;
do
{
printf(“%g “,x);
x = x -2;
}
while ( x > 0 );
Result: 10 8 6 4 2
Printf statement prints the initial value of x which is 10. The x value is
then decremented by 2. Expression is then tested and since it becomes
true the statements are executed to print value 8, and the process
repeated up to 2. Thereafter the do-while statement terminates.
2. Write a program to find the sum of first 100 natural numbers. That is,
we are required to find 1+2+3+4+………………+99+100.
We will start with two variables i and total. Initialize i to be 1 and total
to 0.
//Sum to the first 100 natural numbers. Demo of do-while loop
i = 1;
total = 0;
do
{
total = total +i;
i++;
}
while ( i <= 100 );
The counter i will be incremented and added to total until i equals 100.
You should get a result of 5050. The Guru Chart commentary for this is
shown in Fig. 4.5 and Fig. 4.6.
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
for statement
Syntax:
Examples:
2. Build a 5 period simple moving average of Close price using for loop.
MyAverage[0] =4;
MyAverage[1] =5;
MyAverage[2] = 6;
MyAverage[3] = 2;
MyAverage[4] = 9;
The above statements creates an array MyAverage having its first five
elements assigned the above values. Typeof(MyAverage) will be ‘array’.
The 5 period moving average of Close is the average of the sum of the prior
5 Closes. Since 5 values are required to calculate 5 period moving average, the
first 4 elements of close will not be having the average due to insufficient data.
The first 4 values of moving average array will be Null. If we have a counter
variable i, MyAverage can be generalized as:
MyAverage[i] = ( Close[i] + Close[i-1] + Close[i-2] + Close[i-3] + Close[i-4] )/5.
Note that the array indexes start from zero. We can let i start from 4 and
iterate the calculation until (Barcount -1) which will be the last element of the
Close array. This will make the MyAverage Array.
Syntax:
switch (expression)
{
case constant-expression1:
Statements;
case constant-expression2:
statements;
……
……
case constant-expressionN:
statements;
default:
statements;
}
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
Fig. 4.8 Switch case logic
This is called the immediate if function. The iif() function is used to create
conditional assignments.
Syntax:
The function returns an array. If the expression evaluates to true, the function
returns the true-part, otherwise the false-part. The returned value should be
assigned to a variable for further use. The iif() function is very important and
commonly used.
Examples:
Result: Well Done. Here “Well Done” will be printed for either Grade B
or Grade C.
Exercise 4.2
1. Write a program using while loop for finding the HCF and LCM of two
numbers.
Solution:
Solution:
Solution:
The first two numbers are known. We can print that anyway. The
looping starts from the third number onward.
firstNum = 0;
secondNum = 1;
printf( “%g, %g, “, firstNum, secondNum); //0 and 1 are printed.
X = 500;
nextTerm = firstNum + secondNum;
while ( nextTerm <= X )
{
printf( “%g, “, nextTerm );
firstNum = secondNum;
secondNum = nextTerm;
nextTerm = firstNum + secondNum;
}
Telegram
@librosselectosdetrading
@cursos_trading_rank
@ranking_trading_courses
@Libros_Trading_Algoritmico
Chapter 5
5.1 Introduction
The plot() function plots a graph with the data points given in an array,
provided to the function as a parameter.
The function returns a number. The function plots a graph using the array
data.
Parameters:
• array - This contains the data to be plotted
• name - This defines the graph name to be displayed in the title bar
• color - This defines the color of the plot
• style - Style determines the style of the plot, such as line chart,
histogram chart, thick line etc.
Style can be a combination of one or more of the following.
• styleLine normal line chart ( This is the default value )
• styleHistogram histogram chart
• styleThick fat(thick) line – in combination with other styles
• styleDots dotted line
• styleDashed dashed line style
• styleCandle candlestick chart
• styleBar traditional bar chart
This is not a complete list. For complete style constants see the User’s
Guide.
Examples:
Solution:
The function ADX() returns an array of Average Directional Index values for
default 14 period.
Plot(ADX(),”ADX”,colorRed,styleLine);
Launch AmiBroker. Click on ‘Analysis’. From the drop down menu click
‘Formula Editor’. This loads the Formula Editor.
Type in the above code. Now the Editor should look like the figure below.
2. Plot the MACD value as a histogram with points above zero in green and
those below zero in red.
Solution:
This function allows the user to change the color of the plot dynamically while
displaying the chart. Rather than explicitly defining the color in plot function,
we can use the ParamColor() function. The syntax of paramcolor() is:
This function adds a user definable parameter, which will be accessible via the
Parameters dialog. Right-click over the chart pane and select “Parameters” to
change chart parameters.
• “name” defines parameter name that will be displayed in the
Parameters dialog box.
• defaultcolor defines the default color value of the parameter
Example:
The Relative Strength Index (RSI) is plotted. The ParamColor() function is used
in the place of color parameter of the plot() function. Note that the style
parameter is not used, which defaults to styleLine.
Launch the AFL Editor and type the above code. Verify the syntax for errors
and apply the indicator to display the following chart.
In the previous plots we hard coded the style parameter. With ParamStyle()
function we can allow the user to dynamically change the style of the plot from
the Parameters dialog box. The syntax of paramstyle function is:
The Param function is a very important function and is perhaps one of the
most used functions in AFL. The param function add user definable numeric
parameters.
Syntax:
Example:
Fig 5.5 Demo of Param() Function. The Parameter dialog box is also
shown.
Fig 5.5 shows the plot of the function. Note how the “name” parameters
are mapped to the Parameter dialog box. The default parameter 12 was
changed to 100 in the dialog box.
The Ref function is the easy way to refer the previous values of an array. The
use does not limit to arrays O, H, L, C etc. but on all derived arrays. This is an
important function used extensively in AFL programming.
The formula ref(Close, -5) refers to the Close price 5 periods ago. Let’s assign
this to a variable x.
x = ref( Close, -5 );
The variable x will be an array. The value of x will be the close price 5 periods
ago. The figure below demonstrates this. The value of x will be 45.5, the close
price of candle 5 (See figure 5.6), that is 45.5. Both the arrays Close and x
will have Barcount number of elements. However, the x array elements with
index 0 to 4 (5 elements) will be “null”.
QUIZ::
Solution:
a. They will be same.
AFL is equipped with lot of Indicator functions. These are used for the
Technical Analysis of the security concerned. Many of them can be charted
and studied. Some of the functions are given below:
• AccDist accumulation/distribution
• Adx Average directional index
• ATR Average true range
• BBandBot Bottom bollinger band
• BBandTop Top bollinger band
• CCI commodity channel index
• MACD moving average convergence/divergence
• OBV on balance volume
• RSI relative strength index
• StochD stochastic slow %D
• StochK stochastic slow %K
This list is not complete. Refer to the AmiBroker User’s Manual for the full list
of indicator functions, its syntax and usage. As an example let’s see how the
MACD is used. MACD, the moving average convergence/divergence is a trend
indicator. It is the difference between two moving averages.
The EMA is the exponential moving average. 12 and 26 are the usual values
used in the calculation of MACD. The Exponential moving averages are
calculated on the security’s closing price. EMA(Close,12) is the function to
generate the ema values. In the MACD system a 9 period EMA of the MACD
itself is used as a signal line.
This returns an array of values of macd using fast and slow averaging periods.
While calling the function the desired values of the two variables can be given.
If no values are given the default values of 12 and 26 are used.
Example:
Plot ( MACD(),”Macd”,colorBlue,styleLine);
Plot ( Signal(), “MacdSignal”,colorRed,styleLine);
The above code plots the Macd line in Blue color and Signal line in Red color
in a new pane. The resulting plot is given in Fig. 5.7 below.
The function returns an array and gives a True when array1 crosses above
array2 from below otherwise the result will be False(0). To determine when
array1 cross array2 from above use cross(array2,array1). Fig. 5.8 shows two
arrays array1 and array2 plotted. At point A array1 is crossing array2 from
below, while at point B, the array1 is crossing array2 from above.
Fig 5.8 Crossing of arrays.
Examples:
lengthFast = 10;
lengthSlow = 50;
fastMA = MA( Close, lengthFast);
slowMA = MA( Close, lengthSlow);
longEntry = Cross( fastMA, slowMA);
longExit = Cross( slowMA, fastMA);
HHV calculates the highest high value in the passed ARRAY over the
preceding periods(periods include the current day). The formula HHV(Close, 5)
gives the highest high close price over the previous 5 periods. Fig 5.10
shows how HHV works. HHV( Close, 5 ) gives 117.15. Most recent candle is
counted in “periods”.
Fig 5.10 HHV function
The function returns an Array, and calculates the number of periods that have
passed since the ARRAY have reached its peak within the period periods. For
the case shown in the above Fig 5.10 HHVBars(Close,5) gives the value 3.
This function calculates the highest value in the ARRAY since the first day
loaded in the chart.
Calculates the number of bars that have passed since the ARRAY’s highest
value. HighestBars (Close) returns the number of periods that have passed
since the closing price reached its peak.
Returns the highest ARRAY value since EXPRESSION was true on the Nth
most recent occurrence.
Example:
This returns the highest close price since the Close has crossed the 20 period
MA of Close. To make this clear see the Fig below.
This returns the number of bars since highest ARRAY value since
EXPRESSION was true on the Nth most recent occurrence. If we apply this to
the chart above, the return should be 3, the last three bars.
The functions described from 5.9 to 5.13 have their “Lowest” counterparts
namely LLV, LLVBars, Lowest, LowestBars, LowestSince and
LowestSinceBars. These functions are similar in nature and are not discussed
separately.
5.15 BarsSince
This calculates the number of bars that have passed since ARRAY was true. It
counts how much time (in bars) has passed since an event occurred.
BarsSince( Close > 150 ) returns the number of periods that have passed since
the closing price was greater than 150. If this happens to be currently true, it
will return 0.
Take Fig. 5.12 for illustrating the idea of BarsSince. In the figure the blue line
is the 20 period EMA. Looking at the figure we can see that last seven bars
have passed since the Close was above the 20 period EMA. AFL for getting
number of bars since Close was above 20 EMA can be written as:
In the same figure the Close has been below the 20 period EMA for the past 7
days. But the following formula will not give the desired result. It will return a
value of 0 since at the current bar the passed array is true.
In the above, y will be 0. To determine how many bars the Array was
remaining true, another logic has to be applied.
condition = (MA( Close, 10 ) > MA( Close, 20 ) ) AND (MA( Close, 20) >
MA( Close, 30 ))
To get the number of bars this can be negated and applied to the BarsSince
Function.
barsCount = BarsSince( !Condition );
Fig 5.13 shows an illustration of the condition specified. Note the perfect
alignment of the moving averages shows the possibility of a long entry.
Exercise 5.1
Solution:
Solution:
5.16 GapDown
There are some basic price pattern detection functions in AFL. One among
them is the GapDown() Function. It returns an Array and gives a value of 1 or
True on the day the security’s price gaps down, meaning that yesterday’s
low is greater than today’s high. Otherwise the result will be False.
Fig 5.14 shows an example of a gap down candle. In this case the function
GapDown() returns a True value.
QUIZ:
If x = GapDown(), how many elements of the array x will have values of either
1 (True ) or 0 (False)?
a. Barcount number of elements
b. Barcount-1 number of elements
c. Barcount-2 number of elements
Solution:
5.17 GapUp
This function gives a True value when the security’s price gaps up, that is,
when yesterday’s high is lower than today’s low.
x = GapUp()
5.18 Inside
The function Inside(), which returns an array, gives a value of True(1) when
today’s high is less than yesterday’s high and today’s low is greater than
yesterday’s low. Such a candle is called an inside day candle.
Function Outside() detects an outside day, gives a return value of True when
an outside day occurs. Fig 5.17 shows an outside day.
Exercise 5.2
Solution:
countTrue = 0;
countFalse = 0;
//Generate the x array
x = OutSide();
for ( i = 1; i < barcount ; i++)
{
if (x[i] == True)
countTrue+=1;
else
countFalse+=1;
}
printf(“Total of Trues = %g\nTotal of Falses =
%g”,countTrue,countFalse);
Result in my system:
Total of ‘True’s = 240
Total of ‘False’s = 1778
2. Write a code to generate a buy signal for the strategy given below:
Solution:
We are given three conditions to satisfy a buy signal. The first condition
can be written as:
We explicitly used the period 14, though it was not necessary. The
second condition can be written as:
The third condition requires that the Relative Strength Index is greater
than 70 for atleast 4 bars. There is a function called RSI() to determine
the Relative Strength Index. Combine with BarsSince function we can
frame the third condition.
condC will be true only when the RSI() is greater than 70 for atleast 4 bars.
Combine all the three conditions to get the buy signal.
5.20 BarIndex
This returns an array of zero based bar indices. That is the array will have
values from 0 to barcount-1.
Syntax BarIndex()
QUIZ
5.21 BeginValue
5.22 EndValue
Similar to the function BeginValue. The return value will be the end of the
range or the last bar as the case may be.
Example:
Define a range by double clicking the start of the range and the end of the
range. Write a program to compute the Close prices at the begin and end of
the range. Determine the percent price rise or decrease as the case may be
and print appropriate message. If the prices happen to be same, notify that
also.
5.23 abs
There are a large number of math functions included in AFL to empower the
math capabilities of the programs written in AFL. The abs function accepts a
number or an Array as its parameter, and returns a number or Array. The
function returns the absolute value of the number or the Array.
5.24 ceil
Accepts a number or Array and calculates the lowest integer that is greater
than the number or Array.
5.25 floor
This calculates the highest integer that is less than the number or Array
passed as parameter.
5.26 int
5.27 frac
The frac eleminates the integer portion of the parameter passed and returns
the fractional part.
frac(5.36) returns 0.36 and frac(-4.21) returns -0.21. Note the negative sign is
retained.
These functions accepts two parameters numbers and/or arrays. They return
the maximum or minimum of the two parameters passed.
Example:
If we want to ascertain whether the Close is greater than the 10 MA and also
greater than 20 MA, a formula can be written as:
5.29 round
5.30 Sum
This function takes two parameters Array and periods. It calculates the
cumulative sum of the Array for a specified number of look back periods
including today.
Example:
Since the first parameter is an Array, which can be any derivative of arrays of
price values, its moving averages or anything like that, many interesting and
useful results can be derived. As a simple example, suppose it is desired to
examine how many bars closed above the 10 day simple moving average of
Close within a period of 40 days. We can use the sum function to retrieve the
desired result as shown below:
It returns an array and calculates the cumulative sum of the Array from the
first period in the chart.
Cum( 1 ) keeps adding 1 to its previous value. The first value will be 1 and it
just keeps adding 1 to its prior value. So what will be the last value of the
array? It should be Barcount. Check it in the Guru commentary.
QUIZ:
Solution:
SetBarsRequired( sbrAll );
Plot( Cum( 1 ), “”, colorGold );
Check User Manual for details. ]
5.32 ROC
It may quite often required to find out the percentage change in the price
value or any other array over a specified period of time. The function ROC
gives the percentage rate of change.
The function returns an array. Note the last two parameters are optional as
indicated by the square brackets. If omitted the default values are assumed.
ROC (Close) returns the 12 period percentage rate of change in the Close price
with absmode = False.
Example:
Solution:
This is simple. We have the ROC function to get the percentage rate of change.
The formula can be written as:
The value of buySignal will be either True or False. If True long entry can be
initiated.
5.33 ValueWhen
Syntax:
This function returns the value of the “Array” when the “Expression” was true
on the nth most recent occurrence. The default value of n is 1.
In the above formula, the return value will be the value of MACD() on the first
occurrence of the crossing of the Close price above its 5 period moving
average.
5.34 DayOfWeek
The returned array has values 0 to 6 representing the days of the week.
0 – Sunday
1 – Monday
2 – Tuesday
3 – Wednesday
4 – Thursday
5 – Friday
6 – Saturday
Example:
5.35 PlotShapes
Syntax:
Parameters:
• shape defines the type of the symbol to be plotted. Common shape
constants are shown below.
shapeNone
shapeUpArrow
shapeDownArrow
shapeHollowUpArrow
shapeHollowDownArrow
shapeUpTriangle
shapeDownTriangle
shapeCircle
shapeSquare
There are more constants available.
• Color defines the color of the shape symbol
• layer defines layer number on which shapes are plotted. This defaults to
layer 0
• yposition defines Y-position where shapes are plotted. By default they
are plotted around graph0, the first indicator.
• offset is the distance parameter, defaults to -12.
Example:
A buy signal occurs when the Close price crosses the 10 day moving average.
Plot a green arrow whenever a buy signal occurs.
Solution:
Exercise 5.3
1. Write an AFL code to plot the 20 day moving average of Close. When the
moving average rises the plot should be in green color and while the MA
value decreases, plot in red.
Solution:
• Tenkan Sen
• Kijun Sen
• Senkou Span A
• Senkou Span B
• Chikou
We will try to plot each of the five components as part of our exercise. First
consider the Tenkan Sen. It is calculated by averaging the highest high
and the lowest low for the previous 9 periods.
Write an AFL code to calculate and plot the Tenkan Sen Array. Also plot
the 9 period Simple Moving Average and compare the plots.
Solution:
There should not be any difficulty in doing this. We have the HHV and
LLV functions to calculate the highest high and lowest low values over a
specified period.
//Plot of Tenkan Sen
//Define the Tenkan Sen period
tenkanSenPeriod = Param(“Tenkan Period”,9, 5, 50, 1 );
tenkanSen = ( HHV( High, tenkanSenPeriod ) +
LLV( Low, tenkanSenPeriod )) / 2;
Plot(tenkansen, “Tenkan Sen”,colorGreen,
styleLine | styleDashed | styleThick );
//Plot the simple moving averages
Plot( MA( Close,9 ),”MA-9”, colorLightOrange,styleLine );
Fig. 5.21 shows the plot of Tenkan Sen. While the 9 period Simple
moving average smooths the price, the Tenkan Sen shows periods of
flattening like at points A and B.
Solution:
3. Senkou Span A and Senkou Span B are discussed together. The Senkou
Span A is the average of the Tenkan Sen and Kijun Sen and is projected
26 days in the future on the chart.
Write an AFL program to calculate and plot Senkou Span A and Senkou
Span B. The area between the two lines is called the Kumo Cloud. Plot
the Cloud also.
Solution:
//Senkou Span A
senkouSpanAColor = ParamColor(“Senkou Span A Color”,
colorSeaGreen );
senkouSpanA = ( tenkanSen + kijunSen )/2;
//Last parameter of the Plot function projects the plot to 26
//default period to the future.
Plot( senkouSpanA, “Senkou Span A”, senkouSpanAColor,
styleLine,Null,Null,shiftRight );
//Senkou Span B
senkouSpanBPeriod = Param(“Senkou Span B Period,52,20,200,1);
senkouSpanBColor = ParamColor(“Senkou Span B Color”,
colorPink);
senkouSpanB = ( HHV(High,senkouSpanBPeriod) +
LLV(Low,senkouSpanBPeriod))/2;
Plot(senkouSpanB,”Senkou Span B”,senkouSpanBColor,
styleLine,Null,Null,shiftRight );
The above code used the PlotOHLC() function to plot the Kumo Cloud.
This function plots a customized chart with the open, high, low, close
paramer values appropriately modified.
Solution:
Here the ROC function will come to our rescue. Since the price drop has to
happen within 10 bars, we can limit our ROC calculation up to 10 bars.
We can write the code as given below:
bar = 0;
for ( i = 1; i <= 10; i++ )
{
drop = ROC( Close, i );
if ( drop[ Barcount – 1 ] <= -10 )
{
//Capture the bar count
bar = i;
break;
}
}
dropSignal = drop <= -10;
6. It is to be determined whether the Close price has been above its 5 day
simple moving average for the past 5 periods. Write a formula to check
this.
Solution:
While this works well, there is a condensed version to find out the same
result. The Sum () function adds the values of an array for a specified
number of times. Using Sum() we can rewrite the formula as:
Look, how simple the formula becomes. The isOk variable will be True
only when the Sum() returns a 5, that is when the first 5 closes are
above ma5. Fig. 5.21 shows a chart example of this. In this chart isOk
will be True as the last 5 closes are above ma5, the 5 day Moving
Average.
Fig. 5.24 Sum( C > ma5, 5 ) = 5
7. Write a formula to find out whether the 5 day moving average has
crossed the 10 day moving average within past 5 days.
Solution:
The formula can be written using the Sum() function as shown below:
The flag crossedOk determines whether during the prior 5 days period,
ma5 has crossed ma10. A value of True confirms it has crossed. See
Fig.5.25 for a chart demo.
8. Write a formula that returns the value of the 14 day RSI on the 2nd most
recent occurrence of the closing price closing above its 10 day simple
moving average.
Solution:
ValueWhen is the function to be used here. The “Array” will be RSI( 14 )
and the “Expression” will be Cross( Close, MA( Close, 10 )) and the value of
n = 2. Hence the required formula is:
Solution:
6.1 AmiBroker allows user definable functions to be created and used as many
times like the built-in functions. If you find that a particular logic is not
available in AFL, you can write a function yourself according to the syntax of
function definition and use it in the AFL program. Chapter 3 described how
user defined functions can be created with few examples. To recap the syntax,
the definition of function follows:
function function_name ( [parameter,…] )
{
Statements;
[return result;]
}
The function definition begins with the keyword function, followed by the
function name. The parameter list is enclosed in parentheses after the
function name. The body of the function is included within the braces. The
keyword return returns the result to the calling program.
In this chapter we will practice writing many functions. These functions may
not be useful for practical programming use in AFL. Our intention is to
develop AFL writing skills.
1. We have already seen the built-in function BarsSince(ARRAY). This
calculates the number of bars that have passed since the ARRAY
was true. Write a function yourself, that performs the same task as the
built-in function BarsSince.
Solution:
Let’s name the function as myBarsSince. The function has one
parameter of type Array. Start with the function definition:
function myBarsSince( array )
{
body of function
}
The passed parameter is “array”. We can name the parameter anything
of our choice. The only matter concerned is that the parameter will be
an ARRAY and is to be considered so within the body of the function.
The idea is simple. Start from the last bar, traveling backwards counting
the bars each time the passed array remains False until it becomes
True. The counted value is returned from the function when a True
value is detected in the array. Using a while loop, the function can be
written as:
function myBarsSince( array )
{
//Initialize the counters
count = 0;
i = 1;
while ( array[BarCount – i] == False )
{
i++;
count++;
}
return count;
}
To test this function: Use the Guru Commentary.
x = myBarsSince( Close > 536.7 );
y = BarsSince( Close > 536.7 );//Use the built-in function
WriteVal(x,2.0);
WriteVal(y,2.0);
Result in my system: ( See Figure 6.1 )
5
5
Fig 6.1
2. The HHV function returns the highest value of the array within the
range prescribed. As an exercise, write a function yourself to give the
same functionality as the HHV.
Solution:
Name the function as myHHV with parameters array and range. Assume
that the highest will be the last array element itself and log this into a
variable. Now using a for, loop travel backwards, until the range is
reached, each time resetting the highest value. The complete function is
given below.
function myHHV( array, range )
{
myHighest = array;
for ( bar = 2; bar <= range; bar++ )
{
myHighest = Max( myHighest, array[ Barcount – bar ] );
}
return myHighest;
}
Test the function:
x = myHHV( C, 60);//Our function
WriteVal( x, 5.2 );
y = HHV( C, 60 );//The built-in function
WriteVal( y, 5.2 );
Result :
59.10
59.10
3. Write a user defined function that is similar the the LLV built-in
function. Test the function and compare with the LLV. ( Not solved )
4. Write a function to detect a pullback after the security reached a high.
This may be required to enter a trade. The function parameters are the
array (usually High) and the number of periods of pullback required.
Solution:
See the figure 6.2 for the definition of a pullback. The figure shows a 4
period pullback after reaching a peak.
x = pullBack( H, 3 );
In this case x will be true. We are actually checking whether there was a
three day pullback after reaching a peak.
5. Write an AFL function to check for a Bearish Engulfing Pattern.
Solution:
Fig. 6.4 shows a typical Bearish engulfing pattern.
The pattern is a two candle pattern. The first candle must be a white
body. The second candle, a black one, must open above the close of the
first candle and should close below the open of the first white body.
Visually, the white body of the first candle appears fully covered by the
black body of the second candle. There should have a prior uptrend
before the engulfing formed. Though, a subjective matter, we define an
uptrend when the prior four highs are higher than their respective prior
highs.
function bearishEngulfing ()
{
//Define a white body and a black body
whiteBody = C > O;
blackBody = O > C;
//Define engulfing
engulfing = Ref(whiteBody,-1) AND blackBody AND
O > Ref(C,-1) AND C < Ref(O,-1);
//Define uptrend
upTrend = BarsSince( !( Ref( H.-1 ) > Ref( H, -2))) >=4;
return upTrend AND engulfing;
}
The function returns an Array whose values are True(1) or False(0)
depending upon a bearish engulfing pattern is detected or not. To test
see the chart portion in Fig. 6.5.
Once saved in the “Include” folder, we need not specify the path for it
because AmiBroker will search for the include files in the Include folder,
which is the default folder. Later when we desire to use the functions
defined in the include statement, we can use the functions directly
without further defining them.
#include <myFunctionDefinitions.afl>
x = bearishEngulfing();
WriteVal(x,2.0);
Chapter 7
Fig. 7.3
Type the three symbols ABB,ACC,SUNTECK. Separate the symbols with
a comma. Any number of symbols can be entered, each separated by a
comma. Click OK. Now the Watchlist myList is created with three
symbols added into it. See Fig. 7.4. Keep in mind that the typed names
have to match exactly like the Symbols available in the database.
Otherwise, though the symbols get added to the Watchlist, a chart
cannot be displayed for the corresponding symbol.
Fig. 7.4 myList Watchlist
Fig. 8.5
Suppose we want to filter the entire stocks in the database, choose All
Symbols in the Apply to DropBox. An Exploration gives the following
result as shown in Fig. 8.6.
Fig. 8.6 Exploration Entire database
Chapter 9
This we have already seen while discussing the Explore function. We will be
using the Backtest icon( red ellipse ) in the Analysis window. Though, a
window is opened, note that no file is opened by this procedure. You cannot
edit a file directly in the Analysis window. There should be a file with buy and
sell rules to make a back test. If a file is already saved, we can open it from
the Analysis window for back testing. Click on the ‘Pick a file’ icon on the right
extreme of the Analysis window to open the desired file.
9.3 Reserved variables used in Back testing
The first step in Back testing is to have objective rules for entry and exit into
the market. Once the rules are decided, write them as Buy and Sell rules in
AFL. Suppose a person thinks the following rules:
I will buy the stock when its Close price crosses above the 20 day moving
average.
I will sell the stock when its Close prices crosses below the 20 day moving
average.
He has decided the buy and sell rules. These can be converted into AFL as
given below.
Buy = Cross( Close, MA( Close, 20 );
Sell = Cross( MA( Close, 20 ), Close );
Here the Buy and Sell are special Reserved variables which are used for
setting the buy and sell rules for the Back tester. The Back tester engine use
the Buy and Sell array values to determine the back testing process.
A value of 1 in Buy opens a long trade.
A value of 1 in sell closes the long trade.
Similarly “Short” and “Cover” variables can be used.
A value of 1 in Short opens a short trade.
A value of 1 in Cover closes the short trade.
To Back test our system, just click the “Backtest” icon in the Analysis window.
The following are the reserved variable names applicable to the Back testing.
These names should not be used for user defined variables.
Variable Description
Buy Define a buy rule. Enter long position
Sell Define the sell trading rule. Close the long position
Short Define a short sell rule. Enter a short position
Cover Define cover trading rule. Closes the short position
Buyprice Define buying price array
Sellprice Define selling price array
Shortprice Define short selling price array
Coverprice Define buy to cover price array
Exclude A true value of this excludes current symbol from process
Roundlotsize Define round lot sizes used by the back tester
ticksize Define ticksize used to align prices generated by built-in
stops
Pointvalue Allows to read and modify future contract point value
Margindeposit Allows to read and modify future contract margin
positionsize Allows control dollar amount of percentage of portfolio that
is invested into the trade
In the above buy and sell rules the Buy and Sell are arrays and hold either a
True (1) or False (0) value. There are chances that after a buy/sell signal
generation and before closing sell/buy signals further buy/sell signals are
generated. These excessive signals have to be removed. AFL provides a
function for this purpose, the ExRem( ) function. The ExRem function
Removes Excessive signals. We will add ExRem in our code.
Buy = ExRem( Buy, Sell );
Sell = ExRem( Sell, Buy );
Open the Formula Editor and enter the following statements into the editor
window.
//backTest.Afl
//Sample backtesting code
Buy = Cross( MACD( ), SIGNAL( ) ) AND ADX( ) > 30;
Sell = Cross( SIGNAL( ), MACD( ) );
//Remove excessive signals
Buy = ExRem( Buy, Sell );
Sell = ExRem( Sell, Buy );
Save this as backTest.Afl, check syntax and send to the Analysis Window.
To perform the back test, the back tester requires some other parameters sch
as the initial equity to start with, type of trades such as long, short or both,
maximum number of open positions etc. These can be set up on the Settings
window which is available when the Settings tab ( a wrench like icon ) is
clicked. Select the General tab of the Settings window as shown in Fig. 9.3.
Fig. 9.3 Back tester settings
Set the Initial equity as 100000. We will start with an initial capital of 100000.
Set the Positions: to Long. We are testing for long only trades, no shorts.
Set the Periodicity: to Daily. Daily data is used for back testing.
We can set up the Commissions & rates. Settings, if done in this will
appropriately will be reflected in the profit & loss calculation in the trade
report. In our case, for simplicity we are not setting anything in this. A 100 in
the Account Margin: indicates that we are not using any margin amount. Click
on the Trades tab to set up the buy and sell price conditions and trade delays.
Set the Buy price: to Open. This directs to buy at the Open price.
Set the Buy delay: to 1. This ensures a trade delay of 1 day after the signal
generation.
The direction is to buy at the Open price of the next day.
Set the Sell Price: to Close. This directs to sell the Close price.
Set the Sell Delay: to 0. Make the sell on the same day of signal generation.
The selling of the security happens on the signal day at the Close price.
After completing the Trade set ups, we will proceed with the setting of Stops.
Stop losses are very important and the appropriate placement ensures profit
levels and prevent large draw downs. Click on the Stops tab to bring the Stops
Settings window as shown in Fig. 9.4.
The entire AFL for the back tested strategy is rewritten below:
//backTest.Afl
//Demo of back testing a strategy
//Set initial equity to 100000
SetOption( “Initial Equity”, 100000 );
//Set buy on next day open at open price and sell on same day close at close
//price
SetTradeDelays( 1, 0, 0, 0 );
BuyPrice = Open;
SellPrice = Close;
//Set maximum open positions and equity allocation
totalPosition = 4;
SetOption( “MaxOpenPositions”, totalPosition );
PositionSize = -100/totalPosition;
//Apply the stop settings
ApplyStop( stopTypeLoss, stopModePercent, 6 ); //6% maximum stop loss set
ApplyStop( stopTypeProfit, stopModePercent, 10 );//10% profit target settings
ApplyStop( stopTypeTrailing, stopModeDisable, 0 );//Trailing stop disabled
ApplyStop( stopTypeNBar, stopModeBars, 12 );//12 bar exit settings
//Define buy and sell rules – the strategy
Buy = Cross( MACD( ), SIGNAL( ) ) AND ADX( ) > 30;
Sell = Cross( SIGNAL( ), MACD( ) );
//Remove excessive signals
Buy = ExRem( Buy, Sell );
Sell = ExRem( Sell, Buy );
Save the file.
Exercise 9.1
1. Write buy and sell rules formula for the trading system described below:
Buy when the prior bar close is below the Bottom Bollinger Band and the
current bar closed above the Bottom Bollinger Band. A buy is also initiated
when the current high has exceeded 2% above the Top Bollinger Band.
Sell rules are exact reverse of the Buy rules.
Solution:
There are two functions in AFL to find the Bollinger Bottom and Top bands
arrays. They are the BBandBot and BBandTop functions. Both accept an
array, a period and a width for standard deviation, as parameters.
bottomBand = BBandBot( Close, 20, 2 );
topBand = BBandTop( Close, 20, 2 );
Buy = ( Ref( Close, -1 ) < Ref( bottomBand, -1 ) AND Close > bottomBand ) OR
Close > 1.02*topBand;
Sell = (Ref( Close, -1 ) > Ref( topBand, -1 ) AND Close < topBand ) OR
Close < 0.98*bottomBand;
Buy and Sell signals generated for the above system for a particular stock is
shown in the Figure 9.7 below.
Fig. 9.7 Buy/Sell Signals
2. Write Buy and Sell rules for a trading system described below:
Buy: A 2% gap up in price on the previous day with at least twice average 5
day volume.
Sell: A 2% gap down in price on the previous day with at least twice average
5 day volume.
Solution:
volAverage = MA( Volume, 5 ); //5 day moving average of volume
Buy = Low > Ref( High, -1 )*1.02 AND Volume >= volAverage*2;
Sell = High < Ref( Low, -1 ) * 0.98 AND Volume >= volAverage*2;
Chapter 10
Revision Exercises
The primary intention of this book was to introduce to the reader the most basic
aspects of AFL programming. It is expected that after reading this book, a beginner
in Amibroker will be able to attempt advanced topics. Before concluding, I will
present few more exercises. Though it may look repetitive, I urge you to do all the
exercises given and compare your results with the solutions provided. Programming
is a task like swimming. To master it, you have to actually do lot of exercises. This
will only make a solid launching pad, from where you can make a take off with
confidence.
1. What will be the output of the following printf statement?
printf( %% );
a) %%
b) %
c) An error will be reported
Solution:
Correct answer is c. The argument to printf statement should be a formatted
string and should be enclosed in double quotes.
2. A number can be converted to a string using the Built-in function NumToStr.
Several strings can be concatenated using the operator +. It is desired to print
the current closing price as “Current closing price is xxxx” (xxxx should replace
the current closing price). Write a printf statement to achieve this.
Solution:
Using the NumToStr function, we can convert the current closing price to a
string. Use + to concatenate with “Current closing price is “. The required
statement is:
printf( “Current closing price is “ + NumToStr( Close ) );
Typical result: Current closing price is 33.950
3. AFL has a function called WriteIf that will return different strings depending
on the true/false value of an expression passed as a parameter. The syntax of
the WriteIf is:
WriteIf( Expression, “True Text”, “False Text” )
This function can be used only within the Guru commentary. If Expression
evaluates to True “True Text” is returned otherwise “False Text” is returned.
Write a formula to display a commentary “Bullish” when the MACD is greater
than zero and “Bearish” otherwise.
Solution:
WriteIf( MACD() > 0, “Bullish”, “Bearish” );
4. In Exercise 3 above, there may be a possibility that the MACD( ) be equal to
zero which we wish to register as “Neutral”. Revise the statement to
accommodate this condition.
Solution:
It is possible to combine several WriteIf calls to handle multiple possibilities.
WriteIf( MACD( ) > 0, “Bullish”, WriteIf( MACD( ) < 0, “Bearish”, “Neutral” ));
5. Which of the following printf statements is wrong?
a) printf( “%g %4.2f”,5,6);
b) printf(“The values are: %g and %3.4f”,23,12);
c) printf(“%g + %f”,3.2,6);
d) printf(“%g %g,45,12,22);
Solution:
None of the printf statements is wrong.
6. Which of the following identifier names are valid?
a) MonthlyMacdValue
b) _AboveAverage
c) ShortTime Average
d) 2ndMovingAverage
e) my_AtR-Value
f) shiftedValue65
g) Bill#
Solution:
a) Legally acceptable name
b) Invalid. The first character must be a letter
c) Invalid name. Spaces are not allowed in identifier names
d) Invalid. Must begin with a letter
e) Illegal. A hyphen is used in the name. This is not allowed
f) Acceptable name
g) Invalid. Special character is not allowed
7. What will be the output of the following code fragment?
Item1 = 500;
Item2 = 200;
Item3 = 150;
billTotal = Item1 + Item2 + Item3;
printf( “Total Cost = “ + NumToStr( BILLTOTAL ) );
a) 850
b) Total Cost = 850.000
c) An error will be reported with variable ‘BILLTOTAL’ used without having
been initialized.
Solution:
Correct answer is b). The three zeros after the decimal point in the result is due
to the default behavior of format specification in the NumToStr. This can be
modified to our requirement.
Kindly note that variable names in AFL are case insensitive. billTotal and
BILLTOTAL represent the same entity.
8. One of the following is a wrong way of commenting. Identify it.
a) shortMALength = 10; //Length of the fast moving average
b) //Define the length of the slow
moving average//
fastMALength = 50;
c) /*Find the cross of moving averages
*/
crossArray = Cross( MA( shortMALength, fastMALength);
Solution:
Answer is b).
9. Which of the following is not an AFL built-in function?
a) MACD( )
b) Typeof( )
c) ATR( )
d) Plot( )
Solution:
Answer is b). Typeof( ) is an operator, though it looks like a function.
10. Write a program to display the days of the last five bars. Enter the formula in
the chart commentary window and show the results. ( Hint: Use the
DayOfWeek function and the switch..case statement ).
Solution:
Depending upon the return of DayOfWeek, we can find out which day it was.
Since the days of the last five bars are to be displayed, we will use an outer for
loop which loops five times. Inside this, a switch..case statement will find out
which day is represented and prints it out. A possible solution is given below.
//Display days of last five bars
arrayDays = DayOfWeek( );
//Outer loop 5 times
for ( bar = 1; bar < 6; bar++ )
{
switch ( arrayDays[ Barcount – bar ] )
{
case 0:
printf( “Sunday\n” );
break;
case 1:
printf( “Monday\n” );
break;
case 2:
printf( “Tuesday\n” );
break;
case 3:
printf( “Wednesday\n” );
break;
case 4:
printf( “Thursday\n” );
break;
case 5:
printf( “Friday\n” );
break;
case 6:
printf( “Saturday\n” );
}
}
Sample output is shown in Fig 10.1 below. Saturday and Sunday will not be
displayed as these are trading holidays.
12. Write a formula to detect whether today is a five day high and today’s Close is
below the open.
Solution:
High > Ref( High, -4 ) AND High > Ref( High, -3 ) AND High > Ref( High, -2 )
AND High > Ref( High, -1 ) AND Close > Open ;
There is a condensed version of writing the same.
High > Ref( HHV( High, 4 ), -1 ) AND Close > Open;
13. We are looking for an overbought condition, when the 14 day RSI, has been
remaining above 70 for at least 6 days during a span of 10 days. Write an
exploration formula and short list a portfolio of stocks satisfying this
condition.
Solution:
Launch the Formula Editor and enter the following formula.
Filter = Sum( RSI( 14 ) > 70, 10 ) >= 6;
Click “Filter” and select NiftyLargeMidcap250. In Range select 1 recent bar
and click Explore. Fig. 10.3 shows a short listed portfolio satisfying the
required condition.
15. How can you override the Delay settings set in the Backtester settings dialog
box?
Solution:
By using the SetTradeDelays( ) in the AFL code.
SetTradeDelays( BuyDelay, SellDelay, ShortDelay, CoverDelay );
Now we have come to the end of this short course. By this time you should be in a
position to write your own AFL code. If you have a trading idea in your mind, try
converting it into AFL formula. Any quantifiable idea, without ambiguity, can be
converted to a formula. Wish you good luck.
ADX-PPO PINCH TRADING By the same author is available for download from
Amazon.
https://www.amazon.com/ADX-PPO-PINCH-TRADING-AJAN-K-ebook/dp/B07HRLJ
RNX/ref=sr_1_1?ie=UTF8&qid=1549517031&sr=8-1&keywords=ajan+k+k
https://www.amazon.in/ADX-PPO-PINCH-TRADING-AJAN-K-ebook/dp/
B07HRLJRNX/ref=sr_1_1?ie=UTF8&qid=1549517122&sr=8-1&keywords=ajan+k+k