Exploration Results differ from PositionScore choices using rankings from Static Variables


#1

I'm having an issue where, when comparing the exploration results of the highest ranked stocks in an exploration (using the exact same system code) on an/any specific date and then compare the stocks that were actually chosen by the system on the same exact specific dates, varies significantly.

The code is designed to rank according to two distinct rankings using a slightly modified Static Variable method outlined here in the last example by creating multiple static variables and combining them -- https://www.amibroker.com/guide/h_ranking.html

  • The system rotates a list of 20 stocks monthly
  • When I run the same code in exploration on any of the dates shown by the system, the purchase decisions for the list of stocks are different even though the buy criteria uses the same combined ranking i.e. PositionScore = combined ranking

In other words, if I run the system and look at any specific date and then run the exploration using exact same code, the 20 stocks that rank highest in the exploration do not match those chosen by positionscore. In fact, the stocks chosen from the PositionScore decision making process are way down the ranking list versus the top rankings shown in the exploration.

I hope it won't be difficult to picture this scenario without posting the entire code, otherwise perhaps I can post the code and take out some things. I usually don't mind sharing most code but I'm testing this system on information given from someone else and that person would prefer I do not make it public knowledge.

Thank you. Regards,

DaveDM


#2

@DaveDM

it isn't difficult to understand what you are saying. But, you almost certainly have a mistake in your code. So for anyone to help you correct that code it would be ridiculous to even try without looking at it, testing it, attempting corrections to it.

Trust me, you have not discovered the Holy Grail, but if you are really hesitant to reveal you secret sauce, just make simple change to your ranking generation (that is your secret, not the idea of a rotational strategy) and plug in something generic like a momentum score. If that gives you the same problem that you've been seeing, then post this code and members of the forum can try to help.

If a simple momentum score corrects your problem then you have at least narrowed it down to the "secret sauce" being your source of mistakes.

Good luck.


#3

In addition to @portfoliobuilder 's comments, make sure that if you're using trade delays for entry that you're comparing the Exploration list from the bar that the entry signal was generated, not the bar that it was executed.


#4

@portfoliobuilder

TY. I simplified the code and here it is. Funny thing is, it now seems to work as intended. The real code is not that much different from the simplified code except for the calculation of each value in the Rank section. Perhaps there is some complexity or nuance in the actual formulae used that is throwing off the ranking somehow. In this example you can see that if you run a back test in one Analysis window and an Exploration of a specific date in another Analysis window, the stock picks actually line up for that specific buy date. I was looking at 02/03/2018. I'm scratching my head right now... :-/


// Position Sizing

maxpos = param("Maximum Positions", 20, 1, 100, 1); // maximum number of open positions
startequity = Param("Starting Equity", 100000, 5000, 1000000, 1000);
SetOption("InitialEquity", startequity ); // set initial equity = 100K
SetOption( "MaxOpenPositions", maxpos );
SetPositionSize( 100 / maxpos, spsPercentOfEquity );


// Calculate EMA's
	SMA1 = MA(Close, 100);
	SMA2 = MA(Close, 200);
	
// No fractional shares
RoundLotSize = 1;


BuyDayofMonth = param("Buy Day of Month", 1, 1, 31, 1); // 1 and 2 best optimized values

d = Day();
m = Month();

BuyDay[ 0 ] = d[ 0 ];
for( j = 1; j <= 31; j++)

{

if ((d[j] == BuyDayofMonth) OR ((d[j] == BuyDayofMonth + 1 OR d[j] == BuyDayofMonth + 2 OR d[j] == BuyDayofMonth + 3 OR d[j] == BuyDayofMonth + 4) AND Buy = 0));
{	
	


if ( GetOption( "ApplyTo" ) == 2 )
{
     wlnum = GetOption( "FilterIncludeWatchlist" );
     List = CategoryGetSymbols( categoryWatchlist, wlnum ) ;
}
else
if ( GetOption( "ApplyTo" ) == 0 )
{
     List = CategoryGetSymbols( categoryAll, 0 );
}
else
{
     Error( "The formula works fine if your ApplyTo setting is 'Filter' or 'All' " );
}


// Rank1

if ( Status("stocknum") == 0 ) 
{
    StaticVarRemove( "values1*" );

    for ( m = 0; ( Symbol = StrExtract( List, m ) )  != "";  m++    )
    {
        SetForeign ( symbol );        
             
        values1 = RSI(14);
        
        RestorePriceArrays();
        StaticVarSet ( "values1" + symbol, values1 );
        _TRACE( symbol );
    }

    StaticVarGenerateRanks( "rank1", "values1", 0, 1224); 
}

symbol = Name();

values1 = StaticVarGet ( "values1" + symbol );
rank1 = StaticVarGet ( "rank1values1" + symbol );

AddColumn ( values1, "Values1" );
AddColumn ( rank1, "Rank1" );


Filter = 1;

SetSortColumns( 2, 4 );

// Rank2

if ( GetOption( "ApplyTo" ) == 2 )
{
     wlnum = GetOption( "FilterIncludeWatchlist" );
     List = CategoryGetSymbols( categoryWatchlist, wlnum ) ;
}
else
if ( GetOption( "ApplyTo" ) == 0 )
{
     List = CategoryGetSymbols( categoryAll, 0 );
}
else
{
     Error( "The formula works fine if your ApplyTo setting is 'Filter' or 'All' " );
}


if ( Status("stocknum") == 0 ) 
{
    StaticVarRemove( "values2*" );

    for ( m = 0; ( Symbol = StrExtract( List, m ) )  != "";  m++    )
    {
        SetForeign ( symbol );        
       
        values2 = RSI(20);
        
        RestorePriceArrays();
        StaticVarSet ( "values2" + symbol, values2 );
        _TRACE( symbol );
    }

    StaticVarGenerateRanks( "rank2", "values2", 0, 1224); 
}

symbol = Name();

values2 = StaticVarGet ( "values2" + symbol );
rank2 = StaticVarGet ( "rank2values2" + symbol );

AddColumn ( values2, "Values2" );
AddColumn ( rank2, "Rank2" );

Filter = 1;

SetSortColumns( 2, 4 );


// Combine Values

combinedrankvalues = rank1 + rank2 ;
combinedrank = (1/combinedrankvalues) ; // Use for inverting so largest number for lowest/best combined rank for when using PositionScore

AddColumn( combinedrankvalues, "Combined Rank Values" ) ;
AddColumn( combinedrank, "Combined Rank" ) ;


PositionScore = combinedrank ; 
		
	
	Buy = Ref(C, -1) > SMA1 AND Ref(C, -1) > SMA2;
}
 
 
}  
   
  Mnth = Month();
     
    BuyDay[ 0 ] = d[ 0 ];
	for( j = 1; j <= 31; j++)
{

		Sell = (Month() != Ref(Mnth, -1) and (d[j] == BuyDayofMonth OR d[j] == BuyDayofMonth + 1 OR d[j] = BuyDayofMonth + 2 OR d[j] == BuyDayofMonth +3 OR d[j] == BuyDayofMonth + 4)) ;
		
}
   

BuyPrice = close;
SellPrice = close;





#5

@DaveDM I hope that has solved your problem, but may I at least point out to you that your original post mentioned

But in your code you are not using AmiBroker's built in rotational settings such as,

SetBacktestMode( backtestRotational );

If you had then you would not use regular buy/sell/short/cover signals at all.

Perhaps worth reviewing,
https://www.amibroker.com/guide/afl/enablerotationaltrading.html

http://www.amibroker.com/kb/2016/01/30/separate-ranks-for-categories-that-can-be-used-in-backtesting/

http://www.amibroker.com/kb/2016/04/17/long-only-rotational-back-test/

And a search on this forum will find maybe a dozen threads which discuss various rotational strategies.
image

And lastly your code (perhaps because you only permitted the world a glimpse of a portion) is full of syntax errors,

image


#6

Please use techniques described here: How do I debug my formula?