Search code examples
pyomononlinear-optimizationmixed-integer-programming

How to solve "non-fixed bound or weight" using PYOMO and couenne for a Portfolio Optimization problem


I am trying to implement the mean-variance cardinality constrained portfolio optimization (MVCCPO) problem in PYOMO to then solve with the MINLP solver couenne.

The MVCCPO is based on the traditional portfolio optimisation problem (markowitz's original mean-variance model) but with the addition of two more constraints : 1) the cardinality constraint and 2) the floor and ceiling constraints. See http://www.jhumanities.net/article_86973_2cc8b3b4209b171bd61268833c04ee07.pdf for an example of it's use; It is formulated mathematically on page 2(i would write it in here but unfortunately but due to limitations imposed by stackoverflow i am unable)

When i try to run the solve the MVCCPO problem i am met with the error "non-fixed bound or weight". This problem is coming from the following constraint :

l_{i}\delta_{i}<=w_{i}<=u_{i}\delta_{i}

where l_{i} and u_{i} is the lower bound and upper bound to invest in stock i: the floor and ceiling constraint. \delta_{i} is the cardinality constraint and is 0 when stock is to not be invested in and 1 if it is to be invested in. w_{i} is the amount of the portfolio invested in stock i.

Here is how the constraint is currently implemented in PYOMO

    def floor_ceiling_and_cardinality_constraint(self, m, i):
    return inequality((m.delta[i]*self.l[i]), m.x[i], (m.delta[i] * self.u[i]))

How does one implement such a constraint ? I know the constraint mentioned is the one at fault as by removing the cardinality portion of the constraint (\delta_[i]) it works perfectly. I would be forever in debt to the kind soul who can help me at all.


Solution

  • A sandwich constraint like

    l(i)*δ(i) ≤ x(i) ≤ u(i)*δ(i)
    

    should in general be implemented as two constraints:

    l(i)*δ(i) ≤ x(i) 
    x(i) ≤ u(i)*δ(i)
    

    These are now straightforward linear constraints.

    Note: Pyomo supports constraints of the form

    l(i) ≤ expression ≤ u(i)
    

    directly (see link). But in your case you have variables on both sides.