Comparative Bar Charts

Trying to figure out how to create a comparative bar chart for ROC() values of several symbols that will look like this

ExampleBarChart

Can do comparative bar charts in exploration, but not with 0 mid way and bars built from 0 both positive and negative.

Any suggestions?

have you tried with Gfx functions ?

No, haven't tried Gfx functions. Will they work in an exploration?

That is incorrect.
As you can see below (example shows exploration chart created with help of XYChart* functions and styleHistogram ) you have zero line and both positive and negative output in same chart.

The only thing you can not do (AFAIK) is having the bars horizontally as in your picture (in exploration).
If you need horizontal plot then as mentioned you would have option of using Gfx functionality.
And no, Gfx can not be used in exploration. Gfx functions are chart pane functions.

6

3 Likes

Using the XYChart allowed me to do visual symbol return comparisons, but did not sort them into performance order which I find helpful. I failed to find an easy way to sort using the existing tools such as SETSORTCOLUMNS. So I wrote the following code to accomplish what I wanted and thought others might find it useful. It creates a new tab at the bottom of the analysis window that will show the chart.

if (Status("stocknum") == 0) {
		title = "BarChart"; chartmax = 0;
		symlist = CategoryGetSymbols(categoryWatchlist, GetOption("FilterIncludeWatchList")); // Get watchlist symbols
		if(StrLen(SymList)) symcount = StrCount(SymList, ",") + 1; else symcount = 0;
		yield = Matrix(symcount, 2); // Create matrix
		for (i = 0; (symbol = StrExtract(symlist, i)) != ""; i++) { // Fill in matrix for each symbol
			yield[i][1] = i; // Index into symbol list
			yield[i][0] = SelectedValue(ROC(Foreign(symbol, "C"), 1)); // Calculate yield
			chartmax = Max(chartmax, yield[i][0]); // For forcing layout when all values are < 0
		}
		yield = MxSortRows(yield, False, 0, -1); // Sort matrix rows by yields
		XYChartSetAxis(title, DateTimeToStr(SelectedValue(DateTime()), 1) + " - " + Interval(2), "Yield %", styleHistogram); // Setup chart
		if (chartmax == 0) XYChartAddPoint(title, "", 0, 0); // Add 0 value to chart to force desired layout
		for (i = 0; i < symcount; i++) { // Populate chart with sorted values
			symbol = StrExtract(symlist, yield[i][1]); // Get symbol name
			value = yield[i][0]; // Get yield value
			if(value < 0) color = colorRed; else color = colorGreen; // Assign color
			XYChartAddPoint(title, Symbol + "  " + NumToStr(value, 1.2), i + 1, value, color); // Add symbol value to chart
		}
	}

Will create error in if symcount = 0 (incorrect number of rows for matrix creation)!

Matrix (MxSort) is not required. Just StaticVarGenerateRanks (and new AB 6.40 feature run sequence (not necessary to run code - just needs to run first scan and then explore)).

/// code source
/// @link https://forum.amibroker.com/t/comparative-bar-charts/14464/6
#pragma sequence(scan,explore) 
wlnum = GetOption("FilterIncludeWatchlist");
if ( Status( "action" ) == actionScan ) {
	if ( InWatchList(wlnum) )	StaticVarSet( "values" + Name(), ROC(C, 1));
}
if (Status("stocknum") == 0) {
	dt = SelectedValue(DateTime());
	StaticVarGenerateRanks("top", "values", StrCount(CategoryGetSymbols(categoryWatchlist,wlnum),",")+1, 1224); // top-N mode 
	symlist = StaticVarGetRankedSymbols( "top", "values", dt ); 
	chart_name = "BarChart";	
	XYChartSetAxis(chart_name, StrFormat("%s - %s", DateTimeToStr(dt, 1), Interval(2)), "Yield %", styleHistogram); // Setup chart
	for (i = 0; (symbol = StrExtract(symlist, i)) != ""; i++) { // Populate chart with sorted values		
		value = SelectedValue(StaticVarGet("values" + symbol)); // Get yield value
		color = IIf(value<0, colorRed, colorGreen); // Assign color
		if ( i == 0 AND value < 0 ) XYChartAddPoint(chart_name, "", 0, 0);
		XYChartAddPoint(chart_name, StrFormat("%s  %1.2f",symbol, value), i + 1, value, color); // Add symbol value to chart
	}
}

37

5 Likes

There was StaticVarRemove missing in upper code.

/// code source
/// @link https://forum.amibroker.com/t/comparative-bar-charts/14464/7
#pragma sequence(scan,explore) 
wlnum = GetOption("FilterIncludeWatchlist");
if ( Status( "action" ) == actionScan ) {
	if ( Status("stocknum") == 0 )	StaticVarRemove("values*");
	if ( InWatchList(wlnum) )	StaticVarSet("values"+Name(), ROC(C, 1));
}
if (Status("stocknum") == 0) {
	dt = SelectedValue(DateTime());
	topranks = StrCount(CategoryGetSymbols(categoryWatchlist,wlnum),",")+1;
	StaticVarGenerateRanks("top", "values", topranks, 1224); // top-N mode 
	symlist = StaticVarGetRankedSymbols( "top", "values", dt ); 
	chart_name = "BarChart";	
	XYChartSetAxis(chart_name, StrFormat("%s - %s", DateTimeToStr(dt, 1), Interval(2)), "Yield %", styleHistogram); // Setup chart
	for (i = 0; (symbol = StrExtract(symlist, i)) != ""; i++) { // Populate chart with sorted values		
		value = SelectedValue(StaticVarGet("values"+symbol)); // Get yield value
		color = IIf(value<0, colorRed, colorGreen); // Assign color
		if ( i == 0 AND value < 0 ) XYChartAddPoint(chart_name, "", 0, 0);
		XYChartAddPoint(chart_name, StrFormat("%s  %1.2f",symbol, value), i + 1, value, color); // Add symbol value to chart
	}
}
4 Likes

Looks like you are not using code to sort the data before adding symbols via XYChartAddPoints. Either my example where symbols are sorted using matrix sort or fxshrat's example using StaticVarGenerateRanks does the sorting.

1 Like

The error you mentioned is easily avoided by adding an if clause to check for symcount == 0.

Why do you prefer to use static variables instead of a matrix sort for this purpose? Do you believe the static variable approach is faster or uses less resources than the matrix approach?

Thanks for the help, can you show a chart like @fxshart ?. Can be posted please. Thanks

Each time the barchart tab is clicked Amibroker crashes. Is it because the script is for 6.40 and I am still using 6.35 ?

You don't need additional if statement!
This can be removed completely

if(StrLen(SymList)) symcount = StrCount(SymList, ",") + 1; else symcount = 0;

Also you do not need to find chartmax as you did. All code involving chartmax can be removed.
instead you just have to check first element of sorted array.

if (yield[0][0] <= 0) XYChartAddPoint(title, "", 0, 0); // Add 0 value to chart to force desired layout

Because it does not run with two loops and it stores array to be sorted. Yours is applied on single element.
So with the code using staticvargenerateranks if it is applied on thousands of symbols there should be a difference in speed. E.g. if you want to look at historical data you just have to run runsequence (or scan) just once (if data and symbols do not change) and for any further look at the past you just have to run explore only (with using From-to dates of toolbar and just selecting the to date) without further scan.

NOTE: the Error code line added in below code does not notice about code error but it is supposed to be a notice about exploration having finished after run of first FILTER symbol (and to not unnecessarily run on any further symbol) !!! You just have to click BarChart tab after it shows up as written in that notice.

/// code source
/// @link https://forum.amibroker.com/t/comparative-bar-charts/14464/13
#pragma sequence(scan,explore) 
wlnum = GetOption("FilterIncludeWatchlist");
if ( Status( "action" ) == actionScan ) {
	if ( Status("stocknum") == 0 )	StaticVarRemove("values*");
	if ( InWatchList(wlnum) )	StaticVarSet("values"+Name(), ROC(C, 1));
	_exit();
}
if (Status("stocknum") == 0) {
	dt = SelectedValue(DateTime());
	topranks = StrCount(CategoryGetSymbols(categoryWatchlist,wlnum),",")+1;
	top_n = Min(30, topranks); // top n to be displayed in chart
	StaticVarGenerateRanks("top", "values", topranks, 1224); // top-N mode 
	symlist = StaticVarGetRankedSymbols( "top", "values", dt ); 
	chart_name = "BarChart";	
	XYChartSetAxis(chart_name, StrFormat("%s - %s", DateTimeToStr(dt, 1), Interval(2)), "Yield %", styleHistogram); // Setup chart
	first_val = SelectedValue(StaticVarGet("values"+StrExtract(symlist,0)));
	if (first_val < 0)	XYChartAddPoint(chart_name, "", 0, 0);
	for (i = 0; i < top_n; i++) { // Populate chart with sorted values	
		symbol = StrExtract(symlist, i);
		value = SelectedValue(StaticVarGet("values"+symbol)); // Get yield value
		color = (value<0)*colorRed + (value>0)*colorGreen; // Assign color
		XYChartAddPoint(chart_name, StrFormat("%s  %1.2f",symbol, value), i + 1, value, color); // Add symbol value to chart
	}	
} else // Interrupt exploration after first symbol run
	Error( "EXPLORATION FINISHED! (Click 'BarChart' tab in analysis window)" );


It is exploration code but NOT chart pane code !!!


There is no crash.

1 Like

Ok, I try in explorer. Thanks

will try to make a short video and share if it happens the next time I test again.

The chart my code generates is identical to the chart posted by fxshart.

Chartmax serves a function. If all of the values are negative as a recent chart of the S&P 500 sectors was recently, the chart will look quite different without the added 0 column when Chartmax is less than 0.

You still don't get it.
You do not need chartmax for that!
Re-read my post and try to understand.

If all elements of sorted yield matrix are negative then yield[0][0] is the maximum !!!
Am I talking with Martian dialect? :roll_eyes:

3 Likes

Yes, I agree with you. Your solution is much better than the way I calculated chartmax. My point was it is necessary to look at the max value and add a 0 column if they are all negative to get the chart to display in the desired way.