Error 61: Telechart T2107 Indicator


#1

Newbie Alert
AmiBroker 6.20.1
Worden TeleChart v7 EOD data
I receive Error 61 when examining Telechart's Market Indicators such as T2107 (% Stocks Above 200 Day) and T2108 (% Stocks Above 40 Day) stating the format is mismatched.
How can I fix this?
AmiBroker%20T2107%202018-02-10

Thanks for the help,
Greg


#2

Some of your FullNames contain "%" character (percent sign). "%" is also used in format specifiers (i.e. "%g", "%s", "%1.2f" etc.). Your formula contains printf function. printf uses format specifiers. So if you want to print percent sign (your case) instead of using it for format specifiers you need to add another "%" character in front of existing "%" character of your tname substring (in your case Fullname() ).

So

nm = Name();
fnm = StrReplace(FullName(), "%", "%%");
tname = nm + "(" + fnm + ")";
printf( tname );

or for example

nm = Name();
fnm = StrReplace(FullName(), "%", "%%");
tname = StrFormat( "%s(%s)", nm, fnm );
printf( tname );

or just

nm = Name();
fnm = StrReplace(FullName(), "%", "%%");
printf( "%s(%s)", nm, fnm );

Latter two examples require AmiBroker 6.20 because of new "%s" format specifier.

functions using format specifiers:
https://www.amibroker.com/guide/afl/printf.html
https://www.amibroker.com/guide/afl/strformat.html
https://www.amibroker.com/guide/afl/datetimeformat.html


#3

Correction for last code example of previous post:
If using printf() with format specifier "%s" then there is no replacement of corresponding output string required. So then it works like so

Version( 6.20 );

nm = Name();
fnm = FullName();
printf( "%s(%s)", nm, fnm );// also works if FullName contains "%" character.

Same is true if using StrFormat variable within printf as function argument larger than 1.
i.e.

Version( 6.20 );

nm = Name();
fnm = FullName();
tname = StrFormat( "%s(%s)", nm, fnm );
printf( "%s", tname );

If using StrFormat within first argument of printf and Fullname() containing "%" character then you have to do it as seen in 2nd post of this thread so here again:

Version( 6.20 );

nm = Name();
fnm = StrReplace(FullName(), "%", "%%");
tname = StrFormat( "%s(%s)", nm, fnm );
printf( tname );

#4

The thing is that first argument of printf / StrFormat should not be fed from unknown source. First argument is formatting sequence and it should be fixed in the code. The commentary code from OP post was from the old days when there was no %s specifier available but nowadays instead of printf( string ); one should use printf ("%s", string );


#5

@Tomasz Do I actually edit the code of _Price.afl at Line 58?

The screenshot above is just me clicking among Market Indicators after setting up the TC200x plug-in. I had not even run code yet.


#6

Is there a newer version of the TC200x plug-in?
There seems to be confusion that my code is producing the error. In this case I simply set up the plug-in and updated the data. This was a clean installation of AmiBroker6201.exe and I clicked on the Symbols | Groups | Market Indicators section just checking that data imported properly.


#7

_Price.afl

_SECTION_BEGIN("Price");
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) Vol " +WriteVal( V, 1.0 ) +" {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 )) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 
_SECTION_END();

_SECTION_BEGIN("MA");
P = ParamField("Price field",-1);
Periods = Param("Periods", 15, 2, 200, 1 );
Plot( MA( P, Periods ), _DEFAULT_NAME(), ParamColor( "Color", colorCycle ), ParamStyle("Style", styleLine | styleNoLabel ) | styleNoRescale ); 
_SECTION_END();

_SECTION_BEGIN("Mid MA");
P = ParamField("Price field",-1);
Periods = Param("Periods", 45, 2, 300, 1 );
Plot( MA( P, Periods ), _DEFAULT_NAME(), ParamColor( "Color", colorCycle ), ParamStyle("Style", styleHidden | styleLine | styleNoLabel ) | styleNoRescale ); 
_SECTION_END();

_SECTION_BEGIN("Long MA");
P = ParamField("Price field",-1);
Periods = Param("Periods", 100, 2, 400, 1 );
Plot( MA( P, Periods ), _DEFAULT_NAME(), ParamColor( "Color", colorCycle ), ParamStyle("Style", styleHidden | styleLine | styleNoLabel ) | styleNoRescale ); 
_SECTION_END();

_SECTION_BEGIN("BBands");
P = ParamField("Price field",-1);
Periods = Param("Periods", 15, 2, 100, 1 );
Width = Param("Width", 2, 0, 10, 0.05 );
Color = ParamColor("Color", colorLightGrey );
Color = ColorBlend( Color,  GetChartBkColor(), 0.5 );
Style = ParamStyle("Style", styleLine | styleNoLabel ) | styleNoRescale;;
Plot( bbt = BBandTop( P, Periods, Width ), "BBTop" + _PARAM_VALUES(), Color, Style ); 
Plot( bbb = BBandBot( P, Periods, Width ), "BBBot" + _PARAM_VALUES(), Color, Style ); 
PlotOHLC( bbt, bbt, bbb, bbb, "", ColorBlend( Color, GetChartBkColor(), 0.7 ), styleNoLabel | styleCloud | styleNoRescale, Null, Null, Null, -1 );
_SECTION_END();

_SECTION_BEGIN("Price Interpretation");
movshort = ParamField("Short Time MA", 8 );
movmed = ParamField("Mid Time MA", 9 );
movlong = ParamField("Long Time MA", 10 );
btop = ParamField("BBTop", 11 );
bbot = ParamField("BBBottom", 12 );
if( Status("action") == actionCommentary )
{
width = btop - bbot;
lslop = LinRegSlope( C, 30 ) + 100;
lslo = LLV( lslop, 90 );
lshi = HHV( lslop, 90 );
lswidth = lshi - lslo;
trend = 100*( lslop - lslo )/lswidth;

mawidth = MA( width, 100 );
relwidth = 100*(width - mawidth)/mawidth;

_N( tname = Name()+"("+FullName()+")" );

printf("Price and moving averages:\n");
printf( tname + " has closed " + WriteIf( C > movshort, "above" , "below" ) + " its Short time moving average. ");

printf("\nShort time moving average is currently " + WriteIf( movshort > movmed, "above", "below") + " mid-time, AND " + WriteIf( movshort > movlong, "above", "below" ) + " long time moving averages.");

printf("\nThe relationship between price and moving averages is: "+
WriteIf( C > movshort AND movshort > movmed, "bullish",
WriteIf( C < movshort AND movshort < movmed, "bearish", "neutral" ) ) + " in short-term, and "+
WriteIf( movshort > movmed AND movmed > movlong , "bullish",
WriteIf( movshort < movmed AND movmed < movlong, "bearish", "neutral" ) ) + " in mid-long term. ");

printf("\n\nBollinger Bands:\n");
printf(tname+ " has closed " + 
WriteIf( C < bbot, "below the lower band by " +
WriteVal( 100 *( bbot-C )/ width, 1.1 ) + "%%. " +
WriteIf( trend < 30, " This combined with the steep downtrend can suggest that the downward trend in prices has a good chance of continuing.  However, a short-term pull-back inside the bands is likely.",
WriteIf( trend > 30 AND trend < 70, "Although prices have broken the lower band and a downside breakout is possible, the most likely scenario for "+tname+" is to continue within current trading range.", "" ) ), "" ) +

WriteIf( C > btop, "above the upper band by " +
WriteVal( 100 *( C- btop )/ width, 1.1 ) + "%%. " +
WriteIf( trend > 70, " This combined with the steep uptrend suggests that the upward trend in prices has a good chance of continuing.  However, a short-term pull-back inside the bands is likely.",
WriteIf( trend > 30 AND trend < 70, "Although prices have broken the upper band and a upside breakout is possible, the most likely scenario for "+tname+" is to continue within current trading range.", "" ) ), "" ) +

WriteIf( C < btop AND ( ( btop - C ) / width ) < 0.5, 
"below upper band by " +
WriteVal( 100 *( btop - C )/ width, 1.1 ) + "%%. ", 
WriteIf( C < btop AND C > bbot , "above bottom band by " +
WriteVal( 100 *( C - bbot )/ width, 1.1 ) + "%%. ", "" ) ));

printf("\n"+
WriteIf( ( trend > 30 AND trend < 70 AND ( C > btop OR C < bbot ) ) AND abs(relwidth) > 40,
		 "This picture becomes somewhat unclear due to the fact that Bollinger Bands are  currently",
		 "Bollinger Bands are " )+	  
WriteVal( abs( relwidth ), 1.1 ) + "%% " +
WriteIf( relwidth > 0, "wider" , "narrower" ) +
" than normal.");

printf("\n");

printf(
WriteIf( abs( relwidth ) < 40, "The current width of the bands (alone) does not suggest anything conclusive about the future volatility or movement of prices.","")+
WriteIf( relwidth < -40, "The narrow width of the bands suggests low volatility as compared to " + tname + "'s normal range.  Therefore, the probability of volatility increasing with a sharp price move has increased for the near-term. "+
"The bands have been in this narrow range for " + WriteVal(BarsSince(Cross(-40,relwidth)),1.0) + " bars. The probability of a significant price move increases the longer the bands remain in this narrow range." ,"")+
WriteIf( relwidth > 40, "The large width of the bands suggest high volatility as compared to " + tname + "'s normal range.  Therefore, the probability of volatility decreasing and prices entering (or remaining in) a trading range has increased for the near-term. "+
"The bands have been in this wide range for  " + WriteVal(BarsSince(Cross(relwidth,40)),1.0) + " bars.The probability of prices consolidating into a less volatile trading range increases the longer the bands remain in this wide range." ,""));

printf("\n\nThis commentary is not a recommendation to buy or sell. Use at your own risk.");
}
_SECTION_END();

I see that tname is the problem. Thanks @fxshrat for pointing out the right-click context menu to load the code. I had viewed _Price.afl but assumed it was system code which I should not, as a newbie, edit.


#8

As it has been said already it has got to do with wrong AFL code not being inline with new implementations checking for wrong format within printf/StrFormat functions! But not with your data plugin.

From AB 6.07 development version:

AFL: printf/StrFormat now implement a check for correct formatting string as sometimes users passed strings with % that is special marker for formatting string instead of %% to print actual percent sign.

So if such lonely "%" signs occur in printf/StrFormat first argument because of old code not using proper way of inserting string to printf/StrFormat functions then Error 61 will appear. That is the case in your example. Why? Because Fullname in your code is used within first argument AND some symbols having "%" sign within Fullname.

See yourself and test this:

printf( "%Average" );

It will result in error in your AB 6.20.

Correct and save way is using "%s" from now on (AB 6.20 and above).
So,

printf( "%s", "%Average" );

So here is corrected code (there are other things I do not like the way it has been made. But I only corrected it in such way so that your code will not produce error 61):

Version( 6.20 );

_SECTION_BEGIN("Price");
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) Vol " +WriteVal( V, 1.0 ) +" {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 )) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 
_SECTION_END();

_SECTION_BEGIN("MA");
P = ParamField("Price field",-1);
Periods = Param("Periods", 15, 2, 200, 1 );
Plot( MA( P, Periods ), _DEFAULT_NAME(), ParamColor( "Color", colorCycle ), ParamStyle("Style", styleLine | styleNoLabel ) | styleNoRescale ); 
_SECTION_END();

_SECTION_BEGIN("Mid MA");
P = ParamField("Price field",-1);
Periods = Param("Periods", 45, 2, 300, 1 );
Plot( MA( P, Periods ), _DEFAULT_NAME(), ParamColor( "Color", colorCycle ), ParamStyle("Style", styleHidden | styleLine | styleNoLabel ) | styleNoRescale ); 
_SECTION_END();

_SECTION_BEGIN("Long MA");
P = ParamField("Price field",-1);
Periods = Param("Periods", 100, 2, 400, 1 );
Plot( MA( P, Periods ), _DEFAULT_NAME(), ParamColor( "Color", colorCycle ), ParamStyle("Style", styleHidden | styleLine | styleNoLabel ) | styleNoRescale ); 
_SECTION_END();

_SECTION_BEGIN("BBands");
P = ParamField("Price field",-1);
Periods = Param("Periods", 15, 2, 100, 1 );
Width = Param("Width", 2, 0, 10, 0.05 );
Color = ParamColor("Color", colorLightGrey );
Color = ColorBlend( Color,  GetChartBkColor(), 0.5 );
Style = ParamStyle("Style", styleLine | styleNoLabel ) | styleNoRescale;;
Plot( bbt = BBandTop( P, Periods, Width ), "BBTop" + _PARAM_VALUES(), Color, Style ); 
Plot( bbb = BBandBot( P, Periods, Width ), "BBBot" + _PARAM_VALUES(), Color, Style ); 
PlotOHLC( bbt, bbt, bbb, bbb, "", ColorBlend( Color, GetChartBkColor(), 0.7 ), styleNoLabel | styleCloud | styleNoRescale, Null, Null, Null, -1 );
_SECTION_END();

_SECTION_BEGIN("Price Interpretation");
movshort = ParamField("Short Time MA", 8 );
movmed = ParamField("Mid Time MA", 9 );
movlong = ParamField("Long Time MA", 10 );
btop = ParamField("BBTop", 11 );
bbot = ParamField("BBBottom", 12 );
if( Status("action") == actionCommentary )
{
	width = btop - bbot;
	lslop = LinRegSlope( C, 30 ) + 100;
	lslo = LLV( lslop, 90 );
	lshi = HHV( lslop, 90 );
	lswidth = lshi - lslo;
	trend = 100*( lslop - lslo )/lswidth;

	mawidth = MA( width, 100 );
	relwidth = 100*(width - mawidth)/mawidth;

	_N( tname = Name()+"("+FullName()+")" );

	printf("Price and moving averages:\n");

	printf( "%s has closed %s its Short time moving average. ", tname, WriteIf( C > movshort, "above" , "below" )  );

	printf("\nShort time moving average is currently %s mid-time, AND %s long time moving averages.", 
			WriteIf( movshort > movmed, "above", "below"), 
			WriteIf( movshort > movlong, "above", "below" ));

	condstr1 =	"\nThe relationship between price and moving averages is: "+
				WriteIf( C > movshort AND movshort > movmed, "bullish",
				WriteIf( C < movshort AND movshort < movmed, "bearish", "neutral" ) ) + " in short-term, and "+
				WriteIf( movshort > movmed AND movmed > movlong , "bullish",
				WriteIf( movshort < movmed AND movmed < movlong, "bearish", "neutral" ) ) + " in mid-long term. ";
	
	printf("%s", condstr1 );

	printf("\n\nBollinger Bands:\n");

	condstr2 = tname + " has closed " +
			   WriteIf( C < bbot, "below the lower band by " +
						WriteVal( 100 * ( bbot - C ) / width, 1.1 ) + "%%. " +
						WriteIf( trend < 30, " This combined with the steep downtrend can suggest that the downward trend in prices has a good chance of continuing.  However, a short-term pull-back inside the bands is likely.",
								 WriteIf( trend > 30 AND trend < 70, "Although prices have broken the lower band and a downside breakout is possible, the most likely scenario for " + tname + " is to continue within current trading range.", "" ) ), "" ) +

			   WriteIf( C > btop, "above the upper band by " +
						WriteVal( 100 * ( C - btop ) / width, 1.1 ) + "%%. " +
						WriteIf( trend > 70, " This combined with the steep uptrend suggests that the upward trend in prices has a good chance of continuing.  However, a short-term pull-back inside the bands is likely.",
								 WriteIf( trend > 30 AND trend < 70, "Although prices have broken the upper band and a upside breakout is possible, the most likely scenario for " + tname + " is to continue within current trading range.", "" ) ), "" ) +

			   WriteIf( C < btop AND( ( btop - C ) / width ) < 0.5,
						"below upper band by " +
						WriteVal( 100 * ( btop - C ) / width, 1.1 ) + "%%. ",
						WriteIf( C < btop AND C > bbot , "above bottom band by " +
						WriteVal( 100 * ( C - bbot ) / width, 1.1 ) + "%%. ", "" ) );
	printf( "%s\n", condstr2 );
	
	condstr3 =	WriteIf( ( trend > 30 AND trend < 70 AND ( C > btop OR C < bbot ) ) AND abs(relwidth) > 40,
						 "This picture becomes somewhat unclear due to the fact that Bollinger Bands are  currently",
						 "Bollinger Bands are " )+	  
				WriteVal( abs( relwidth ), 1.1 ) + "%% " +
				WriteIf( relwidth > 0, "wider" , "narrower" ) +
				" than normal.";

	printf("%s\n", condstr3);

	condstr4 =	WriteIf( abs( relwidth ) < 40, "The current width of the bands (alone) does not suggest anything conclusive about the future volatility or movement of prices.", "" ) +
				WriteIf( relwidth < -40, "The narrow width of the bands suggests low volatility as compared to " + tname + "'s normal range.  Therefore, the probability of volatility increasing with a sharp price move has increased for the near-term. " +
						 "The bands have been in this narrow range for " + WriteVal( BarsSince( Cross( -40, relwidth ) ), 1.0 ) + " bars. The probability of a significant price move increases the longer the bands remain in this narrow range." , "" ) +
				WriteIf( relwidth > 40, "The large width of the bands suggest high volatility as compared to " + tname + "'s normal range.  Therefore, the probability of volatility decreasing and prices entering (or remaining in) a trading range has increased for the near-term. " +
						 "The bands have been in this wide range for  " + WriteVal( BarsSince( Cross( relwidth, 40 ) ), 1.0 ) + " bars.The probability of prices consolidating into a less volatile trading range increases the longer the bands remain in this wide range." , "" );
	printf( "%s", condstr4 );

	printf("\n\nThis commentary is not a recommendation to buy or sell. Use at your own risk.");
}
_SECTION_END();

#9

@fxshrat, First off, thank you very much for all of the work and for fixing this code. I am analyzing your corrections line-by-line as a tutorial. You're quite talented and I truly appreciate your efforts.

Question:
Where did _Price.afl originate as I did not write that code and it is found in the hidden directory Drag-Drop? Shoot, I did not realize I could edit base code like that in AB without breaking something!

In addition, thank you for kindly pushing me along. I know it must have been a frustrating exercise on your part.


#10

@fxshrat I like the way you broke out the multiple WriteIf() functions to feed condstrX variables. It is easier to review the code and also separates the printf() for better visibility.