robertmartin8 / PyPortfolioOpt

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

Add constraint >= #421

Closed qowiews closed 2 years ago

qowiews commented 2 years ago

Hi! I am currently doing som portfolio optimisation with different ESG scores.

Are there a way to implement that the optimisation should only use companies with a score >= x? I am not wanting an aggregated ESG score for the portfolio. I only want companies that have a score >= x.

I have a large data set of stock prices and their respective ESG score from a wide range of providers.

So far have I used the example provided with my own data. But as mentioned I want to exclude the companies that does not meet the criteria of having a company specific ESG score of let say 0.75. I do not want to exclude them from the data set, only in the optimisation. That's because I want to compare the companies that end up in the portfolio across the providers. So ideally I will end up with a full list of companies only with weights in companies that meet the company specific constraint of an ESG score, and thus be able to analyse what a different providers ESG score will have off impact on the portfolio.

portfolio_min_score = 0.75 ef = EfficientFrontier(rets,risk) ef.add_constraint(lambda w: msci_esg @ w >= portfolio_min_score) ef.add_sector_constraints(sector_mapper=sector_mapper1,sector_lower=sector_lower1,sector_upper=sector_upper1) ef.efficient_return(0.12) ef.portfolio_performance(verbose=True) msci_port = pd.Series(ef.efficient_return(0.12))

thanks in advance!

phschiele commented 2 years ago

Hi @qowiews,

I'll preface this by saying that from an optimization point of view, it would probably be better to filter to companies out before setting up the problem, but nevertheless here is an idea:

You can create a numpy array with ones and zeros to indicate which companies fulfill the requirement, full example below.

import numpy as np
import cvxpy as cp

from tests.utilities_for_tests import setup_efficient_frontier

ef = setup_efficient_frontier()

# Random scores
np.random.seed(0)
esg_scores = np.random.rand(ef.n_assets)
min_score = 0.75
is_prohibited = (esg_scores < min_score).astype(float)

ef.add_constraint(lambda w: cp.multiply(w, is_prohibited) == 0 )

ef.min_volatility()
print(np.round(ef.weights,2))