Optimizing number of positions and their weights

Hello, I've found what I believe to be a "good" system for when to be in and when to be out of the market. Now I'm curious as to what weights I should be in which instruments to have a diversified portfolio. Right now, I'm using something along the lines of the following to determine the weights of the different instruments (or whether to be in them at all):

OPTSIZE1=Optimize("SPXTR",0,0,100,10);
OPTSIZE2=Optimize("MIDTR",40,0,100,10);
OPTSIZE3=Optimize("RUTTR",0,0,100,10);
OPTSIZE4=Optimize("VBMFX",60,0,100,10);
OPTSIZE5=Optimize("GLD",0,0,100,10);
OPTSIZE6=Optimize("EFA",0,0,100,10);
Exclude=OPTSIZE1+OPTSIZE2+OPTSIZE3+OPTSIZE4+OPTSIZE5+OPTSIZE6!=100;

///and then later on in the code

if(Name()=="$SPXTR")
		{
			Buy=OpeningTrade;
			SetPositionSize(OPTSIZE1,spsPercentOfEquity);
			Sell=ClosingTrade;
		}
		
	else if(Name()=="$MIDTR")
		{
			Buy=OpeningTrade;
			SetPositionSize(OPTSIZE2,spsPercentOfEquity);
			Sell=ClosingTrade;
		}
///etc etc etc

The problem I'm having is when I go to use the CMAE optimizer to optimize other parameters in my formula the exclude statement causes several combinations to be thrown out, i.e. several tests will return no results because of the exclude statement. Is there a more efficient way to code for finding optimal weights of positions than the above? Any help would be greatly appreciated. As of now, I do a full scan of the parameters and then use the CMAE for the remainder of the formula, but I would like to be able to not break apart the formula like that. Thanks for any help or advice.
Regards,
TonyR

crickets...ok, I guess that's what I'm stuck with

I was hoping that someone else would answer this - but I guess I will since I have a little time this morning.
As quick background, I have dealt with this issue many times over many years of working with fund managers and investors. IMO - the key point about optimizing systems is that it is an art to do effectively, and it is inevitable subject to business rules. There are many places to go wrong, and more importantly, many places to improve results.
The bottom line on your code is -

You are constraining the solution space too much by having the sum of the weights == 100. This will use the optimizer ineffectively

It is also always best to define your goal. I can read between the lines of your question as 3 possible goals -

  1. Optimize the percentages so that 1 to 6 positions are held that can total <= 100. The residual will be in cash if total < 100.

  2. Optimize the percentages so that all 6 positions are held that can total <= 100. The residual will be in cash if total < 100.

  3. Optimize the percentages so that all 6 positions are held that can total == 100.

AS brief background, whenever you constrain the solution space, you can significantly constrain the search. Because of caching in the optimizers, it is not unusual to visit a reduced, smaller percentage of the possibilities with re-visits. Constraints then reduce that percentage further.

I've posted a code snippet with comments that describe this and is designed to show 3 things.

  1. If you want to hold 1-6 things, sec the minPcnt to 0. If you want 6, set the minpcnt to 5.

  2. Set the upper limit on the optimize statement to something practical. For example, most would not want to hold more than 30% gold of 50% SPY, etc. This will reduce the unwanted combo's that total > 100. These are effectively business rules.

  3. Set the Exclude = totalPCNT > 100. This will handle case #1 and #2 of the goal definitions.

It is also critical to define your objective / optimization target that weighs the result that you want. This is one place where the art comes in. You might want CAR^2/MDD, you might exclude results with CAR < minimum acceptable, etc.

Final note - problem definition #3 requires another technique for another day. You will find that setting minPcnt to 5 will yield a significant number of results with no residual cash that should suffice.

//OptimizerSetEngine( "cmae" );

//  Use SPSO to control number of solution points,
//  it initializes with same random number seed each time, 
//  so, effect of constraint can be measured accurately
//  IOW - in this example, less than 2*5000 points will be visited
OptimizerSetEngine( "spso" );
OptimizerSetOption( "Runs", 2 );
OptimizerSetOption( "MaxEval", 5000 );

//  Set minpcnt to 0 if you want 1-6 positions
//  Set minpcnt to 5 if you want only 6 positions
//  Set upper limits based on business rules
minpcnt = 5;
OPTSIZE1 = Optimize("SPY",    0,  minPcnt,  50,  5);
OPTSIZE2 = Optimize("MDY",   40,  minPcnt,  50,  5);
OPTSIZE3 = Optimize("IWM",    0,  minPcnt,  50,  5);
OPTSIZE4 = Optimize("VBMFX", 60,  minPcnt,  40,  5);
OPTSIZE5 = Optimize("GLD",    0,  minPcnt,  30,  5);
OPTSIZE6 = Optimize("EFA",    0,  minPcnt,  30,  5);

totalPcnt = OPTSIZE1 + OPTSIZE2 + OPTSIZE3 + OPTSIZE4 + OPTSIZE5 + OPTSIZE6;

Exclude = totalPCNT > 100;
7 Likes

Thank you Bruce, I truly and sincerely appreciate your solution and insight. And I'm glad you had time to look at it!
Kindest Regards,
Tony R