InWatchlist and MaxOpenPositions

I am having some trouble with this, hope someone can help.

I want to limit the number of positions I can hold based on what watchlist the ticker is in.

For example, I want to have 7 positions from currency market and 2 positions from bond market.

So, A maximum of 7 open positions from my watchlist 6 (which contains 9 symbols) and a maximum of 2 open positions from my watchlist 7 (which contains 5 symbols). Symbols in both watchlists are different securities.

I want to be able to do this as part of one system so I can see the benefits of combining the different watchlists.

Some code I have got so far which is not working for me:

NumContracts = 1;
PositionSize = NumContracts * MarginDeposit;
RoundLotSize = 1;

if (InWatchList(6))
{
// Strategy 1 here
buy = MA(C,50) > MA(C,100)
		AND C>Ref(HHV(C,100),-1);
sell = 0;
short =  MA(C,50) < MA(C,100)
		AND C<Ref(LLV(C,100),-1);
cover = 0;
SetOption("MaxOpenPositions",7);
Trail = Optimize("trail",5,3,7,1);
ApplyStop(stopTypeTrailing,stopModePoint, trail*ATR(20),2,True);
}
else
if (InWatchList(7))
{
// Strategy 2
buy = MA(C,50) > MA(C,100)
		AND C>Ref(HHV(C,100),-1);
sell = 0;
short = MA(C,50) < MA(C,100)
		AND C<Ref(LLV(C,100),-1);
cover = 0;
SetOption("MaxOpenPositions",2);
Trail = Optimize("trail",5,3,7,1);
ApplyStop(stopTypeTrailing,stopModePoint, trail*ATR(20),2,True);
}

Many Thanks in advance for any help

1 Like

MaxOpenPositions is per-backtest setting. It can’t be suddenly changed from symbol to symbol.
To do what you want you need to use custom backtester and check open positions list and “skip” the entry signal (by setting sig.Price = -1) if you exceed desired per-type pos count.

1 Like

If anyone is interested in this I have put together some code (with help).

This code lets you have a different number of max open positions for different watchlists. For example, you can have a limit of 5 positions for watchlist 1 and 10 positions for watchlist 2. This is so you can better manage diversification etc. You can add this code into your own system rules.

SetOption("InitialEquity",1000*1000);  
SetOption("AllowSameBarExit", 0);
SetTradeDelays(1,1,1,1);
Buy = Sell = Short = Cover = 0;
BuyPrice = ShortPrice = O;
SellPrice = CoverPrice = O;
NumContracts = Param("Number of Contracts", 1, 1, 1000);
Watchlist1 = Param("Watchlist 1 #", 1, 0, 100);
Watchlist2 = Param("Watchlist 2 #", 2, 0, 100);//Watchlist 2 #
MaxPositions1 = Param("Watchlist 1 Max Positions", 48, 1, 1000);
MaxPositions2 = Param("Watchlist 2 Max Positions", 1, 1, 1000);

SetCustomBacktestProc("");
//SetOption("MaxOpenPositions",10);

if( Status("action") == actionPortfolio ) {
	bo = GetBacktesterObject();
	bo.PreProcess();
	for ( i = 0; i < BarCount; i++ ) {
		WL1Count = WL2Count = 0;
		for( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() ) {
			wlCode = StaticVarGet("WL"+trade.Symbol);
			if (!IsNull(wlCode)) {
				if (wlCode == 1) {
					WL1Count++;
				}
				else if (wlCode == 2) {
					WL2Count++;
				}
			}
		}
				
		for ( sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) ) {
			if (sig.IsEntry()) {
			
				allowTrade = False;
				wlCode = StaticVarGet("WL"+sig.Symbol);
				if (!IsNull(wlCode)) {
					if (wlCode == 1) {
						allowTrade = WL1Count < MaxPositions1;
						if (allowTrade) {
							WL1Count++;
						}
					}
					else if (wlCode == 2) {
						allowTrade = WL2Count < MaxPositions2;
						if (allowTrade) {
							WL2Count++;
						}						
					}					
				}
				else {
					_TRACE("WLCode is null!");
				}
				
				if (!allowTrade) {
					sig.Price = -1;
				}
			}
		}
		bo.ProcessTradeSignals( i );
	}
	
	for( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() )  { 
		wlCode = StaticVarGet("WL"+trade.Symbol);
		if (!IsNull(wlCode)) {
			if (wlCode == 1) {
				trade.AddCustomMetric("In WL", Watchlist1, 0);
			}
			else if (wlCode == 2) {
				trade.AddCustomMetric("In WL", Watchlist2, 0);
			}
		}
	}	
	
	
	bo.PostProcess();
}

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

// Your System Rules Here

if (InWatchList(Watchlist1)) {
	StaticVarSet("WL"+symbol, 1);
}
else if (InWatchList(Watchlist2)) {
	StaticVarSet("WL"+symbol, 2);
}
10 Likes

I’m new to the custom backtester and would welcome any help and advice.

I’m wondering if the procedure above can be adapted to limit the number of open positions by sector? So, for example, MaxOpenPositions can be 7 but only 1 position is allowed per sector (energy, real estate etc).

Trying to get my head around the code but I get lost once the loop is initialised.

That was a long time ago.

I did piece together some code at the time but limiting the number of open positions per sector seemed to reduce the performance of strategies. I guess momentum is usually strongest in a select few sectors at a time and you limit your exposure to leading stocks by capping your holdings in them.

My code snippets are definitely not best practice but they might give someone some ideas:

// COUNT TICKERS IN WATCHLISTS CREATED FOR EACH SECTOR
// https://forum.amibroker.com/t/grouping-symbols-to-avoid-correlation/6342/7?u=prophetmines
// Count symbols belonging to WL number https://forum.amibroker.com/t/number-of-symbols-belonging-to-category/2735?source_topic_id=3022&source_topic_id=3021
// Count symbols belonging to WL name https://forum.amibroker.com/t/number-of-symbols-belonging-to-category/2735?source_topic_id=3022&source_topic_id=3021
StrategySector = "Breakouts "+SectorID(1); // "Breakouts" was the strategy name
SymbolWLnumber = CategoryFind(StrategySector,categoryWatchlist);
WLsymbols = CategoryGetSymbols(categoryWatchlist,SymbolWLnumber);
if(WLsymbols != "") 
WLcountSymbols = StrCount(WLsymbols, ",")+1;
else WLcountSymbols = 0;
MaxSector = WLcountSymbols <= 4; // Limit 4 opens positions per sector

Your BUY rules need to include your maximum sector requirements:

Buy = C > MA(C,50) AND MaxSector; // Sample BUY rule with Max sector rule.

Now if the BUY order proceeds, add the the symbol to your strategy sector watchlist for counting on the next cycle.

// IF BUY ADD TO WATCHLIST FOR CATEGORY
if( LastValue(Buy)==1 )
{
CategoryAddSymbol( "", categoryWatchlist, SymbolWLnumber);
}

And, after a SELL order, remove the symbol from the strategy sector watchlist:

// REMOVE FROM WATCHLIST FOR CATEGORY
if( LastValue(Sell)==1 )
{
CategoryRemoveSymbol( "", categoryWatchlist, SymbolWLnumber);
}

Thats about all I can find in my old files.

I do recall the watchlists needed to be cleared each time a backtest was run.

1 Like

@GustavMejlvang: You need to verify your license: License Verified badge

@ProphetMines: It does not appear that the code you posted would work in a backtest. Did you verify its operation after you wrote it?

Hi Matt - just revisting this topic as I actually never figured out how to accomplish the task.. And I am verified fwiw :smiley:

Do you, or perhaps @marwood, have any inputs to how to do it?
Thanks in advance!

Your actual question and your attempt to code it does not appear in my timeline. Could you restate it?

Hi Matt,

I just tried @ProphetMines's code and it didn't work. I assume one would need to specify a watchlist with the symbols in order for it to work?

I guess a better way to accomplish the task would be to 1) block all entry signals, 2) check if the number of sector positions is below the tolerance level set, 3) if it is then the system can proceed to include the stock as a buy candidate, 4) if it buys it then add the sectorID to a list to track the portfolio sector positions, 5) in a Sell the system should remove the sectorID from the list.

Not sure how to approach this though... :smiley:

Sorry to belabor the point, but you still haven't actually asked a question. You've stated that you tried to run some code that I already said wouldn't work in a backtest, and you found that... it didn't work! You should really review this post: How to ask a good question

If I had to guess what your goal is, I would say you're trying to prevent opening more than N trades in any particular sector. If N=1, then the high-level steps you listed should work though you're probably missing a few details. If N>1, then you will probably want to keep a static variable per sector for the current count of open trades in that sector rather than just a single list with all the sector IDs in it. Either approach will require a CBT, which means you will also need one static variable per symbol to get the stock's sector information into the CBT where you can retrieve it and then evaluate whether to allow the entry signal or disable it as @Tomasz posted in Oct 17.

1 Like