PositionScore / Ranking for trades taken “next day at limit”

Your backtest should reflect the process you intend to use for live trading. In the example that I described previously, the assumption is that if you only have capacity to take two trades on Tuesday, then you will place AT MOST two limit orders before the market opens, no matter how many Setups you have on Monday night. The two orders that you place will correspond to the two entry signals with the highest position scores.

The sequence in which orders are filled is only relevant if you plan to place MORE THAN two orders before Tuesday's open, or if you intend to monitor the market in real time and place your orders as the limit price is approached or breached.

1 Like

Suppose I have a strategy which calculates RSI(2) values after the close and then buys the next day on Open - x% limit. Only a maximum of 5 positions can be taken any day. And all positions are closed EOD close.
I calculate the RSI(2) values on Monday night and found 7 stocks which have a value lesser than the cutoff value of 10. These stocks are then shortlisted and ranked 1-7 accordingly.
I then send it to CBT which takes the top 5 ranks(stocks 1-5) and takes position in it.

In real world, suppose stock 7 breached the limit price earliest at 10AM followed by stock 6 at 10:15AM. On a real trading day, my positions are in the following stocks: stock-7, stock-6, stock-1, stock-2, stock-3. Stock 4 & 5 also breach the limit price but since I am already maxed out, I have to pass on them.

However in the case of CBT , it would have taken positions in stock1-5. This is a kind of lookahead bias which only takes position in the best ranked stocks. I don't see a way where we can simulate real world trading scenario UNLESS and UNTIL we have data of lower granularlity(1min/tick-by-tick).
In that case, we can take signals on EOD data but run the strategy on lower timeframe data to simulate real exchange.

As I said, your AFL needs to reflect your trading rules. If you only placed orders for stocks 1-5, then you would not have an issue running a backtest with EOD data. If you are going to place orders for stocks 1-7 as described in your most recent post, then you are correct that you will need intraday data to determine the sequence in which your orders actually get filled.

1 Like

On the Amibroker Knowledge Base the bottom code on this page:
https://www.amibroker.com/kb/2014/11/26/handling-limit-orders-in-the-backtester/
It deals with limit orders for multiple positions. In this example, all of the stocks in the watchlist are ranked using the RSI and only the top 3 can be candidates for a limit order. Then the possible setups are calculated by a cross of the close over the 100 bar moving average and if none of those setups are ranked in the top 3, there won't be any limit orders. Shouldn't it be that you find all the setups first, and then only rank the setups for possible limit orders instead of ranking all the stocks? Would a proper CBT for limit orders would only rank the setups for limit orders and not rank all the stocks?

Sorry if I ask a lot of questions about limit orders with multiple positions, it can be somewhat complicated. However I believe that limit orders can give you an advantage for a lot of trading systems. I think it's important for us to understand how they work with Amibroker and that it warrants discussion.

One challenge with using limit entries is that you need to consider how many orders you can place in live trading. Let's assume you have a 10k account with 5 equally sized positions of 2k each, and no margin available. If you have four open positions coming into today, then in live trading you would only be able to place one order before running out of buying power.

In AmiBroker terms, the number of "orders" you place corresponds to how far down the ranked list of Setups you go. In the example above, you should only consider the Setup with the highest position score. If you have 2 open positions today (and therefore 3 slots available), then you should only consider the Setups with the 3 highest position scores. It should be noted that when testing a portfolio, there is no way to know how many slots are available in the Phase 1 code. This can only be known in Phase 2 (CBT).

The example that you referenced is not attempting to solve the challenge described above. Instead, it is simply reducing the number of potential setups to three, and as such there is nothing wrong with the code. You could proceed as you described by only ranking the valid setups instead of ranking all stocks, but that just changes the logic of the strategy slightly without solving the "number of orders" problem.

6 Likes

this post has helped me a lot. I started learning custom backtest to solve this problem and had some success. just thought i would post this here for sharing as a starting point. this replaces the ranking code in the original post. its way faster than staticvargenerateranks. it ranks, checks limit order fill, and only looks at the first (max position - # of open position) rankings.

SetBacktestMode(backtestRegularRaw);
SetOption("UseCustomBacktestProc", True );

if( Status("action")== actionPortfolio ) 
{ 
    // retrieve the interface to portfolio backtester 
     bo = GetBacktesterObject(); 
     bo.PreProcess();    //  Do pre-processing (always required)

	for (i = 0; i < BarCount; i++) // Loop through all bars
	{
		PosQty = bo.GetOpenPosQty();
		_TRACE("Day ------ " + i);
		_TRACE("Open Position: " + PosQty);
		count=0;
		for(sig=bo.Getfirstsignal(i) ; sig ; sig=bo.GetNextSignal(i))
		{
			LowArray=Foreign(sig.Symbol,"Low"); //grab the low to check limit order fill
			if(sig.IsEntry())
			{
				if(count>9-PosQty or LowArray[i]>sig.price) 
					sig.Price=-1;
			}
				
			count++;
		}
		
		bo.ProcessTradeSignals( i );
	}

    bo.PostProcess();    //  Do post-processing (always required)
}
6 Likes

Also make sure to turn off priceboundchecking so the buyprice will actually be sent to CBT un-altered for checking.

2 Likes