Portfolio constraint feasibility checker with LP/MIP/CVaR support
Project description
portfolio-optimizer
Portfolio constraint feasibility checker with formal verification. Determines whether a set of portfolio constraints (cardinality, sector limits, position bounds, budget, CVaR risk) can be simultaneously satisfied — and if not, identifies exactly which constraints conflict and suggests fixes.
1,143 tests. Exhaustive brute-force verification, property-based fuzzing, adversarial edge cases, and formal solution certification on every result.
Install
pip install portfolio-optimizer
Quick Start
from portfolio_optimizer import PortfolioChecker
pc = PortfolioChecker(n_assets=500)
# Cardinality: select 15-20 assets
pc.add_cardinality(min_assets=15, max_assets=20)
# Sector weight limits
pc.add_weight_limit("tech", assets=[0,1,2,3,4], max_pct=0.30)
pc.add_weight_limit("energy", assets=[5,6,7], min_pct=0.10, max_pct=0.25)
# Position bounds and budget
pc.add_position_bounds(min_w=0.02, max_w=0.10)
pc.add_budget(total=1.0)
# Mutual exclusions
pc.add_exclusion(asset_a=0, asset_b=1) # Can't hold both
# CVaR risk constraint
import numpy as np
returns = np.random.normal(0.01, 0.05, (200, 500))
pc.add_cvar_limit(confidence=0.95, max_cvar=0.15, returns=returns)
# Check feasibility
result = pc.check_feasibility()
print(result.feasible) # True/False
print(result.method) # "quick", "sat", "lp", "mip", "cvar"
print(result.infeasible_constraints) # Which constraints conflict
print(result.suggestion) # How to fix it
Architecture: 5-Step Pipeline
Each step is more expensive than the previous. The pipeline stops at the first conclusive result.
| Step | Method | What it checks | When used |
|---|---|---|---|
| 1 | Quick checks | Arithmetic impossibilities | Always |
| 2 | SAT (torc-sat) | Binary constraints (cardinality, exclusions, sectors) | Binary only |
| 3 | LP (scipy.linprog/HiGHS) | Weight constraints (sectors, budget, bounds) | Weight only |
| 4 | MIP (scipy.milp/HiGHS) | Mixed binary + weight constraints | Mixed |
| 5 | CVaR (Rockafellar-Uryasev LP) | Risk constraints | When CVaR present |
Diagnostics: IIS Extraction
When constraints are infeasible, portfolio-optimizer identifies the Irreducible Infeasible Subsystem (IIS) — the minimal set of constraints that cannot be simultaneously satisfied. Analogous to MUS (Minimal Unsatisfiable Subset) in SAT solving.
result = pc.check_feasibility()
if not result.feasible:
print(result.infeasible_constraints)
# ['position_bounds(max_w=0.1)', 'budget(total=1.0)']
# → max 10 assets * 0.1 = 1.0, but cardinality says min 15
print(result.suggestion)
# "Relax position_bounds(max_w) or budget(total)"
Verification (1,143 Tests)
| Suite | Tests | What it verifies |
|---|---|---|
| Exhaustive | 87 | Brute-force all C(n,k) subsets for n<=7, compare with MIP |
| Fuzzing | 246 | Random constraints, verify LP>=MIP monotonicity, solution certification |
| Adversarial | 35 | Near-boundary, degenerate pivots, 1000 assets, overlapping sectors |
| Certification | 341 | Every feasible solution satisfies ALL constraints; every infeasible is brute-force confirmed |
| Parametrized | 320 | Systematic parameter sweeps across all constraint types |
| Unit | 114 | Individual module tests |
pytest tests/ -v # All 1,143 tests in ~7 seconds
Constraint Types
- CardinalityConstraint: min/max number of selected assets
- ExclusionConstraint: two assets cannot both be selected
- SectorMinConstraint: minimum assets from a sector
- DiversificationConstraint: at least 1 asset from each sector
- WeightLimitConstraint: sector weight min/max percentage
- BudgetConstraint: total weight must equal target (default 1.0)
- PositionBoundsConstraint: per-asset weight min/max when selected
- CVaRConstraint: Conditional Value at Risk limit (Rockafellar-Uryasev 2000)
Dependencies
numpyscipy >= 1.11.0(HiGHS MIP solver)torc-sat >= 0.1.1(topological SAT preprocessor)
License & Patent
All Rights Reserved. Carmen Esteban / IAFISCAL & PARTNERS.
This software implements methods protected by patent applications before the Spanish Patent and Trademark Office (OEPM). The topological SAT preprocessing method used in this package (via torc-sat) is the subject of a pending patent application.
- Free for academic research and education.
- Commercial use requires a written license from the author.
- Contact: caresment@gmail.com
Any use of this software or its methods in commercial products, SaaS platforms, or for-profit services without a license agreement constitutes patent infringement under Spanish and EU law.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file torc_portfolio-0.1.0.tar.gz.
File metadata
- Download URL: torc_portfolio-0.1.0.tar.gz
- Upload date:
- Size: 45.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23d466ebbfe6f5614d06f369bb69ad36551203fb4a9210f3639aafaa70aaf6f3
|
|
| MD5 |
9e7b50e86a5112be5f9a1364010618d4
|
|
| BLAKE2b-256 |
df684d4a443988c222d50ebb75944b94ac1b5f21f8ce738d2a90128aebeb4b8e
|
File details
Details for the file torc_portfolio-0.1.0-py3-none-any.whl.
File metadata
- Download URL: torc_portfolio-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e08320023f96769c2db3631a4635f3b1481392fd18ff9615046cefd9b41f393e
|
|
| MD5 |
a16e2428170d1609c96065c66f6871ae
|
|
| BLAKE2b-256 |
cb56097f5f449f0d564dd3de82ac78bedab5c1af9dd5153b07edfc0cd43804d8
|