Intraday portfolio backtest - Select stocks based on % change of day's open

I want to do a portfolio back test on an intraday strategy where my stock selection is based on percentage change of the day’s open from previous day’s close. My watchlist has about 150 stocks and I would like to shortlist 10 stocks based on the percentage change. Stocks from top 5 (positive change) and bottom 5 (negative change).

I apologise if this has been already answered, but I have searched the forum and could not find the solution for my problem so far.

@gandavadi you have not shown us what attempts you have made. this might help you get started, you need to compare new day Open price to previous day's Close. The opening bar prices has been discussed many times. For example,


Then some calculations like this may help (I have not tested this so be sure to debug and confirm it is correct),

dn = DateNum();
//dn = Day(); // alternate method
NewDay  = dn != Ref( dn, -1 );
FBO 	= ValueWhen( NewDay, Open ); // First Bar Open
pClose  = TimeFrameGetPrice( "Close", inDaily, -1 ); // Previous Day Close
Change 	= ( ( FBO - pClose ) / pClose ) * 100; // percent change FBO vs previous Close

The rest is up to you. Make an effort, good luck!

There is no timeframegetprice required

dn = DateNum();
newday = dn != Ref( dn, -1);
pcnt_chg = ValueWhen(newday, (O-Ref(C,-1))/Ref(C,-1)) * 100;

If you want to go long only then see StaticVarGenerateRanks function.

Finding the percentage change is the not the problem. I am able to do that. But shortlisting the stocks for the day in portfolio testing is what I am unable to do. My watchlist has about 150 stocks. When I run portfolio backtest, I want to enter trade in 10 stocks on any given day. These 10 stocks are selected based on the percentage change from the previous day's price and current day's open price. So, Day 1 and Day 2 will have completely different set of stocks that will enter trade.

I am able to rank and shortlist 10 stocks for each day in explore using the following code.....but how do I use this data in my backtest? Below is my afl code

_SECTION_BEGIN("Top 10 Pre Open");
	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( "PreOpen*" );

		for ( n = 0; ( Symbol = StrExtract( List, n ) )  != "";  n++    )
		{
			SetForeign ( symbol );
			PrevDayClose = Ref(Close, -1);
			DayOpen = Open;
			ChangePercent = IIf(DayOpen >= 50 AND DayOpen <=7000, abs(((DayOpen - PrevDayClose)/PrevDayClose) * 100), 0);
			RestorePriceArrays();
			StaticVarSet (  "PreOpenPrevDayClose"  +  symbol, PrevDayClose );
			StaticVarSet (  "PreOpenDayOpen"  +  symbol, DayOpen );
			StaticVarSet (  "PreOpenChangePercent"  +  symbol, ChangePercent );
			_TRACE( symbol );
		}

		StaticVarGenerateRanks( "PreOpenTop", "PreOpenChangePercent", 0, 1224 );
	}

	symbol = Name();
	Top = StaticVarGet ( "PreOpenTopPreOpenChangePercent" +  symbol );
	PrevDayClose = StaticVarGet ( "PreOpenPrevDayClose" +  symbol );
	DayOpen = StaticVarGet ( "PreOpenDayOpen" +  symbol );
	ChangePercent = StaticVarGet ( "PreOpenChangePercent" +  symbol );

	AddColumn ( PrevDayClose, "PrevDayClose" );
	AddColumn ( DayOpen, "DayOpen" );
	AddColumn ( ChangePercent, "ChangePercent" );
	AddColumn ( Top, "Top" );
	Filter = Top <= 10;
	SetSortColumns( 2, 6 );

_SECTION_END();

2020-08-16 02_05_54-Clipboard

1 Like

E.g. something like this

SetOption("MaxOpenPositions", 10);
SetPositionSize(1, spsPercentOfEquity);

symlist = CategoryGetSymbols(categoryWatchlist, 0); 

dn = DateNum();
newday = dn != Ref( dn, -1);

/// @link https://www.amibroker.com/guide/afl/staticvargenerateranks.html
/// modified at
/// @link https://forum.amibroker.com/t/intraday-portfolio-backtest-select-stocks-based-on-change-of-days-open/20849/6
if ( Status("stocknum") == 0 ) {
	// delete static variables - DO NOT forget the asterisk (wildcard) at the end 
	StaticVarRemove( "ValuesToSort*" ); 

	// fill input static arrays 
	for ( i = 0; ( sym = StrExtract( symlist, i ) ) != ""; i++ ) 
	{
		SetForeign( sym );
		    refC = Ref(C,-1);
		    Value = ValueWhen(newday, (O-refC)/refC);
		RestorePriceArrays();
		StaticVarSet( "ValuesToSort1" + sym, Value );
		StaticVarSet( "ValuesToSort2" + sym, -Value );
	}

	// perform ranking 
	StaticVarGenerateRanks( "rank", "ValuesToSort1", 0, 1224 ); // normal rank mode 
	StaticVarGenerateRanks( "rank", "ValuesToSort2", 0, 1224 ); // normal rank mode 
}

rank1 = StaticVarGet( "rankValuesToSort1" + Name() );// highest pos. %chg having highest rank
rank2 = StaticVarGet( "rankValuesToSort2" + Name() );// lowest neg. %chg having highest rank

Buy = Cross(C, MA(C,20)) AND (rank1 <= 5 OR rank2 <= 5);
Sell = Cross(MA(C, 20), C);
2 Likes

Thanks a ton. I will try this and come back.

Hi @fxshrat, thanks again. Your code works really well. But I am facing one issue and I hope you will help me with your suggestions. Since I am working on a intraday strategy with 1m/3m bars and this code runs on each bar. It takes a long time to complete the portfolio backtest (with 150 stocks in the watchlist). And I also intend to do optimization. I am new to "Generating Ranks" with static variables. Want to check with you whether it will give the same results if I run this code only on the first bar of the day? Can you please suggest any changes that that can improve the performance of this code?

You only have to run the ranking code "one time" via scan before backtest. Then you can do backtest/optimization/etc. by calling the ranks.

SetOption("MaxOpenPositions", 10);
SetPositionSize(1, spsPercentOfEquity);

symlist = CategoryGetSymbols(categoryWatchlist, 0); 

dn = DateNum();
newday = dn != Ref( dn, -1);

/// DON'T FORGET TO ENABLE PAD&ALIGN
if ( Status("action" ) == actionScan ) {
	/// Run SCAN on single Symbol 
	///
	/// Code source at
	/// @link https://www.amibroker.com/guide/afl/staticvargenerateranks.html
	/// modified at
	/// @link https://forum.amibroker.com/t/intraday-portfolio-backtest-select-stocks-based-on-change-of-days-open/20849/6
	Buy = 0;
	if ( Status("stocknum") == 0 ) {
		// delete static variables - DO NOT forget the asterisk (wildcard) at the end 
		StaticVarRemove( "ValuesToSort*" ); 

		// fill input static arrays 
		for ( i = 0; ( sym = StrExtract( symlist, i ) ) != ""; i++ ) 
		{
			SetForeign( sym );
				refC = Ref(C,-1);
				Value = ValueWhen(newday, (O-refC)/refC);
			RestorePriceArrays();
			StaticVarSet( "ValuesToSort1" + sym, Value );
			StaticVarSet( "ValuesToSort2" + sym, -Value );
		}

		// perform ranking 
		StaticVarGenerateRanks( "rank", "ValuesToSort1", 0, 1224 ); // normal rank mode 
		StaticVarGenerateRanks( "rank", "ValuesToSort2", 0, 1224 ); // normal rank mode 
	}
} else {
	/// RUN BACKTEST OR WHATEVER
	rank1 = StaticVarGet( "rankValuesToSort1" + Name() );// highest pos. %chg having highest rank
	rank2 = StaticVarGet( "rankValuesToSort2" + Name() );// lowest neg. %chg having highest rank

	Buy = Cross(C, MA(C,20)) AND (rank1 <= 5 OR rank2 <= 5);
	Sell = Cross(MA(C, 20), C);
}

EDIT: IT IS ARRAY(S) STORED to static var(s) in upper code!
Read here about what are arrays https://www.amibroker.com/guide/h_understandafl.html

4 Likes

Wont the static variables hold only the latest ranks? I intend to rank the stocks for each day and then want to run my backtest for a range of 10 years. Please let me know if this will work for my requirement.

Thanks.

Wow... got it. That worked. Thanks a ton. :+1: :pray: