PyOptima
Declare an optimization problem once, in configuration. Run it anywhere.
PyOptima turns an optimization problem into a configuration file — one
{template, data, solver} artifact that runs identically from Python, the CLI,
a REST API, a worker queue, and a web studio, on whichever solver you have
installed.
Thirty-three problem templates span scheduling, portfolio construction, routing, networks, packing, and facility location, with an expression-language escape hatch for anything they do not cover. Swapping solvers is a config edit, never a code change.
Features
- One artifact, five surfaces – the same config solves from Python, CLI, REST, the worker queue, and the studio UI
- 33 templates – scheduling (
rcpsp,jobshop), finance (portfolio,watchlist,rebalance,execution), routing (tsp,vrp), networks, packing, facility location, and theexprescape hatch - Solver-agnostic – HiGHS, CBC, GLPK, SciPy, OSQP out of the box; IPOPT,
Gurobi, CPLEX, SCIP when installed.
solver: {name: gurobi}is the whole migration - Validated up front – every template publishes a JSON Schema; unknown keys and impossible requests are rejected with the offending field named
- Honest results – a constraint that cannot be enforced is refused, never silently dropped, and a failed solve never returns a fabricated answer
- sklearn-style API –
PortfolioOptimizer(objective=...).solve(**data)withget_params/set_params/clone
Priority domains
| Domain | Template | Scale |
|---|---|---|
| Resource-constrained scheduling | rcpsp |
~30 activities (see docs/SCHEDULING_CUSTOM_CONSTRAINTS.md) |
| Portfolio construction | portfolio |
500 assets, sub-second for convex objectives |
| Daily watchlist formation | watchlist |
3000 names in ~0.3s |
Installation
Core Library
pip install pyoptima
With Optional Dependencies
# API server
pip install pyoptima[api]
# UI (Next.js frontend)
pip install pyoptima[ui]
# Worker (durable job queue; requires SQLAlchemy)
pip install pyoptima[worker]
# All optional dependencies
pip install pyoptima[api,ui,worker]
Solvers
PyOptima uses Pyomo, which supports multiple solvers. Run ./setup.sh to install everything (no system packages required):
- IPOPT - Nonlinear and quadratically-constrained models. Optional:
pip install 'pyoptima[ipopt]' && idaes get-extensions - HiGHS - Linear and mixed-integer programming via
highspy - CBC - Linear/integer programming (system package)
- GLPK - Linear programming (system package)
- Gurobi - Commercial solver (requires license)
Quick Start
Config-driven (recommended)
Config schema: template, data, solver. For portfolio, data includes objective, expected_returns, covariance_matrix.
1. Create a config file (portfolio.json):
{
"template": "portfolio",
"data": {
"objective": "min_volatility",
"expected_returns": [0.12, 0.11, 0.15],
"covariance_matrix": [
[0.04, 0.01, 0.02],
[0.01, 0.05, 0.01],
[0.02, 0.01, 0.06]
],
"symbols": ["AAPL", "MSFT", "GOOGL"],
"weight_bounds": [0, 1]
},
"solver": { "name": "auto" }
}
solver is optional — omit it and each template picks a backend that can
actually take the model it builds.
2. Run from Python
from pyoptima import run_from_config, PortfolioOptimizer, load_config_file
# One-shot (any template: portfolio, knapsack, lp, ...)
result = run_from_config("portfolio.json") # returns OptimizationResult
print(result.weights, result.portfolio_return, result.portfolio_volatility)
# Or: build optimizer from config, then solve (portfolio only)
opt = PortfolioOptimizer.from_config("portfolio.json")
result = opt.solve() # uses config data
3. CLI
pyoptima solve portfolio.json
Choosing an API
- Config-only:
run_from_config(path)— DAGs, FSM, reproducibility. - Code (sklearn-style):
PortfolioOptimizer(...).solve(**data)— interactive, pipelines. - Generic template:
solve("knapsack", data)orget_template("lp").solve(data)— LP, knapsack, TSP, etc. - Batch/ETL:
optimize_batch(records, objective=..., **kwargs)— pycharter, many records. - API / CLI: POST
/v1/optimizeorpyoptima solve config.json— remote or scripts.
See API Quick Reference. Integration: pystator, Airflow.
Code-only (sklearn-style)
from pyoptima import PortfolioOptimizer
opt = PortfolioOptimizer(objective="min_volatility", max_weight=0.4)
result = opt.solve(
expected_returns=[0.12, 0.11, 0.15],
covariance_matrix=[[0.04, 0.01, 0.02], [0.01, 0.05, 0.01], [0.02, 0.01, 0.06]],
symbols=["AAPL", "MSFT", "GOOGL"],
)
print(result.weights, result.portfolio_return, result.portfolio_volatility)
ETL Integration
PyOptima provides first-class integration with pycharter ETL pipelines. Use pyoptima.etl.optimize_batch directly as a pycharter custom_function:
pycharter Configuration (No Bridge Code Needed)
# transform.yaml
custom_function:
module: pyoptima.etl
function: optimize_batch
mode: batch
kwargs:
objective: min_volatility
solver: ipopt
Python Usage
from pyoptima.etl import optimize_batch
# ETL input format
data = [{
"job_id": "growth-2025-01-06",
"symbols": ["AAPL", "MSFT", "GOOGL"],
"covariance_matrix": {
"matrix": [[0.04, 0.01, 0.02], [0.01, 0.05, 0.01], [0.02, 0.01, 0.06]],
"symbols": ["AAPL", "MSFT", "GOOGL"]
},
"expected_returns": {"AAPL": 0.12, "MSFT": 0.11, "GOOGL": 0.15},
}]
# Optimize - returns ETL-ready output
results = optimize_batch(data, objective="min_volatility", solver="ipopt")
# Output format ready for loading
print(results[0]["job_id"]) # "growth-2025-01-06"
print(results[0]["weights"]) # {"AAPL": 0.25, "MSFT": 0.40, "GOOGL": 0.35}
print(results[0]["status"]) # "optimal"
print(results[0]["volatility"]) # 0.142
Key features: pycharter custom_function support, input normalization (dict/list/numpy/pandas), ETL-ready output (job_id, weights, status, metrics), all portfolio objectives, per-record error handling.
See ETL Integration Guide for complete details.
Constraints
PyOptima supports advanced portfolio constraints beyond basic weight bounds:
Available Constraints
- Sector Caps - Limit total exposure to specific sectors
- Sector Minimums - Enforce minimum exposure to sectors
- Cardinality - Maximum number of non-zero positions
- Turnover Limits - Control trading from current portfolio state
- Per-Asset Bounds - Individual min/max bounds per asset
- Minimum Position Size - Conditional holding requirements
Example
from pyoptima import PortfolioOptimizer, SectorCaps, SumToOne, WeightBounds
opt = PortfolioOptimizer(
objective="min_volatility",
constraints=[
WeightBounds(0.05, 0.40),
SumToOne(),
SectorCaps({"Technology": 0.50}, asset_sectors={"AAPL": "Technology", "MSFT": "Technology"}),
],
)
result = opt.solve(expected_returns=..., covariance_matrix=..., symbols=...)
Or pass constraints as kwargs in config data:
# In config data
constraints = dict(
# Sector constraints
sector_caps={"Technology": 0.40, "Financials": 0.30},
asset_sectors={
"AAPL": "Technology",
"MSFT": "Technology",
"JPM": "Financials"
},
# Position limits
max_positions=15,
min_position_size=0.02,
# Turnover control
max_turnover=0.30,
current_weights={"AAPL": 0.20, "MSFT": 0.30, ...},
# Per-asset bounds
per_asset_bounds={
"AAPL": (0.05, 0.30), # Min 5%, Max 30%
"MSFT": (0.10, 0.40)
}
)
See Constraints Documentation for detailed examples and best practices.
Available Methods
PyOptima provides 21 portfolio optimization methods organized by category:
Efficient Frontier Methods
min_volatility- Minimize portfolio volatilitymax_sharpe- Maximize Sharpe ratiomax_quadratic_utility- Maximize quadratic utilityefficient_risk- Maximize return for target volatilityefficient_return- Minimize volatility for target return
Black-Litterman Methods
black_litterman_max_sharpe- BL with max Sharpe objectiveblack_litterman_min_volatility- BL with min volatility objectiveblack_litterman_quadratic_utility- BL with quadratic utility objective
Conditional Value at Risk (CVaR)
min_cvar- Minimize CVaRefficient_cvar_risk- Maximize return for target CVaRefficient_cvar_return- Minimize CVaR for target return
Conditional Drawdown at Risk (CDaR)
min_cdar- Minimize CDaRefficient_cdar_risk- Maximize return for target CDaRefficient_cdar_return- Minimize CDaR for target return
Semivariance Methods
min_semivariance- Minimize downside varianceefficient_semivariance_risk- Maximize return for target semivarianceefficient_semivariance_return- Minimize semivariance for target return
Hierarchical Risk Parity (HRP)
hierarchical_min_volatility- HRP with min volatilityhierarchical_max_sharpe- HRP with max Sharpe
Critical Line Algorithm (CLA)
cla_min_volatility- CLA for min volatilitycla_max_sharpe- CLA for max Sharpe
See examples/ directory for complete, runnable examples of each method.
Data Format Support
PyOptima automatically detects and converts various data formats:
Covariance Matrix Formats
- Nested dict (ETL format):
{"matrix": [[...], [...]], "symbols": [...]} - Flat dict:
{"AAPL": {"AAPL": 0.04, "MSFT": 0.01}, ...} - NumPy array:
np.array([[0.04, 0.01], [0.01, 0.05]]) - Pandas DataFrame:
pd.DataFrame(..., index=symbols, columns=symbols)
Expected Returns Formats
- Flat dict:
{"AAPL": 0.12, "MSFT": 0.11} - Pandas Series:
pd.Series([0.12, 0.11], index=["AAPL", "MSFT"]) - NumPy array:
np.array([0.12, 0.11])
Symbols are automatically aligned between covariance matrix and expected returns.
Documentation
- ETL Integration Guide - Using PyOptima with ETL pipeline
- Constraints Documentation - Advanced constraint types and examples
- Usage Guide - Detailed usage examples
API Reference
Config-driven API
from pyoptima import run_from_config, load_config_file, OptimizationConfig
# One-shot from path or dict
result = run_from_config("portfolio.json")
config = load_config_file("portfolio.json")
# Config shape: template, data, solver (see Quick Start)
PortfolioOptimizer (sklearn-style + from_config)
from pyoptima import PortfolioOptimizer
# Build from config (portfolio only); solve uses config data
opt = PortfolioOptimizer.from_config("min_volatility.json")
result = opt.solve()
# Or solve with different data
result2 = opt.solve(expected_returns=er2, covariance_matrix=cov2, symbols=symbols)
Result Format
Results are returned as dictionaries:
{
"weights": {"AAPL": 0.30, "MSFT": 0.40, ...},
"portfolio_return": 0.12,
"portfolio_volatility": 0.15,
"sharpe_ratio": 0.80,
"status": "optimal",
"objective_value": 0.04,
"message": "Optimization successful"
}
ETL Integration
from pyoptima.etl import optimize_batch
# ETL (pycharter custom_function)
results = optimize_batch(
data=[{"expected_returns": {...}, "covariance_matrix": {...}}],
objective="min_volatility",
max_weight=0.40,
solver="ipopt"
)
Constraints via kwargs
# Pass constraints as kwargs to optimize_batch
results = optimize_batch(
data,
objective="min_volatility",
sector_caps={"Technology": 0.40},
asset_sectors={"AAPL": "Technology", ...},
max_assets=10,
max_turnover=0.30,
current_weights={"AAPL": 0.20, ...},
max_weight=0.30,
)
CLI Usage
Optimization
# Optimize from config file
pyoptima solve config.json
# With output file
pyoptima solve config.json --output results.json --pretty
# Print the generated JSON schema for a template's data payload
pyoptima schema portfolio
API Server
# Start API server
pyoptima api --host 0.0.0.0 --port 8000
# With auto-reload (development)
pyoptima api --host 0.0.0.0 --port 8000 --reload
Worker (durable queue)
When long-running optimizations should survive restarts and scale across multiple processes, use the DB-backed queue and worker:
- Set
PYOPTIMA_DATABASE_URL(e.g.sqlite:///pyoptima.dbor PostgreSQL). - Create the table (optional; the worker creates it if missing):
pyoptima db upgrade
- Start one or more workers:
pyoptima worker --concurrency 5 --poll-interval 500
- Start the API with the same
PYOPTIMA_DATABASE_URL. POST/api/v1/optimize/asyncwill enqueue jobs; workers claim and process them. Multiple workers can run; each job is claimed by exactly one worker (atomic claim). Graceful shutdown drains in-flight jobs.
UI
# Development mode
pyoptima ui dev
# Build for production
pyoptima ui build
# Serve built UI
pyoptima ui serve
pyoptima ui dev and pyoptima ui build verify the bundled Next.js
dependencies before starting. On a fresh checkout, or after package-lock.json
changes, they run npm ci from src/pyoptima/ui/package-lock.json so Tailwind,
Next.js, and PostCSS dependencies are installed consistently.
Development Setup
# Clone repository
cd pyoptima
# Install in development mode
pip install -e ".[api,ui]"
# Run tests
pytest tests/
# Run API server
pyoptima api --host 0.0.0.0 --port 8000
# Run UI (development)
pyoptima ui dev
Requirements
- Python 3.11+
- Pyomo (for optimization)
- NumPy, Pandas (for data handling)
- Pydantic >= 2.0.0 (for configuration)
- Optional: FastAPI, Uvicorn (for API server)
- Optional: Node.js/npm (for UI development/build;
pyoptima ui devandpyoptima ui buildinstall the checked-in npm dependencies automatically)
Project Structure
pyoptima/
├── pyoptima/ # Core package
│ ├── methods/ # Optimization methods (registry)
│ ├── constraints/ # Constraint system
│ ├── adapters/ # Data format adapters
│ ├── integration/ # ETL integration
│ ├── utils/ # Utilities (data formats, Pyomo helpers)
│ └── models/ # Configuration models
├── api/ # FastAPI server (optional)
├── ui/ # Next.js UI (optional)
├── examples/ # Example configurations and scripts
├── tests/ # Test suite
└── docs/ # Documentation
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Made with ❤️ for the Python optimization community
Metadata
Release files for pyoptima 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pyoptima-0.1.0.tar.gz | 1.0 MB | With provenance | Details for pyoptima-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pyoptima-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for pyoptima-0.1.0-py3-none-any.whl |
Total release size: 1.6 MB
Release files / pyoptima-0.1.0.tar.gz
| Download URL | pyoptima-0.1.0.tar.gz |
|---|---|
| Size | 1.0 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
23a89ed168b09cd21404345871c1f61d3f09e39f6cddc5dda7dde204dd4fa801
|
|
BLAKE2b-256 checksum How to use checksums |
ee1978ce6e58dcd58c1438b46a30139c34753ecaa825b491a2b55c9a754fd577
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logRelease files / pyoptima-0.1.0-py3-none-any.whl
| Download URL | pyoptima-0.1.0-py3-none-any.whl |
|---|---|
| Size | 546.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
31cc03c792949c4ee8cfe17e8f0577f0ca2573c5813f22d3d23db102a06b0c63
|
|
BLAKE2b-256 checksum How to use checksums |
7235f643422b280aa9fc6e6c787109a5374959d8f0bd310f36b60de002553e40
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logSecurity for pyoptima 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pyoptima-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.