I tried to get it working, but have trouble to get reproducable results.
PART ONE: Trying to run the original code by rocketpower (post #1)
I changed rocketpowers original code only slightly to run it as exploration (refer to first line in this code). I also left the last line as "StaticVarRemove("RankRSraw*_");", altough the * should be placed after the underline.
// Relative Strength ranking of stocks by @rocketpower, modified by @RioL(line 4-6 commented out the market lists, line 11 changed to testing list, changed output watchlist in line 45 and 47, in last line 53 is the * still in front of the "_" - should be afterwards)
// Choose markets to include in the universe (I only use NYSE Market and delisted databases for backtesting hence why they are commented out)
//listNYSE = CategoryGetSymbols(categoryMarket, 1);
//listNSDQ = CategoryGetSymbols(categoryMarket, 2);
//listARCA = CategoryGetSymbols(categoryMarket, 3);
//listNMKT = CategoryGetSymbols(categoryMarket, 4);
//listDLST = CategoryGetSymbols(categoryMarket, 14);
// Create the full list of stocks to be ranked
List = CategoryGetSymbols(categoryWatchlist, 3); //list with 439 symbols for testing
ListQty = StrCount(List, ",") + 1;
// Determine the quantity of stocks to rank
StaticVarSet("UniListTotal", ListQty, True);
// Clear the static vars from last run
StaticVarRemove( "RS_*" );
// Generate the raw RS score for every stock and store in a static var
for (n = 0; (Symbol = StrExtract(List, n)) != ""; n++)
{
SetForeign (Symbol);
// relative strength IBD style
ThreeMthRS = 0.4*(C/Ref(C,-63));
SixMthRS = 0.2*(C/Ref(C,-63*2));
NineMthRS = 0.2*(C/Ref(C,-63*3));
TwelveMthRS = 0.2*(C/Ref(C,-63*4));
RSraw = ThreeMthRS + SixMthRS + NineMthRS + TwelveMthRS;
RestorePriceArrays();
StaticVarSet("RSraw_" + Symbol, RSraw);
}
// rank the stocks using this extremely useful function!
StaticVarGenerateRanks("Rank", "RSraw_", 0, 1224);
// Convert the static var ranks generated into a percentile score.
for (n = 0; (Symbol = StrExtract(List, n)) != ""; n++)
{
Rank = StaticVarGet ("RankRSraw_" + Symbol);
RSpctile = 100 - 100*Rank/ListQty;
StaticVarSet("RS_" + Symbol, RSpctile, True);
// use this opportunity to store the highest ranking stocks in a watchlist.
if (LastValue(RSpctile) >= 95)
CategoryAddSymbol( Symbol, categoryWatchlist, 62);
else
CategoryRemoveSymbol(Symbol, categoryWatchlist, 62);
}
// remove unnecessary static data
// free up old stuff
StaticVarRemove("RSraw_*");
StaticVarRemove("RankRSraw*_");
I did run it with these settings and set as filter the watchlist number 3 as in the code and cleared my output watchlist number 62.
After pressing "Explore" I exported the watchlist 62 and cleared it again to run the exploration again, comparing the tickers from run 1 and run 2 it showed both lists do have 21 symbols, but each list has some unique symbols! My expectation was: Both lists have the same symbols, the order might vary due to multithreading.
Correcting the last line to
StaticVarRemove("RankRSraw_*");
does not help (still 21 symbols as result, but some symbols are not reproducible). And neither does it help to activate the "Pad and align ..." option as suggested by the info-tab of the exploration. I tried it with ^DJI (21 symbols as result, some unique) and NEON, a ticker from my test-watchlist, which was also part of the previous result lists (once 17 symbols and one 19 symbols as result, some unique).
PART TWO: Trying to debug it with exploration tables to find my mistake
With the help of comment #2 by @beppe I tried some more, but was not able to get my desired result of always getting the same tickers and the same RSpctile-value with the origianl code.
I sort of got an acceptable result after splitting the code into two parts and run them one after the other as a exploration like described earlier. The results are now always the same for the tested date and my testlist. I also tested it for all my 10662 tickers: Adjusted the variable "List" in the following code "part 1" and set the exploration to "All symbols" with a defined date, with "1 recent bar(s)" and with "1 recent day(s)". In all cases the exploration took less than a minute (Intel Core i7 7th Gen, 8 threads used by AmiBroker) and the first and the second run had the same identical results.
Here are the two exploration codes:
// Relative Strength ranking of stocks part 1
// code by rocketpower, modified by RioL
// run in Exploration window, set the same ticker list (see variable "List") as a filter.
Filter = 1; // all quotes and symbols are accepted
// Determine the quantity of stocks to rank
if( Status( "stocknum" ) == 0 )
{
// Choose markets to include in the universe (I only use NYSE Market and delisted databases for backtesting hence why they are commented out)
//List = CategoryGetSymbols(categoryAll, 0);
List = CategoryGetSymbols(categoryWatchlist, 3);
ListQty = StrCount(List, ",") + 1;
StaticVarSet("UniListTotal", ListQty, True);
// Clear the static vars from last run (the second and third are only integrated to ensure a proper start in case the last run was aboarded)
StaticVarRemove( "RS_*");
}
AddColumn( StaticVarGet("UniListTotal", True), "UniListTotal" );
AddTextColumn( MarketID( 1 ), "Market name" );
AddColumn( Close, "Close" );
// Generate the raw RS score for every stock and store in a static var
// relative strength IBD style
ThreeMthRS = 0.4*(C/Ref(C,-63));
SixMthRS = 0.2*(C/Ref(C,-63*2));
NineMthRS = 0.2*(C/Ref(C,-63*3));
TwelveMthRS = 0.2*(C/Ref(C,-63*4));
RSraw = ThreeMthRS + SixMthRS + NineMthRS + TwelveMthRS;
AddColumn( RSraw, "RSraw", 1.2 );
StaticVarSet("RSraw_" + Name(), RSraw);
SetSortColumns(-6,1);
// Relative Strength ranking of stocks part 2
// code by rocketpower, modified by RioL
// run in Exploration window, set the same ticker list (see variable "List" in part 1) as a filter.
Filter = 1; // all quotes and symbols are accepted
if( Status( "stocknum" ) == 0 )
{
// rank the stocks using this extremely useful function!
StaticVarGenerateRanks("Rank", "RSraw_", 0, 1224);
}
AddTextColumn( MarketID( 1 ), "Market name" );
AddColumn( Close, "Close" );
AddColumn(StaticVarGet("RSraw_" + Name()), "RSraw_StaticVar");
AddColumn(StaticVarGet("RankRSraw_" + Name()), "RankRSraw_StaticVar");
// Convert the static var ranks generated into a percentile score.
Rank = StaticVarGet ("RankRSraw_" + Name());
RSpctile = 100 - 100*Rank/StaticVarGet("UniListTotal", True);
AddColumn( RSpctile, "RSpctile" );
StaticVarSet("RS_" + Name(), RSpctile, True);
SetSortColumns(-7,1);
/*// Commented out, because it causes nearly empty columns for "RankRSraw" and "RSpctile" - only one ticker shows results.
// remove unnecessary static data
// free up old stuff
if( Status( "stocknum" ) == 0 )
{
StaticVarRemove( "RSraw_*");
StaticVarRemove("RankRSraw_*");
}
*/
Thanks for taking the time to read this long post, I'll appreciate any input.