Looping in Amibroker

Just want to share what I found to help me understand the concept of looping in Amibroker. Howard Bandy has a good writeup about it on page 10-8 in his book titled “Introduction to Amibroker” which is available free for download at this site:
http://www.blueowlpress.com/wp-content/uploads/2016/01/IntroductionToAmiBroker-SecondEdition.pdf
Howard uses three loops to make a simple moving average. I added some comments to his code to help me make sense of it. I also added the builtin Amibroker moving average for comparison:

//from page 10-8 Introduction to Amibroker by Howard Bandy http://www.blueowlpress.com/wp-content/uploads/2016/01/IntroductionToAmiBroker-SecondEdition.pdf
//three loops are used to calculate a moving average
//the first number in the array (i=0) is for the oldest bar, the last number is the most recent bar on the chart

for(i=0;i<4;i++)
{
MyOwnAvg[i]=Close[i] ;//puts a value of close in each of the first four bars, not enough values for an average yet
}
//finished with the first for loop, code does not return to it

for (i=4;i<BarCount;i++)//second loop iterates through the remaining "i" bars after the first four in the first loop
{
Summer=0;
for (j=0; j<=4; j++)//third loop within the second loop iterates through five "j" values for each of the "i" bars
{
Summer=Summer+Close[i-j];//j at 0 summer = 0  + close[i-0], j at 1 summer = 1st close + close[i-1], j at 2 summer = 1st + 2nd close + close[i-2], j at 3 summer = 1st + 2nd + 3rd close + close[i-3] , j at 4 summer = 1st + 2nd + 3rd + 4th close + close[i-4] 
}
MyOwnAvg[i]=Summer/5; //summer is the total of the 5 previous closes/5
}


Average=MA(C,5);//Amibroker builtin code for moving average does the same as the loops above 


//exploration code, if you run it on your first month of an equity's data you can see what happens on the first five bars
Filter=1; 

AddColumn(C,"Close"); 
AddColumn(MyOwnAvg,"MyOwnAvg",1.2); 
AddColumn(Average,"Average",1.2); 

This is a screen shot of an exploration from the code for the oldest month of data available:
image

2 Likes

All is fine except:

  1. Mathematically 5-bar moving average is undefined by design for first 4 data points - your formula returns false data (just unaveraged data) and should be returning Null instead.
  2. The code is written inefficiently. Simple moving average can be written without nesting loops. A single loop would do just fine. There is a wikipedia article that you could google
1 Like

@Marcel thanks for your input!

With regards to this topic some users might also find these links useful:

  1. Understanding how AFL works: https://www.amibroker.com/guide/h_understandafl.html

  2. For Statement - with the example of how to calculate exponential moving average using loops: https://www.amibroker.com/guide/keyword/for.html

  3. Using loops with TimeFrame functions: http://www.amibroker.com/kb/2014/11/25/using-loops-with-timeframe-functions/

  4. I can also recommend this interesting tutorial (with many examples of using different kind of loops) by Wayne aka GreatPig (user name) from Aussie Stocks Forums :

Regards

6 Likes

I would like to correct the information about the author of the above pdf. I was just informed, that the author is Wayne aka Great pig (user name) from Aussie Stocks Forums (not JB Marwood).

I found this pdf on JB Marwood server, the pdf isn’t signed and I haven’t found any references to the original author. This is the reason of my misinformation. I am sorry for that.

I give credit to the original author. Here’s the link to the source:

6 Likes

Below is a loop for a simple moving average using a single loop. I’m not sure if there’s a better way without having to address each of the previous individual close values.

Period=5;

for( i = Period-1; i < BarCount; i++ )
{
MyAvg[i]=(Close[i]+Close[i-1]+Close[i-2]+Close[i-3]+Close[i-4])/Period;
}

Average=MA(C,5);//Amibroker builtin code for moving average does the same as the loop above 

//exploration 
Filter=1; 

AddColumn(C,"Close"); 
AddColumn(MyAvg,"MyAvg",1.2); 
AddColumn(Average,"Average",1.2); 
2 Likes

The document is nice, but contains one pretty obvious error: In the examples it uses Avg which is reserved word in AmIBroker that holds typical price (H+L+C)/3. This typical price is used for some indicators and overriding it is not good idea. Other than that it is very nicely written tutorial :slight_smile:

5 Likes

@Marcel,

Do like so if using just one loop.

function cMA( array, period ) { 
	/// @link http://forum.amibroker.com/t/looping-in-amibroker/2334/8
	result = Null;

	csum = 0;
	for(i = 0; i < BarCount; i++) {
		csum += array[i];
		if(i >= period)	csum -= array[i-period];
		if(i >= period-1) result[i] = csum;
	}

	return result / period;
}

period = 5;

Plot( cMA( C, period ), "MA custom", colorRed );
Plot( MA( C, period ), "MA inbuilt", colorBlue );

Then compare speed with version of 1st post.

8 Likes

@Anyone

Exponential moving averages (EMA) or referred to as “Exponential Lag” as Ed Seykota terms it and can provide a return value after the first bar and then approach the “useable” value once you get to desired EMA length. The ease of updating the EMA value and speed is simplified as you only need the previous value and the new price etc.

To update the EMA or “Lag” is…
New_EMA = Previous_EMA + (New_Price - Previous_EMA) / EMA_Length

-S

That is Wilders smoothing, not classic EMA. Both are 1st order IIR filters (i.e. mathematically use same formula) but Wilders using 1/Period factor while EMA uses 2/(Period+1) factor.

3 Likes

“Well alrighty then”. ~(Pet detective)

1 Like