Please Help me correct my code for 2-pass Ranking model

Hi All,

My model is
1st step : Select the top 60 stocks (from all 700 stocks in universe) using Ranking of criteria-1
2nd step : then, select the top 20 stocks (from 60 stocks in 1st step) using Ranking of criteria-2
3rd step : invest in this 20 stocks and hold for 20 days then rebalance to invest in another new 20 stocks.

Because I am so novice on coding and programming, I used to ask how to code this model here.


but The code I got is a bit too complicated for me to translate and modify.

So I write the code by myself with guideline from
https://www.amibroker.com/guide/afl/staticvargenerateranks.html
As example, I use Close price as criteria-1, ROC as criteria-2
1st step :I use staticvargenerateranks function
2nd step :I use positionscore
3rd step :I use ApplyStop :stopTypeNBar

{//Option
	SetOption("InitialEquity" , 1000000);
	SetOption("MaxOpenPositions", 20);
	SetOption("MinShares", 100);
	RoundLotSize = 100;
	SetOption("CommissionMode", 1);
	SetOption("CommissionAmount", 0.16);
	
	SetTradeDelays(1, 1, 0, 0);
	BuyPrice = Open; 
	SellPrice = Open;
}

///// Start my own coding////////////
Mainlistnum = GetOption( "FilterIncludeWatchlist" ); //ok...probably about identify and getting the number of stocks in universe
Mainlist = CategoryGetSymbols( categoryWatchlist, Mainlistnum ); //ok..probably about identify and getting list of stocks in universe

StaticVarRemove( "ValuesToSort*" );

// Fill input value (for ranking) into Static arrays



for( i = 0; ( sym = StrExtract( Mainlist, i ) ) != ""; i++ ) 
{ 
SetForeign(sym ); 
Value = C; 
RestorePriceArrays(); 
StaticVarSet( "ValuesToSort" + sym, Value ); 
} 

// Perform Ranking
StaticVarGenerateRanks("rank", "ValuesToSort", 60, 1224); // Top rank mode

	
buyConRank = StaticVarGet("rankValuesToSort" + sym ) < 60;
	
Buy =  buyConRank; //buyConMK +
Sell = 0; 




{//Position
	SetPositionSize(5, spsPercentOfEquity);
	PositionScore = ROC(C,100);
}

{//Stop
	ApplyStop(stopTypeNBar, stopModeBars, 20);//20 means 20 trading day equal to 1 month holding period.
}


The backtest show no result ! or even worse, detect the error!
error_afl
which should not be an error
because I copy this part from amibroker guideline itself at
https://www.amibroker.com/guide/afl/staticvargenerateranks.html
About the error message, it happen only to my amibroker on my PC. I have my friend check the code
on his computer, no error message like this shown, but still the backtest show no result.

Can anyone help me pinpoint what I do wrong with my code
or guide me which part probably need to be fixed or checked?

@golfpatchawat I do not get the error, but found this on the Premium Data web site describing “error 47”

"When SetForeign is used, AmiBroker needs to keep the contents of the foreign symbol referenced in SetForeign in its in-memory cache. If the number of foreign symbols accessed exceeds the cache size then error 47 will be given. You should increase the In-memory cache size in Tools -> Preferences -> Data. Ensure that the max symbols and max megabytes has enough size to cache all symbols. You can monitor the usage of the cache by clicking Tools -> Performance Monitor. "

Also what you are describing sounds like a “Long Only” rotational trading system

If so, you will need a few other lines and changes in your code. Look into using lines like

SetBacktestMode( backtestRotational ); 
PositionScore = 1000 + ROC( Close, 100 ); // making sure it is positive by adding big constant

Or you need to identify your rotation schedule with something like

m = Month(); 
PositionScore = IIf( m != Ref( m, -1 ), score, scoreNoRotate );

Go read the articles in the Official Knowledge Base and on this forum the posts that deal with Rotational trading. Some links to get you started,

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/

Good luck.

2 Likes

There are two ways to fix that: Either increase in memory cache to match the number of symbols you are using or UPGRADE to version 6.20.

1 Like

Thank you all for the response. You give me the clue to go on.
: )

I can fix the error message already.
but still I can’t make the backtest to generated result eventhough I do what mr. portfoliobuilder suggest.
So I am still open to more suggestion from you guys.

@golfpatchawat: Have you used an Exploration to see if you should get any results from the backtest?

As a newbie to coding, you might want to “chcek” your work by doing an Exploration first to see what results you get for each step. That way you know you have your logic and programming solid, before you step into the more complex world of the backtest.

1 Like

Thank Snoopy.pa30,
Exploration show no result. :frowning:

You should use normal ranking. Top rank mode prepares comma separated symbol list being called by StaticVarGetRankedSymbols

Read https://www.amibroker.com/guide/afl/staticvargenerateranks.html

So This

StaticVarGenerateRanks("rank", "ValuesToSort", 60, 1224); // Top rank mode

is wrong

Third argument should be zero in normal ranking. So,

StaticVarGenerateRanks("rank", "ValuesToSort", 0, 1224); // normal ranking

Next, this

buyConRank = StaticVarGet("rankValuesToSort" + sym ) < 60;

is wrong too. You should use Name() there. So,

buyConRank = StaticVarGet("rankValuesToSort" + Name() ) < 60;

Also ranking should be applied at start (first symbol only).
So use

if( Status( "stocknum" ) == 0 ) 
{	
    // do something
}

So “corrected” code:

{//Option
	SetOption("InitialEquity" , 1000000);
	SetOption("MaxOpenPositions", 20);
	SetOption("MinShares", 100);
	RoundLotSize = 100;
	SetOption("CommissionMode", 1);
	SetOption("CommissionAmount", 0.16);
	
	SetTradeDelays(1, 1, 0, 0);
	BuyPrice = Open; 
	SellPrice = Open;
}

///// Start my own coding////////////
Mainlistnum = GetOption( "FilterIncludeWatchlist" ); //ok...probably about identify and getting the number of stocks in universe
Mainlist = CategoryGetSymbols( categoryWatchlist, Mainlistnum ); //ok..probably about identify and getting list of stocks in universe

topn = 60;

// Rank at start (if first symbol)
if( Status( "stocknum" ) == 0 ) 
{	
	StaticVarRemove( "ValuesToSort*" );
	StaticVarRemove( "rank*" );
	StaticVarRemove( "top*" );
	
	// Fill input value (for ranking) into Static arrays
	for( i = 0; ( sym = StrExtract( Mainlist, i ) ) != ""; i++ ) 
	{ 
		SetForeign(sym ); 
		Value = C; 
		RestorePriceArrays(); 
		StaticVarSet( "ValuesToSort" + sym, Value ); 
	}
	
	// Perform Ranking
	StaticVarGenerateRanks( "rank", "ValuesToSort", 0, 1224 ); // normal ranking
	StaticVarGenerateRanks( "top", "ValuesToSort", topn, 1224); // Top rank mode
}

rank = StaticVarGet("rankValuesToSort" + Name() );

buyConRank = rank < topn;
	
Buy = buyConRank; //buyConMK +
Sell = 0; 
Short = Cover = 0;

{//Position
	SetPositionSize(5, spsPercentOfEquity);
	PositionScore = ROC(C,100);
}

{//Stop
	ApplyStop(stopTypeNBar, stopModeBars, 20);//20 means 20 trading day equal to 1 month holding period.
}


// comma separated list of top ranked (number defined in StaticVarGenerateRanks( "top", "ValuesToSort", topn, 1224);   )
topranked = StaticVarGetRankedSymbols( "top", "ValuesToSort", LastValue (DateTime()) );
// ranked values
values = StaticVarGet("ValuesToSort" + Name() ); 

// Exploration
// %s requires AmiBroker 6.20
AddRow( StrFormat( "Top ranked at last bar (%s): %s", DateTimeToStr(LastValue (DateTime())), topranked ) );
AddColumn( values, "Rank Values" );
AddColumn( rank, "Rank" );

Filter = buyConRank;
10 Likes

Thank you very much “fxshrat”.
Your reply is highly appreciated :slight_smile:
It give me more progression for sure.

I will tried the code of your version and report the result very soon.

Hi fxshrat, and every one

Your code make me closer to what I want. The Exploration show result !

Then I try backtest.
At the early period the system entry and exit stocks according to maxopenpositions setting, hold them for 20 days and exit all,
(That is 20 stocks at a time, then rebalance all 20 stocks every 20days.)
This seem to be what I want.

But then later, (as you can notice from the attached pictures)
the system seem to detour that it entry and exit the new set of stocks not exactly at every 20 stocks

I have try adjust (tick and untick) many thing at the backtest setting but still can not solve the problem.
(allow position size shrinking, allow same bar exit/entry signal, etc)

Do you found this same problem using this code?
What can be the problem ?
I really appreciated your contribution.

Thank you,
Patchawat K.

1
2
3
4
5

@golfpatchawat Sir,
As you say top 3 are look OK, in 4th one may your 20 bar stop hit then it buy new one.
and then after your ROC(c,100) condition not fit for new stock so it may not add new stock instantly.

as per my understand that's your back test show this type of result.

have a nice time.