Incorrect user formula, was: Positionscore ignored again

I have read the other 2 posts on this topic but I seem to be missing something. My HD crashed and I reinstalled AB and my positionscore on larger watchlists (300+) does not seem to work properly. It seems to work properly on a Watchlist of 10 very liquid ETFs.
Here is my test code running on a watchlist of 440 tickers...

	 Maxpositions = 3; 
	 SetOption("MaxOpenPositions",Maxpositions )  ;
	 SetTradeDelays( 1,0,0,0 );

	RSI2 =RSI(2);
	RSIok = RSI2 < 20;
	
	PositionScore =  1000 +(RSI2 * -1) ; 

/*********************** ALLOCATIONS - EQUAL AMONG ALL POSITIONS *********************/
	PositionSize = -98 / Maxpositions;
	
/*********************** BUYS AND SELLS **********************************************/
	Buy  =  RSIok; //  
	Sell =  RSI2 > 80; //

	ExRem(Buy ,Sell );
	ExRem(Sell ,Buy );

/*EXPLORATION CODE*/
	if (status( "action" ) == actionExplore)
	{
	Filter = 1;
	AddColumn ( Close, "close" ); 
	AddColumn ( RSI2, "RSI2" ); 
	AddColumn ( PositionScore, "PositionScore" );
	SetSortColumns( 2, -5 );
	}

Here is the exploration showing what the model should pick...
image

Yet in the backtest it picks ITA...
image

Analysis settings...
image
image

If you can see what I am doing wrong, please advise.
Thank you for your time.

You are using trade entry delay so you need to delay by 1 one bar in Explorer too! See Ref() function.

@orionsturtle, welcome to this Forum.

Please, see this previous thread: Understanding the Relationship between Backtest, TradeDelays, and Explore

So, this is NOT related to the size of your watchlists...

From your reports it is clear that the score you see when you acutally "buy" is different from the one of the exploration (calculated on different dates). This is because its value is depending by your setting of TradeDelay, If you want to use the same "score" seen in your exploration you should shift it too.

1 Like

I thought that by pulling the exploration from the day before the trade, that would show what was the top scored for the trade date, but I'll say say that is wrong and spend more time digging through the readings. But, can you tell me what is wrong with this output?
Below I have taken all trade delays out so the trade in question now occurs on the 27th instead of the 28th and I ran the exploration for the 27th which shows once again that the model is not picking the ticker that scored the highest.

Adjusted code with no trade delays...`

	 Maxpositions = 3; //Optimize("MaxPos",9,1,15,1);  // 
	 SetOption("MaxOpenPositions",Maxpositions )  ;
	 SetTradeDelays( 0,0,0,0 );

	RSI2 =RSI(2);
	RSIok = RSI2 < 20;
	
	PositionScore =  1000 +(RSI2 * -1) ; //1000 + (RSI2 * -1) ;

/*********************** ALLOCATIONS - EQUAL AMONG ALL POSITIONS *********************/
	PositionSize = -98 / Maxpositions;
	
/*********************** BUYS AND SELLS **********************************************/
	Buy  =  RSIok; //  
	Sell =  RSI2 > 80; //

	ExRem(Buy ,Sell );
	ExRem(Sell ,Buy );

/*EXPLORATION CODE*/
	if (status( "action" ) == actionExplore)
	{
	Filter = 1;
	AddColumn ( Close, "close" ); 
	AddColumn ( RSI2, "RSI2" ); 
	AddColumn ( PositionScore, "PositionScore" );
	SetSortColumns( 2, -5 );
	}			

image
image

Explorations from the 26th and 28th to see if ITA was ever #1...
image
image
I apologize if I'm just not getting it, The exploration in the past has been a great tool for me in checking trade logic, I just can't see my error.

Your formula is incorrect. Your exploration shows ALL stocks (Filter=1) while backtest enters only those stocks that have Buy signal. Modify exploration to match the signals that you are using in backtest. Otherwise you are comparing apples to oranges. The backtester detailed log clearly shows you that you have BUY signal on ITA and it is highest ranked symbol that HAS BUY signal. Other stocks that you are looking don't have buy signal at all.

1 Like

As said by Tomasz. Your incorrect exploration code is misleading you.

Simply filter by signal and add delay in Explorer (same one as backtest) and then check Signal, BuyPrice, Indicator, PositionScore. And run exploration on trade entry date June 27th same as in backtester. (Note: 27th is the entry date but since there is delay of 1 bar the signal is on June 26th.)

Here is modified code where delay variable is added already.
I changed Close column to BuyPrice column. Also note: BuyPrice is price where you enter so it is not delayed. Only Buy signal, Indicator and PositionScore get delayed in explorer.

Now do re-run exploration...

trade_delay = 1;
Maxpositions = 3;
SetOption( "MaxOpenPositions", Maxpositions )  ;
SetTradeDelays( trade_delay, 0, 0, 0 );

RSI2 = RSI( 2 );
RSIok = RSI2 < 20;

PositionScore = 1000 + ( RSI2 * -1 ) ;

/*********************** ALLOCATIONS - EQUAL AMONG ALL POSITIONS *********************/
PositionSize = -98 / Maxpositions;

/*********************** BUYS AND SELLS **********************************************/
Buy  =  RSIok; //
Sell =  RSI2 > 80; //

Short = Cover = 0;

ExRem( Buy , Sell );
ExRem( Sell , Buy );

/*EXPLORATION CODE*/
if( status( "action" ) == actionExplore )
{
    Filter = Ref(Buy, -trade_delay);
    
    AddColumn(BuyPrice, "BuyPrice", 1.2);
    AddColumn(Ref(RSI2, -trade_delay), "RSI2", 1.4);
    AddColumn(Ref(PositionScore, -trade_delay), "PositionScore", 1.4);
    SetSortColumns( 2, -5 );
}
1 Like

Exp Filter = Buys now with NO delays...

	 Maxpositions = 3; //Optimize("MaxPos",9,1,15,1);  // 
	 SetOption("MaxOpenPositions",Maxpositions )  ;
	 SetTradeDelays( 0,0,0,0 );

	RSI2 =RSI(2);
	RSIok = RSI2 < 20;
	
	PositionScore =  1000 +(RSI2 * -1) ; //1000 + (RSI2 * -1) ;

/*********************** ALLOCATIONS - EQUAL AMONG ALL POSITIONS *********************/
	PositionSize = -98 / Maxpositions;
	
/*********************** BUYS AND SELLS **********************************************/
	Buy  =  RSIok; //  
	Sell =  RSI2 > 80; //

	ExRem(Buy ,Sell );
	ExRem(Sell ,Buy );

/*EXPLORATION CODE*/
	if (status( "action" ) == actionExplore)
	{
	Filter = Buy;
	AddColumn ( Close, "close" ); 
	AddColumn ( RSI2, "RSI2" ); 
	AddColumn ( PositionScore, "PositionScore" );
	SetSortColumns( 2, -5 );
	}	

On the 27th here are all the ETFs eligible for a buy...
image

If I start the backtest on the 27th everything is great, the engine picks the top three...
image

But, if I start the backtest at the beginning of the year...
image

I don't know if this means anything, but I see multiple commas between some of the tickers in the screenshots. I manually import the data from Bloomberg via CSV files OHLCV.
Again I apologize if I just don't see what I am doing wrong. I invite you to tweak this basic code to work, if not, I understand and I'll let this rest and program it outside AB.
Peace.

I believe part of the trouble is your using ExRem. Your buy signals are void until you have a sell signal, while your exploration does not.

@orionsturtle I have only had a cursory look at your code and this thread. I am curious about the syntax of

ExRem( Buy , Sell );
ExRem( Sell , Buy );

I have only seen it used as this,

Buy = ExRem( Buy, Sell );
Sell = ExRem( Sell, Buy ); 

I'm not an expert but are those two equivalent? I had run a couple of Explorations and did not get the same results using the different methods.

I've run a couple of quick backtests and explorations and it seem to work.

I don't know if that will help at all but give it a try.

1 Like

Yes, his ExRem lines are incorrect too and are additional reason for difference of PositionScore ranks in Exploration.

Exrem is not required in (regular) backtest since backtestRegular does remove excessive signals already.
But it has influence to none backtest environment such as exploration, chart, scan if you have state signals before.

RSIok = RSI2 < 20;
Buy  =  RSIok;   

Sell =  RSI2 > 80;

are state signals (e.g.1,1,1,0,0,0,1,1,1)

So to make it impulse signals (e.g. 1,0,0,0,0,0,1,0,0) in explorer he needs to assign ExRem to Buy and Sell variables.

Buy = ExRem( Buy, Sell );
Sell = ExRem( Sell, Buy );

See also difference between ExRem and Flip

Period						1   2	3	4   5   6   7	8
Signals						B   B	B	S   S   B   S 	S
Buy		= ExRem(Buy, Sell)	1   0	0	0   0   1   0	0
Sell	= Exrem(Sell, Buy)	0   0	0	1   0   0   1	0
Buy		= Flip(Buy, Sell)	1   1	1	0   0   1   0	0
Sell	= Flip(Sell, Buy)	0   0	0	1   1   0   1	1 

Here is additional correction

trade_delay = 0;
Maxpositions = 3;
SetOption( "MaxOpenPositions", Maxpositions );
SetTradeDelays( trade_delay, trade_delay, trade_delay, trade_delay );

RSI2 = RSI( 2 );
RSIok = RSI2 < 20;

PositionScore = 1000 + ( RSI2 * -1 ) ;

/*********************** ALLOCATIONS - EQUAL AMONG ALL POSITIONS *********************/
PositionSize = -98 / Maxpositions;

/*********************** BUYS AND SELLS **********************************************/
Buyprice = SellPrice = Close;

Buy  =  RSIok; //
Sell =  RSI2 > 80; //

Short = Cover = 0;

Buy = ExRem( Buy, Sell );
Sell = ExRem( Sell, Buy );

/*EXPLORATION CODE*/
if( status( "action" ) == actionExplore )
{
    Filter = Ref(Buy, -trade_delay);
    
    AddColumn(BuyPrice, "BuyPrice", 1.2);
    AddColumn(Ref(RSI2, -trade_delay), "RSI2", 1.4);
    AddColumn(Ref(PositionScore, -trade_delay), "PositionScore", 1.4);
    SetSortColumns( 2, -5 );
}

4 Likes

PB you found it!!! I knew it was something hidden in plain sight that I just wasn't seeing and I just needed some fresh eyes on it. Thank you for taking the time to look at the code.:blush:

@orionsturtle,

maybe I can not count correctly (maybe I was sleeping in elementary school)

but AFAICS there have been five people looking at your code.... FIVE.

And FYI @Metamega has mentioned your usage of ExRem being incorrectly too.

Besides your mistakes have not been just Exrem but other mistakes too (mentioned in same thread).

Quite strange seeing just one "thank you for taking the time" from you.

1 Like

Thank you Tomasz for your reply. You were correct that the Back tester was showing the correct buy signals. The issue I was having is that buy candidates were showing up in the exploration when I would run it for the DAY BEFORE the trade (due to the delay). I like to run the exploration check on the day the trade signaled , not when I place the trade. Hence I do not use the ref function in my explorations. You can see this in the very top post. My normal workflow of checking with an exploration on the date before trade placement was corrected once I fixed the erroneous ExRem( Buy , Sell ); code. Thank you again for your time and help.

Thank you Beppe for your reply. I did understand the trade delay. That was not the issue for the way I use the exploration to check signals. The issue was fixed once I corrected the erroneous ExRem(Buy ,Sell ); code. I appreciate you taking the time to give your input. Thanks Again.

1 Like

Thank you Metamega. You were correct. I still just didn't see it syntax wise. Thanks again for your time and help.

1 Like

Thank you fxshrat for your reply. I hope you can forgive me in offending you. It was not my intention. I was under a deadline to get this model out and I couldn't check the trades. When the answer came I took it and ran. No excuse, but it is what it is and I am very sorry. Thanks for calling me out on it. I believe I have thanked everyone now in this thread. Just to be clear, the issue I was having is that buy candidates were showing up in the exploration when I would run it for the DAY BEFORE the trade (due to the delay). I like to run the exploration check on the day the trade signaled , not when I place the trade. Hence I do not use the ref function in my explorations. I understand the delay. You can see this in the very top post. My normal workflow of checking with an exploration on the date before trade placement was corrected once I fixed the erroneous ExRem( Buy , Sell ); code. That was the only fix I needed for my particular way I work in AB. Thank you again for taking the time to reply and offer advice. Be well.

1 Like