How to sum a variable when it changes over n periods?

No clue if this will be useful yet or not, but I have an idea to compare stocks using an indicator that measures historical trend strength and quality. The way I was thinking about doing this was to use the zigzag function, sum all the bull moves over a rolling window, and then divide by the number of those bull moves. This would in theory promote strong smooth trending stocks while demoting slower choppy stocks.

The AFL question I have is that I am unsure how to do this summation of this variable and also count how many times it changes over the rolling window. This loop is where I was trying to do the iteration of the counting of times the gain variable changes over the rolling window.

for( i = 0; i < n; i++)
{
	if(gain[i] != gain[i-1])
	{
		count++;
	}
}

But it obviously doesn't work. I feel like I'm missing some simple concept of how to check if a variable changes and then do something with it like count how many times it happens or add the n changed variables together.

Any help to point me in the right direction about this concept would be appreciated.

Full code below for reference:

/*
TREND INDEX
This is an attempt to measure both the quality and strength of a stock's "trendiness" vs. "noise."
The idea is to measure and sum all the bull moves as defined by the Zigzag indicator over a rolling window.
Then divide that total by the number of different moves it took to get there.
In theory this ratio should show off strong trending stocks that tend to hold trends vs. chop.
*/

// ==========================================================================================
// === PLOT CHART & INDICATORS ===
// ==========================================================================================
// Chart
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - " + FullName() + " | {{INTERVAL}} {{DATE}}: Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 

// Moving Averages (use Nz to avoid lack of history screening strong stocks out)
sma50 = Nz(ma(Close, 50));
sma200 = Nz(ma(Close, 200));
Plot(sma50,"50MA",colorGrey40, styleNoTitle);
Plot(sma200,"200MA",colorWhite, styleNoTitle);


// ==========================================================================================
// === ZIGZAG ===
// ==========================================================================================

// Zigzag trend indicator
zigAmount = 12;
zz = Zig(Close, zigAmount );

// Values
pk = Peak(Close, zigAmount, 1);
tr = Trough(Close, zigAmount, 1);
tr2 = Trough(Close, zigAmount, 2);
// Bars Back
pkbrs = PeakBars(Close, zigAmount, 1);
trbrs = TroughBars(Close, zigAmount, 1);
trbrs2 = TroughBars(Close, zigAmount, 2);

// Calculate percent gain of bullish waves
gain = IIf(pkbrs < trbrs, (pk - tr) / tr, (pk - tr2) / tr2) * 100;

// Sum gains
n = 252; // 252 = one year
count = 0; // number of price swings
gainTotal = 0;  // sum the total gains of all the up moves

//for( i = 0; i < n; i++)
//{
//	if(gain[i] != gain[i-1])
//	{
//		count++;
//	}
//}
	
trendIndex = gainTotal / count;

Plot( zz, "ZigZag line", colorLime, styleThick );


// ==========================================================================================
// === INTERPRETATION WINDOW ===
// ==========================================================================================
printf( "<b>–––––––––––––––––––– " + Date() +" –––––––––––––––––––</b>" + "\n" );
printf( "Ticker:	 " + name() + "\n" );
printf( "Name:	 " + FullName() + "\n" );
printf( "Sector:	 " + SectorID(1) + "\n" );
printf( "Industry:	 " + IndustryID(1)+ "\n" );
printf( "––––––––––––––––––––––––––––––––––––––––––––––––––––" + "\n" );
printf( "Peak:		$" + NumToStr(pk, 1.2) + "\n" );
printf( "Trough:		$" + NumToStr(tr, 1.2) + "\n" );
printf( "Trough 2:	$" + NumToStr(tr2, 1.2) + "\n" );
printf( "Peak Bars:	" + NumToStr(pkbrs, 1.0) + "\n" );
printf( "Trough Bars:	" + NumToStr(trbrs, 1.0) + "\n" );
printf( "Trough Bars 2:	" + NumToStr(trbrs2, 1.0) + "\n" );
printf( "Gain:		" + NumToStr(gain, 1.1) +"%%" + "\n" );
printf( "Trend Index:	" + NumToStr(trendIndex, 1.1) +"%%" + "\n" );

@millerrh I admire your effort to find a measure of "signal to noise" and from first principles. Sorry I have not any help to offer with respect to your code.

But ....

This concept has been worked on by others and you may get some ideas that will help in you quest if you review the work of others investigating similar ideas. They may not be exactly what you are looking for but they are definitely related and almost all have existing AmiBroker codes.

Kaufman's efficiency ratio.
Hurst exponent and Fractal Dimension Index.
Varadi's R-Squared Auto Correlation (dvRAC).
Katsanos Congestion Index
Perhaps Kestner's Moving Average Confluence score.

Nothing is perfect and below is a screen shot of this users attempts (possibly correct, possibly incorrect). Good luck, and please let us know how your investigation goes.

1 Like

Perhaps this idea might give you something to play with...

upFinish = Cross( Ref( zz, -1 ), zz );
count = Sum( upFinish, n );
gainTotal = Sum( IIf( upFinish, gain, 0 ), n );
1 Like

The code for this is quite simple:

period = 14; // moving window length
input = C; // input data

change = input != Ref( input, -1 ); // gives 1 when input changes

how_many_changes = Sum( change, period ); // sum changes in rolling window

See AFL reference:
https://www.amibroker.com/f?sum

3 Likes

Thanks for all your replies. It was a very simple concept that I was not thinking of (assuming I needed to do a loop when none was necessary). I got my idea to work. Now I plan to compare it with the other similar ideas @portfoliobuilder mentioned and see what I can learn. Final code for reference:

/*
TREND INDEX
This is an attempt to measure both the quality and strength of a stock's "trendiness" vs. "noise."
The idea is to measure and sum all the bull moves as defined by the Zigzag indicator over a rolling window.
Then divide that total by the number of different moves it took to get there.
In theory this ratio should show off strong trending stocks that tend to hold trends vs. chop.
*/

// ==========================================================================================
// === PLOT CHART & INDICATORS ===
// ==========================================================================================
// Chart
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - " + FullName() + " | {{INTERVAL}} {{DATE}}: Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 

// Moving Averages (use Nz to avoid lack of history screening strong stocks out)
sma50 = Nz(ma(Close, 50));
sma200 = Nz(ma(Close, 200));
Plot(sma50,"50MA",colorGrey40, styleNoTitle);
Plot(sma200,"200MA",colorWhite, styleNoTitle);


// ==========================================================================================
// === ZIGZAG ===
// ==========================================================================================

// Zigzag trend indicator
zigAmount = 15;
zz = Zig(Close, zigAmount );

// Values
pk = Peak(Close, zigAmount, 1);
tr = Trough(Close, zigAmount, 1);
tr2 = Trough(Close, zigAmount, 2);
// Bars Back
pkbrs = PeakBars(Close, zigAmount, 1);
trbrs = TroughBars(Close, zigAmount, 1);
trbrs2 = TroughBars(Close, zigAmount, 2);

// Calculate percent gain of bullish waves - need to ensure it is current close being used.
//gain = IIf(pkbrs < trbrs, (pk - tr) / tr, (pk - tr2) / tr2) * 100;  // looks at gain of all completed waves
gain = IIf(pkbrs > trbrs, (zz - tr) / tr, (pk - tr2) / tr2) * 100;  // uses current value of zz if bullish

// Sum gains
n = 252; // 252 = one year

change = gain != Ref(gain, -1);  // gives a 1 when the gain variable changes
total_swings = Sum(change, n);  // total number of up moves in the rolling window

gainTotal = Sum(IIf(change, gain, 0), n);
	
trendIndex = gainTotal / total_swings;

Plot( zz, "ZigZag line", colorLime, styleThick );


// ==========================================================================================
// === INTERPRETATION WINDOW ===
// ==========================================================================================
printf( "<b>–––––––––––––––––––– " + Date() +" –––––––––––––––––––</b>" + "\n" );
printf( "Ticker:	 " + name() + "\n" );
printf( "Name:	 " + FullName() + "\n" );
printf( "Sector:	 " + SectorID(1) + "\n" );
printf( "Industry:	 " + IndustryID(1)+ "\n" );
printf( "––––––––––––––––––––––––––––––––––––––––––––––––––––" + "\n" );
printf( "ZigZag:		$" + NumToStr(zz, 1.2) + "\n" );
printf( "Peak:		$" + NumToStr(pk, 1.2) + "\n" );
printf( "Trough:		$" + NumToStr(tr, 1.2) + "\n" );
printf( "Trough 2:	$" + NumToStr(tr2, 1.2) + "\n" );
printf( "Peak Bars:	" + NumToStr(pkbrs, 1.0) + "\n" );
printf( "Trough Bars:	" + NumToStr(trbrs, 1.0) + "\n" );
printf( "Trough Bars 2:	" + NumToStr(trbrs2, 1.0) + "\n" );
printf( "Recent Gain:	" + NumToStr(gain, 1.1) +"%%" + "\n" );
printf( "Total Swings:	" + NumToStr(total_swings, 1.0) + "\n" );
printf( "Gain Total:	" + NumToStr(gainTotal, 1.1) +"%%" + "\n" );
printf( "Trend Index:	" + NumToStr(trendIndex, 1.1) + "\n" );


1 Like