Australian (ASX) Stock Market Forum

Document - Looping In AmiBroker AFL

Ok tradezy, here is an indicator you can overlay on your price chart.

Code:
_SECTION_BEGIN( "Guppy CBL" );
function Cbl( bars )
{
    cblArr = Null;

    if ( bars > 0 )
    {
        for ( i = 1; i < BarCount; i++ )
        {
            steps = bars - 1;
            mostLow = Low[i];

            for ( j = i - 1; j >= 0 && steps > 0; j-- )
            {
                if ( Low[j] < mostLow )
                {
                    mostLow = Low[j];
                    steps--;
                }
            }

            cblArr[i] = mostLow;
        }
    }

    return cblArr;
}
_SECTION_END();


_SECTION_BEGIN( "Guppy Stop" );
function TrailingStop( data )
{
    stop[0] = data[0];

    for ( i = 1; i < BarCount; i++ )
    {
        if ( Close[i] >= stop[i-1] )
            stop[i] = Max( data[i], stop[i-1] );
        else
            stop[i] = data[i];
    }

    return stop;
}

cblStop = TrailingStop( Cbl( 3 ) );
Plot( cblStop, "cblStop", colorBlue, styleLine );
_SECTION_END();

I hope this helps you understand what was required.
 
Thanks. Note though that looping is not the same as recursion. AmiBroker doesn't support recursion (last I saw mention of it).

And no idea about AmiBroker with Tradesim. Never used Tradesim.

Cheers,
GP

Metastock achieves self-referencing (recursive) with PREV whereas AmiBroker uses AMA() or AMA2(). Here is a message from TJ which discusses both approaches:

"PREV in MS is needed because MS does NOT have looping.

In AB, there are loop constructs so there is no need for PREV
because loops give faster and more general way of solving coding
problems.

Since loops are more general they allow easy translation of every
case where MS needs PREV.

Statment like this:
Z =(A*B)+(C*PREV);

Using loop looks as follows:

z = 0; // initialize
for( i = 1; i < BarCount; i++ )
{
prev = Z[ i - 1 ]; // PREV is previous value of Z.
Z[ i ] = A[ i ] * B[ i ] + C[ i ] * prev;
}

As you can see the statement is identical with the exception that AFL looping code uses [ ] operator to access individual array elements.

Good thing is that AFL looping code is BarCount-times faster than MS code. Since 5 years of EOD data is 1300 bars, AFL looping code is 1300 times faster than MS in that case.

It is also possible to use AMA/AMA2 instead of PREV:

Z = AMA2( A, B, C );

which is shorter but AMA is less general than looping code.

Best regards,
Tomasz Janeczko
amibroker.com"
 
Metastock achieves self-referencing (recursive) with PREV whereas AmiBroker uses AMA() or AMA2(). Here is a message from TJ which discusses both approaches:

"PREV in MS is needed because MS does NOT have looping.

In AB, there are loop constructs so there is no need for PREV
because loops give faster and more general way of solving coding
problems.

Since loops are more general they allow easy translation of every
case where MS needs PREV.

Statment like this:
Z =(A*B)+(C*PREV);

Using loop looks as follows:

z = 0; // initialize
for( i = 1; i < BarCount; i++ )
{
prev = Z[ i - 1 ]; // PREV is previous value of Z.
Z[ i ] = A[ i ] * B[ i ] + C[ i ] * prev;
}

As you can see the statement is identical with the exception that AFL looping code uses [ ] operator to access individual array elements.

Good thing is that AFL looping code is BarCount-times faster than MS code. Since 5 years of EOD data is 1300 bars, AFL looping code is 1300 times faster than MS in that case.

It is also possible to use AMA/AMA2 instead of PREV:

Z = AMA2( A, B, C );

which is shorter but AMA is less general than looping code.

Best regards,
Tomasz Janeczko
amibroker.com"

Sorry GP. I did not realize that your message was from 2007.
 
Sorry GP. I did not realize that your message was from 2007.

It doesn't matter whether it is 2007 or now it stands as wrong in both cases.
Here's another quote.

Hello,

"MetaStock: L0:= ( (1-g)*C ) + (g*PREV) ; TradeStation: L0 = (1 -gamma)*Price + gamma*L0[1] ; I made the assumption that AmiBroker can do whatever MS or TS can do, (and probably much faster). That silly assumption has wasted a lot of my time, but that's OK. That's part of my learning process :) More importantly, I apologize to yourself, kunal, and Nick for wasting their time. Hopefully, they have also learned something that they didn't know previously: that AB can't calculate self-referencing equations copied from MS or TS, other than by much slower looping, or by using AMA "


Here we are again: assumptions. While we are at sayings, here there is something relevant http://is.gd/7DcWOY :)

So let us go through your assumptions:

a) Metastock PREV - it was already explained how PREV works in MS and why it is such a bad idea:
http://www.mail-archive.com/amibroker@yahoogroups.com/msg41154.html

MS prev is there ONLY because they don't have loops. It is thousands of times SLOWER than loops,
because putting PREV anywhere in MS formula causes entire formula to be re-executed as many times
as there are bars loaded.

b) Tradestation
L0 = (1 -gamma)*Price + gamma*L0[1] ;

Tradestation has a hidden, implicit loop trading loop that causes your formula to be RE-executued
EVERY BAR. This implict loop can be observed by increasing CurrentBar variable. That's is why the statement like above allows recursion but this again causes unnecessary waste of CPU resources (not as bad as MS PREV, but close) and makes Tradestation slow.

Now compare that to AmiBroker.
AmiBroker does NOT waste CPU cycles without reason as TS and Metastock.
AmiBroker executes formula ONCE for all bars at once, see:
http://www.amibroker.com/kb/2008/08/12/afl-execution-speed/

This is similar in concept to supercomputers doing vector processing (single instructions multiple data).

Now, vectors are processed in parallel, hence no recursion occurs.

But... in places where you really need recursion - you simply write a LOOP, like below:

for( i = 1; i < BarCount; i++ )
L0[ i ] = (1 -gamma)*Price + gamma * L0[ i -1] ;


You see the similarity to Tradestation code ???

But loop in AmiBroker is EXPLICIT. It is much faster than Tradestation because it does
the loop only where/when needed, and only one block (inside loop body) is re-executed
number_of_bars time instead of re-executing entire formula as Tradestation does.

That gives enormous speed gain (orders of magnitude).

Because of local scope, loops in AmiBroker are orders of magnitude faster than MS PREV and Tradestation grand implicit trading loop.

Bottom line:
AmiBroker of course can do anything that MS or Tradestation does but much FASTER.


Best regards,
Tomasz Janeczko
amibroker.com

>> The bottom line it seems is that you cannot recursively alter the
>> value of any array by referencing other values of that array... at
>> least not directly.

Of course that you CAN.

Recursion needs either:
a) a loop

Value1=0;
Value2=log(Close);
for( i = 1; i < BarCount; i++ )
Value1[ i ] = Value1[ i -1 ] + Value2[ i ];

b) or AMA / AMA2 http://www.amibroker.com/f?ama
Value1 = AMA2( Value2, 1, 1 );

c) or CUM (this one is limited to simple "cumulation" while above two are universal)
Value1 = Cum( Value2 );

A must read:
http://www.amibroker.com/guide/h_understandafl.html


Best regards,
Tomasz Janeczko
amibroker.com
 
Hello Everyone,

Thank you all for responding so far.

To be clear I am an absolute Amibroker looping beginner.!!!!... This is why I am posting these questions. I've tried reading the Amibroker manual & Howard Bandy's Introduction to Amibroker and I am still struggling to grasp looping.

As requested, below is the code I am using to get the Guppy trailing stop. The looping section of the code is from page 20 & 21 of the Great Pig's "Looping in Amibroker AFL" document. I have added on my own Buy & Sell conditions.

Unfortunately the Guppy Count Back Line is not triggering when I run my backtest.:banghead:

Could someone with programing experience please correct the code, so that the Guppy trailing stop triggers when I run a backtest? :1zhelp:

With thanks

Tradezy


Code:
function Cbl(bars)
{
cblArr = Null;
if (bars > 0)
{
for (i = 1; i < BarCount; i++)
{
steps = bars - 1; 
mostLow = Low[i]; 
for (j = i-1; j >= 0 && steps > 0; j--) 
{ 
if (Low[j] < mostLow) 
{
mostLow = Low[j]; 
steps--; 
} 
} 
cblArr[i] = mostLow; 
} 
} 
return cblArr; 
} 

function TrailingStop(data) 
{
stop[0] = data[0]; 
for (i = 1; i < BarCount; i++) 
{
if (Close[i] >= stop[i-1]) 
stop[i] = Max(data[i], stop[i-1]); 
else 
stop[i] = data[i]; 
} 
return stop; 
}

SetOption ("Maxopenpositions", 5);
SetPositionsize (20, spsPercentofEquity);
Moving1 = MA (C,20);
Moving2 = MA (C,50);
cblStop = TrailingStop (Cbl(3));
Buy = Cross (Moving1, Moving2);
Sell = Cross (cblStop, C);
 
Simply plot cblStop then you will see that there won't be a cross. So your rules have to be different based on Ref( cblStop, -1).
 
Thanks Trash, That really helps!

The original Guppy Count Back line trailing sell is only meant to recalculate when a new high is formed.

The loop provided by GP does not seem to cater for this.

Is there any way to change the looping code to make this happen?

With thanks,

Tradezy

PS Here is the code below for anyone interested.

Note the last line has been amended, thanks to the suggestion by Trash.


CODE]function Cbl(bars)
{
cblArr = Null;
if (bars > 0)
{
for (i = 1; i < BarCount; i++)
{
steps = bars - 1;
mostLow = Low;
for (j = i-1; j >= 0 && steps > 0; j--)
{
if (Low[j] < mostLow)
{
mostLow = Low[j];
steps--;
}
}
cblArr = mostLow;
}
}
return cblArr;
}

function TrailingStop(data)
{
stop[0] = data[0];
for (i = 1; i < BarCount; i++)
{
if (Close >= stop[i-1])
stop = Max(data, stop[i-1]);
else
stop = data;
}
return stop;
}

SetOption ("Maxopenpositions", 5);
SetPositionsize (20, spsPercentofEquity);
Moving1 = MA (C,20);
Moving2 = MA (C,50);
cblStop = TrailingStop (Cbl(3));
Buy = Cross (Moving1, Moving2);
Sell = C < Ref (cblStop, -1);[/CODE]
 
Thanks Trash, That really helps!

The original Guppy Count Back line trailing sell is only meant to recalculate when a new high is formed.

The loop provided by GP does not seem to cater for this.

Is there any way to change the looping code to make this happen?

With thanks,

Tradezy

PS Here is the code below for anyone interested.

Note the last line has been amended, thanks to the suggestion by Trash.


CODE]function Cbl(bars)
{
cblArr = Null;
if (bars > 0)
{
for (i = 1; i < BarCount; i++)
{
steps = bars - 1;
mostLow = Low;
for (j = i-1; j >= 0 && steps > 0; j--)
{
if (Low[j] < mostLow)
{
mostLow = Low[j];
steps--;
}
}
cblArr = mostLow;
}
}
return cblArr;
}

function TrailingStop(data)
{
stop[0] = data[0];
for (i = 1; i < BarCount; i++)
{
if (Close >= stop[i-1])
stop = Max(data, stop[i-1]);
else
stop = data;
}
return stop;
}

SetOption ("Maxopenpositions", 5);
SetPositionsize (20, spsPercentofEquity);
Moving1 = MA (C,20);
Moving2 = MA (C,50);
cblStop = TrailingStop (Cbl(3));
Buy = Cross (Moving1, Moving2);
Sell = C < Ref (cblStop, -1);[/CODE]


Here is a link for a Guppy Countback plugin. I have not used it but give it a shot.

http://www.marketcalls.in/amibroker...-trailing-stop-loss-plugin-for-amibroker.html
 
Hi Colion,

Thanks for the link for the Guppy Countback plugin. It looks like an interesting website.

Thank you,

Tradezy.
 
Attached is a document I've written covering the use of loops in AmiBroker's AFL.

It starts off discussing arrays and array indexing, then progresses to looping, the different types of loop constructs, the switch & case construct (new in version 4.91.0 Beta), and finally a few real examples.

It's aimed at AmiBroker users who already have a basic knowledge of programming AFL but would like to learn how to use loops.

Feedback from both experienced programmers and beginners welcome, to let me know if I've made any mistakes or have anything wrong, and whether it's logical and easy to follow for someone who's not already familiar with the topic. I've tried to make it progress step by step, but may have unwittingly made some of the steps giant leaps. :D

The document may be freely distributed.

Cheers,
GP

I am a Newbie, so I am reading your file 8 years after you posted it. i just wanted to say thanks it is great! I wish someone would write an entire book on the programming aspect of AmiBroker (Howard bandy's books a good but deal mostly with trading systems).

Great job and thanks for generously sharing.

Larry:xyxthumbs
 
Top