robertmartin8 / PyPortfolioOpt

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

fixed key error when adding multiple sector constraints #531

Closed andyherfer closed 1 year ago

andyherfer commented 1 year ago

I wanted to add multiple sector constraints, for example:

mapper1 = {
     "AAPL": "ESG",
     "PG": "NOTESG"
     . 
     .
     .
   }
lower1 = {
    "ESG": 0.1
}
upper1 = {
    "NOTESG": 0.1
}

ef.add_sector_constraint(mapper1, lower1, upper1)

mapper2 = {
     "AAPL": "TECH",
     "PG": "DEFENSIVE"
     . 
     .
     .
   }
lower2 = {
    "DEFENSIVE": 0.1
}
upper2 = {
    "TECH": 0.2
}

ef.add_sector_constraint(mapper2, lower2, upper2)

Where the main problem was that some assets belonged to more than one sector, and wanted to mix different sector classifications, such as debt can be subdivided between corporate and governmental.

When adding the second constraint, it looks for all registered tickers, where some may not be present in the second mapper, thus by changed the [] dict indexing notation for a .get notation, a None is returned, and therefore not added to the optimization constraint sum in:

        for sector in sector_upper:
            is_sector = [sector_mapper.get(t) == sector for t in self.tickers]
            self.add_constraint(lambda w: cp.sum(w[is_sector]) <= sector_upper[sector])
        for sector in sector_lower:
            is_sector = [sector_mapper.get(t) == sector for t in self.tickers]
            self.add_constraint(lambda w: cp.sum(w[is_sector]) >= sector_lower[sector])
codecov-commenter commented 1 year ago

Codecov Report

Patch coverage: 100.00% and project coverage change: -0.12 :warning:

Comparison is base (6f699fd) 99.42% compared to head (3feb53a) 99.30%.

:mega: This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more

Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #531 +/- ## ========================================== - Coverage 99.42% 99.30% -0.12% ========================================== Files 33 33 Lines 5072 5072 ========================================== - Hits 5043 5037 -6 - Misses 29 35 +6 ``` | [Impacted Files](https://codecov.io/gh/robertmartin8/PyPortfolioOpt/pull/531?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | | |---|---|---| | [pypfopt/base\_optimizer.py](https://codecov.io/gh/robertmartin8/PyPortfolioOpt/pull/531?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cHlwZm9wdC9iYXNlX29wdGltaXplci5weQ==) | `97.54% <100.00%> (ø)` | | ... and [1 file with indirect coverage changes](https://codecov.io/gh/robertmartin8/PyPortfolioOpt/pull/531/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Do you have feedback about the report comment? Let us know in this issue.

88d52bdba0366127fffca9dfa93895 commented 1 year ago

Thanks you for the fix.