User-definable functions allow for encapsulating user code into easy-to-use modules that can be used in many places without the need to copy the same code over and over again.
Functions must have a definition. The function definition includes the function body — the code that executes when the function is called.
A function definition establishes the name and attributes (or parameters) of a function. A function definition must precede the call to the function. The definition starts with the function keyword, followed by the function name, an opening parenthesis, then an optional list of arguments, and a closing parenthesis. The function body then follows, enclosed in curly braces.
A function call passes execution control from the calling function to the called function. The arguments, if any, are passed by value to the called function. Execution of a return statement in the called function returns control and possibly a value to the calling function.
If the function does not include a return statement (does not return anything), we call it a procedure.
Following is an example of function definition:
//
the following function is 2nd order smoother
function IIR2( input,
f0, f1, f2 )
{
result[ 0 ] = input[ 0 ];
result[ 1 ] = input[ 1 ];
for(
i = 2; i < BarCount;
i++ )
{
result[ i ] = f0 * input[ i ] +
f1 * result[ i - 1 ] +
f2 * result[ i - 2 ];
}
return result;
}
Plot( Close, "Price", colorBlack, styleCandle );
Plot( IIR2( Close, 0.2, 1.4,
-0.6 ), "function
example", colorRed );
In this code, IIR2 is a user-defined function. input, f0, f1, f2 are
formal parameters of the function.
At the time of the function call, the argument values are passed into these variables.
Formal parameters behave like local variables.
Later, we have result and i, which are local variables. Local variables
are visible only inside the function. If any other function uses the same variable
name, they won't interfere with each other.
Because AFL does not require variables to be declared, the decision of whether a given variable is treated as local or global depends on where it is FIRST USED.
If a given identifier first appears INSIDE a function definition, it is
treated as a LOCAL variable.
If a given identifier first appears OUTSIDE a function definition, it is
treated as a GLOBAL variable.
This default behavior can, however, be overridden using global and local keywords (introduced in 4.36) — see Example 2.
Example (commentary):
k = 4; //
this is GLOBAL variable
function f( x )
{
z = 3; //
this is LOCAL variable
return z * x * k; //
'k' here references global variable k (first used above outside function)
}
z = 5; //
this is GLOBAL variable with the same name as local variable in function f
"The value of z before function call :" + WriteVal(
z );
// Now even if we call function
// the value of our global variable z
// is not affected by function call because
// global variable z and local variable z are separate
and
// arguments are passed by value (not by reference)
"The result of f( z ) = " + WriteVal(
f( z ) );
"The value of z after function call is unchanged : " + WriteVal(
z );
Example 2: Using local and global keywords to override default visibility rules:
VariableA = 5; //
implict global variable
function Test()
{
local VariableA; //
explicit local variable with the same identifier as global
global VariableB; //
explicit global variable not defined earlier
// may be used to return more than one value from
the function
VariableA = 99;
VariableB = 333;
}
VariableB = 1; //
global variable
"Before function call";
"VariableA = " + VariableA;
"VariableB = " + VariableB;
Test();
"After function call";
"VariableA = " + VariableA
+ " (not affected by function call )";
"VariableB = " + VariableB
+ " (affected by the function call )"
At the end of the function, we can see a 'return' statement that is used to return the result to the caller. Note that currently, a return statement must be placed at the very end of the function.
It is also possible to write a procedure (a function that returns nothing (void))
procedure SinePlotter(
Freq, ColorIndex )
{
pname = "Line"+WriteVal(ColorIndex,1.0);
array = sin( Cum(
Freq * 0.01 ) );
Plot(
array, pname , colorRed +
ColorIndex, styleThick );
}
for( n = 1;
n < 10; n++ )
{
SinePlotter( n/2+Cum(0.01),
n );
}
Note that although there are two separate keywords, 'function' and 'procedure,' AmiBroker currently treats them the same (they both accept return values but do not require them), but in the future, the rules might get enforced to use
a return statement ONLY in conjunction with the function keyword. So, it is advised to use the function keyword in cases when your function returns any value, and the procedure keyword otherwise.
Note also that recursion (having a function call itself from within itself)
is NOT supported as of now.
Please also read Understanding how AFL works article to learn more.