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

UserWarning: max_sharpe transforms the optimization problem so additional objectives may not work as expected. #526

Open nathanramoscfa opened 1 year ago

nathanramoscfa commented 1 year ago

I have been running this portfolio optimization function and getting the following warning, pypfopt\efficient_frontier\efficient_frontier.py:257: UserWarning: max_sharpe transforms the optimization problem so additional objectives may not work as expected. Why might I be seeing this warning?

    def maximum_sharpe_portfolio(
            self, posterior_expected_returns, posterior_covariance_matrix, risk_free_rate, prints=False
    ):
        """
        :description: Maximum Sharpe ratio portfolio

        :param posterior_expected_returns: Posterior expected returns
        :type posterior_expected_returns: pandas.core.series.Series, required
        :param posterior_covariance_matrix: Posterior covariance matrix
        :type posterior_covariance_matrix: pandas.core.frame.DataFrame, required
        :param risk_free_rate: Risk free rate
        :type risk_free_rate: float, required
        :param prints: Prints, default is False
        :type prints: bool, optional
        :return: Maximum Sharpe portfolio asset weights, and portfolio results
        :rtype: tuple
        """
        ef = efficient_frontier.EfficientFrontier(posterior_expected_returns, posterior_covariance_matrix, self.bounds)
        ef.add_objective(objective_functions.L2_reg, gamma=self.gamma)
        ef.add_constraint(lambda w: cp.norm(w, 1) <= self.long_weight + self.short_weight)
        ef.max_sharpe(risk_free_rate=risk_free_rate)
        volatility, weights, results, print_results = self.process_ef_output(
            ef, risk_free_rate, 'Maximum Sharpe Portfolio'
        )
        if prints:
            print('Maximum Sharpe Portfolio:')
            print('Sharpe Ratio: {}'.format(results.loc['Sharpe_Ratio']))
            self.print_results(weights, print_results)

        return weights, results
88d52bdba0366127fffca9dfa93895 commented 1 year ago

Because the original "max_sharpe" calculation is not a convex optimization, therefore we cannot solve it directly. However, we could transform the "max_sharpe" calculation to a convex optimization by a simple math, but the risk of that transformation is not zero therefore you see the error above.

Please take a look at this book http://web.math.ku.dk/~rolf/CT_FinOpt.pdf or this short paper https://people.stat.sc.edu/sshen/events/backtesting/reference/maximizing%20the%20sharpe%20ratio.pdf