Hi,
I take the MA & StDev functions in AB for granted.
So I thought it would be a good exercise to try and code it using looping code in afl, (well that’s why it’s there
)
Unfortunately, I am having difficulties.
The afl code below is based on
http://www.wisestocktrader.com/indicators/1477-arnaud-legoux-moving-average
http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap08/mov-avg.html
( I googled moving average/SD in C/C++ – various code made no sense to me.)
I would be grateful if someone could correct my code below for rolling mean, and hence/otherwise adapt it for a rolling SD, both on log Returns. I’m sure it’s very simple.
many thanks,
Amarjit
// Based on
/// @link http://www.wisestocktrader.com/indicators/1477-arnaud-legoux-moving-average
/// @link http://www.cs.mtu.edu/~shene/COURSES/cs201/NOTES/chap08/mov-avg.html
//===============================
window = 20;
// function rolling SD's of RETURNS
// --------------------------------
function ALMA(C, window)
{
// set logRets to Null's
w = Null;
// logRets
for(i = 1; i < Barcount; i++)
{
w[i] = ln(C[i]/C[i-1]);
}
// set output and intermim vectors to Null's
outalma = Null;
// loop through data
for(i = 1; i < BarCount - Window + 1; i++)
{
a1Sum = 0;
if(i < Window)
{
outalma[i] = Null;
}
else
{
// ROLLING MEAN
for(j = i; j < i + Window - 1 ; j++)
{
alSum = a1Sum + w[j];
}
outalma[i] = alSum/Window;
}
}
return outalma;
}
ac_alma = ALMA(C, window);
//===============================
// Explore
logRet = ln( C / Ref(C, -1) );
Filter = 1;
AddColumn(C, "C", 1.6);
AddColumn(logRet, "logRet", 1.6);
AddColumn(MA( logRet , window ), "tjMA", 1.6);
AddColumn(StDev( logRet , window ), "tjStDev", 1.6);
AddColumn(ac_alma, "ac_alma", 1.6);
Your primary error is that your secondary loop (the one that uses j as the loop counter) is moving forward through the data, not back. For example, if today was April 15 and the window size was 10, you should be finding the average of the bars from approximately April 2-15 (assuming some weekends in there). Instead, you are finding the average of the bars from April 15-28.
I did not fix this error and run your code to see if that resolves all issues. I assume you’re doing this just to learn how to write loops, so continuing to debug your own work will be a good exercise. 
Hi,
Thanks for the reply.
Here’s A solution.
Unfortunately there’s a “fudge” to output the SD result.
If anyone has a more elegant method I’d be interested.
There’s a way to return multiple values, rather than parameters list
http://www.amibroker.com/kb/2014/09/21/a-function-with-multiple-return-values/
My background is in FORTRAN.
// Based on
/// @link http://www.wisestocktrader.com/indicators/1477-arnaud-legoux-moving-average
//===============================
// function muSig for rolling MEAN's & SD's of LOG RETURNS
// -------------------------------------------------------
// Set parameters
window = Param("window", 10, 2, 1000, 1);
muOrSig = ParamList( "mu Or Sig:", "mu|Sig" );
price = C;
function muSig(price, window)
{
// set logRets to Null's
w = Null;
// logRets
for(i = 1; i < Barcount; i++)
{
w[i] = ln( price[i] / price[i-1] );
}
// set outputs to Null's
res0 = Null;
res2 = Null;
// loop through the Data
for(i = 1; i < BarCount; i++)
{
// set leading output data to Null's
if(i < window)
{
res0[i] = Null;
res2[i] = Null;
}
else
{
// initialize counters to zero
alSum = 0;
res1 = 0;
// ROLLING MEAN
for(j = 0; j < window; j++)
{
// sum logRets over the window
alSum += w[i - window + j + 1];
}
// mean is res0
res0[i] = alSum/window;
// ROLLING SD POPULATION
for(j = 0; j < window; j++)
{
// sum squared deviations from mean over the window
res1 += ( w[i - window + j + 1] - res0[i] ) ^ 2;
}
// sd population is res2
res2[i] = sqrt(res1/window);
// fudge adjust for leading point
res2[window] = Null;
}
}
// choose/swap res0 for MA and
// res2 for SD
if ( muOrSig == "mu" )
{
return1 = res0;
}
if ( muOrSig == "Sig" )
{
return1 = res2;
}
return return1;
}
// set function ready for explore
ac_muSig = muSig(C, window);
//===============================
// Explore
logRet = ln( C / Ref(C, -1) );
Filter = 1;
AddColumn(C, "C", 1.6);
AddColumn(logRet, "logRet", 1.6);
AddColumn(MA(logRet,window), "tjMA", 1.6);
AddColumn(StDev(logRet,window), "tjStDev", 1.6);
AddColumn(ac_muSig, "ac_muSig", 1.6);
To confirm, you’re writing this code simply as an exercise to get comfortable with looping code, correct? The most efficient solution by far is to use the array functions already built into AmiBroker, as these will run at the speed of compiled code, i.e. many times faster than any looping code you can write in AFL. Make sure that you understand which functions are array functions. For example, you don’t have to call ln from within a loop, because you can pass an entire array to it and calculate all bars at once. If that’s not obvious to you yet, then spend some more time in the tutorials and the help file. It will be time well spent!!
Matt
Yes, that’s right I am writing it simply as an exercise to get comfortable with looping code within AB.
Thanks for the recommendations & advice.
Amarjit