# How to optimize with "if" constraints

The minimizing problem is the following : $$\underset{w}{\operatorname{argmin}} \sum_{i=1}^{n}\left[w_{i}\times (\frac{Vw}{\sigma})_{i} - b_{i}\right]^{2}$$ with $$V$$ a $$n\times n$$ matrix (covariance matrix) which depends on the vector $$w$$ of size $$n$$, $$\sigma$$ is a scalar which is equal to $$\sigma = \sqrt{w^\top Vw}$$.

For $$i=1,\ldots,n$$, the quantity $$w_{i}\times\left(\frac{Vw}{\sigma}\right)_{i}$$ has a meaning in finance and I want the vector to be as close as possible to the target vector $$b$$. That's why I am minimizing this function.

I have a function that uses scipy.minimize to solve this problem and it returns the optimal weights $$\tilde{w}=(w_{i})$$ of a portfolio of 500+ stocks. However, some of these weights are very low and I would like the weights $$w_{j}$$ that are under a certain thresold $$\rm thr$$ to be set to 0.

One way to have this would be to run my function, then manually set such weights to 0 with if conditions, and finally rescale the weights so the sum equals one. The problem with this method is that the final vector $$w$$ will not be the optimal vector $$\tilde{w}$$ anymore.

Do you know any way to minimize a function while having such conditions ?

• what is the function you are minimizing? can you write down your model? Jun 19 '20 at 12:57
• Welcome to OR.SE! Please take a look at these questions and answers, and see whether they answer your question: or.stackexchange.com/questions/76/… and or.stackexchange.com/questions/33/… Jun 19 '20 at 13:05
• Thank you @LarrySnyder610 ! I checked your links, unfortunately I don't think my problem can be solved with the answers. Jun 19 '20 at 13:10
• OK -- in that case, it would be good if you can put your problem statement into your question rather than in the comments. Hopefully someone will have a good answer for you. Thanks! Jun 19 '20 at 13:11
• The $w_i$ are semicontinuous variables or.stackexchange.com/questions/1512/… . Any MIQP solver should be able to handle this, whether handled directly as semicontinuous variables, or handled by binary variables Believe me when I say you are not the first person in the history of portfolio optimization who has done this. Jun 19 '20 at 13:17

with optimization engines like CPLEX you can model this if with logical constraints:

For instance, (x<=2) implies (y>=3) can be written in OPL, which is one of CPLEX APIs

(x<=2) => (y>=3);


you may easily add if constraints or logical constraints:

{string} Investments = ...;
float Return[Investments] = ...;
float Covariance[Investments][Investments] = ...;
float Wealth = ...;
float Rho = ...;  // Variance Penalty (increasing rho from 0.001 to 1.0
//                   produces a distribution of funds
//                   with smaller and smaller variability).

/******************************************************************************
* MODEL DECLARATIONS
******************************************************************************/

range float FloatRange = 0.0..Wealth;

dvar float  Allocation[Investments] in FloatRange;  // Investment Level

/******************************************************************************
* MODEL
******************************************************************************/

// Minimal Investment
float minimalInvestment=0.01;
// max nb assets
float nbAssetsMax=5;

dexpr float Objective =
(sum(i in Investments) Return[i]*Allocation[i])
- (Rho/2)*(sum(i,j in Investments) Covariance[i][j]*Allocation[i]*Allocation[j]);

maximize Objective;

subject to {
// sum of allocations equals amount to be invested
allocate: (sum (i in Investments) (Allocation[i])) == Wealth;

sum(i in Investments) (Allocation[i]>=minimalInvestment)<=nbAssetsMax;

forall(i in Investments) (Allocation[i]>=minimalInvestment) || (Allocation[i]==0);

}

tuple AllocationSolutionT{
string Investments;
float value;
};
{AllocationSolutionT} AllocationSolution = {<i0,Allocation[i0]> | i0 in Investments};

float TotalReturn = sum(i in Investments) Return[i]*Allocation[i];
float TotalVariance = sum(i,j in Investments) Covariance[i][j]*Allocation[i]*Allocation[j];

execute DISPLAY {
writeln("Total Expected Return: ", TotalReturn);
writeln("Total Variance       : ", TotalVariance);
}


in particular

forall(i in Investments) (Allocation[i]>=minimalInvestment) || (Allocation[i]==0);


makes sure that an allocation is either 0 or more than a minimum level

NB:

I gave an example in OPL but that 's the same in C, python, java ...