robertmartin8 / PyPortfolioOpt

Financial portfolio optimisation in python, including classical efficient frontier, Black-Litterman, Hierarchical Risk Parity
https://pyportfolioopt.readthedocs.io/
MIT License
4.43k stars 948 forks source link

Error when calling 'efficient_return()': Creating a deepcopy of a CVXPY expression is not supported. Use .copy() instead. #491

Closed xinnny closed 1 year ago

xinnny commented 1 year ago

Hi, It seems that there is some trouble with the efficient_return function, it used to work correctly before, but now the latest version of CVXPY (1.2.2) is installed with pyportfolioopt 1.5.3, and I am getting this error message:

Creating a deepcopy of a CVXPY expression is not supported. Use .copy() instead.

Here's the code I'm using:

ef = EfficientFrontier(mu, sigma, weight_bounds=bounds, solver="ECOS")
ef.efficient_return(param_value)
AveryLevin commented 1 year ago

I am also seeing this error. It appears the update to cvxpy 1.2.2 included removing deepcopy support for their Canonical objects. This dependency upgrade also causes tests.test_efficient_frontier.test_efficient_return to fail, generating the following stacktrace:

============================= test session starts ==============================
collecting ... collected 1 item

test_efficient_frontier.py::test_efficient_return FAILED                 [100%]
tests/test_efficient_frontier.py:1056 (test_efficient_return)
def test_efficient_return():
        ef = setup_efficient_frontier()
        target_return = 0.25
>       w = ef.efficient_return(target_return)

test_efficient_frontier.py:1060: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../pypfopt/efficient_frontier/efficient_frontier.py:395: in efficient_return
    self._max_return_value = copy.deepcopy(self)._max_return()
../../../.pyenv/versions/3.9.9/lib/python3.9/copy.py:172: in deepcopy
    y = _reconstruct(x, memo, *rv)
../../../.pyenv/versions/3.9.9/lib/python3.9/copy.py:270: in _reconstruct
    state = deepcopy(state, memo)
../../../.pyenv/versions/3.9.9/lib/python3.9/copy.py:146: in deepcopy
    y = copier(x, memo)
../../../.pyenv/versions/3.9.9/lib/python3.9/copy.py:230: in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
../../../.pyenv/versions/3.9.9/lib/python3.9/copy.py:153: in deepcopy
    y = copier(memo)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Variable((20,))
memo = {6079247888: <pypfopt.efficient_frontier.efficient_frontier.EfficientFrontier object at 0x1120e5a00>, 6079298224: arra...3883542,  0.38866583,  0.22671796,  0.15617015,  0.23181536]), ['GOOG', 'AAPL', 'FB', 'BABA', 'AMZN', 'GE', ...]], ...}

    def __deepcopy__(self, memo):
        """
        Called by copy.deepcopy()
        """
>       raise NotImplementedError('Creating a deepcopy of a CVXPY expression is not supported. '
                                  'Use .copy() instead.')
E       NotImplementedError: Creating a deepcopy of a CVXPY expression is not supported. Use .copy() instead.

../env/lib/python3.9/site-packages/cvxpy/utilities/canonical.py:111: NotImplementedError

============================== 1 failed in 1.07s ===============================

As a short-term work-around, changing the cvxpy requirement to cvxpy>=1.1.10, <1.2.2 seems to side-step this issue

robertmartin8 commented 1 year ago

That’s annoying - I wonder if I just change it to copy, that’ll fix it… or will it break for people on the previous version of cvxpy

phschiele commented 1 year ago

@robertmartin8 I can raise a PR for this later.

robertmartin8 commented 1 year ago

That’d be very helpful. Planning to close a lot of tickets and merge stuff this weekend!

robertmartin8 commented 1 year ago

fixed