cvxrisk: Convex Optimization for Portfolio Risk Management
📋 Overview
cvxrisk is a Python library for portfolio risk management using convex optimization. It provides a flexible framework for implementing various risk models and solves optimization problems directly with the Clarabel conic solver — no cvxpy required.
The library is built around an abstract Model class that standardizes
the interface for different risk models, making it easy to swap between
them in your optimization problems.
🚀 Installation
# Install from PyPI
pip install cvxrisk
# For development installation
git clone https://github.com/cvxgrp/cvxrisk.git
cd cvxrisk
make install
# For experimenting with the notebooks (after cloning)
make marimo
🔧 Quick Start
cvxrisk makes it easy to formulate and solve portfolio optimization problems:
import numpy as np
from cvx.risk.sample import SampleCovariance
from cvx.risk.portfolio import minrisk_problem
from cvx.core import Variable
# Create a risk model
riskmodel = SampleCovariance(num=2)
# Update the model with data
riskmodel.update(
cov = np.array([[1.0, 0.5], [0.5, 2.0]]),
lower_assets = np.zeros(2),
upper_assets = np.ones(2)
)
# Define portfolio weights variable
weights = Variable(2)
# Create and solve the optimization problem
problem = minrisk_problem(riskmodel, weights)
problem.solve()
print(problem.status)
print(np.array2string(np.round(weights.value, 2), separator=" "))
Solved
[0.75 0.25]
📊 Features
cvxrisk provides several risk models:
Sample Covariance
The simplest risk model based on the sample covariance matrix:
from cvx.risk.sample import SampleCovariance
import numpy as np
riskmodel = SampleCovariance(num=2)
riskmodel.update(
cov=np.array([[1.0, 0.5], [0.5, 2.0]]),
lower_assets=np.zeros(2),
upper_assets=np.ones(2),
)
# Reconstruct covariance from Cholesky factor and print
cov_est = riskmodel.parameter["chol"].value.T @ riskmodel.parameter["chol"].value
print(np.array2string(cov_est, precision=1))
[[1. 0.5]
[0.5 2. ]]
Factor Risk Models
Factor models reduce dimensionality by projecting asset returns onto a smaller set of factors:
import numpy as np
from cvx.risk.factor import FactorModel
from cvx.linalg import pca
# Create some sample returns data
a = 100
m = 25
returns = np.random.randn(a, m)
# Compute principal components (deterministic using a fixed seed for reproducibility)
np.random.seed(0)
factors = pca(returns, n_components=10)
# Create and update the factor model
model = FactorModel(assets=m, k=10)
model.update(
cov=factors.cov,
exposure=factors.exposure,
idiosyncratic_risk=factors.idiosyncratic.std(axis=0, ddof=1),
lower_assets=np.zeros(m),
upper_assets=np.ones(m),
lower_factors=-0.1*np.ones(10),
upper_factors=0.1*np.ones(10),
)
# Verify the model has the correct dimensions
print(model.parameter["exposure"].value.shape)
(10, 25)
Factor risk models use the projection of the weight vector into a lower dimensional subspace, e.g. each asset is the linear combination of $k$ factors.
$$r_i = \sum_{j=1}^k f_j \beta_{ji} + \epsilon_i$$
The factor time series are $f_1, \ldots, f_k$. The loadings are the coefficients $\beta_{ji}$. The residual returns $\epsilon_i$ are assumed to be uncorrelated with the factors.
Any position $w$ in weight space projects to a position $y = \beta^T w$ in factor space. The variance for a position $w$ is the sum of the variance of the systematic returns explained by the factors and the variance of the idiosyncratic returns.
$$Var(r) = Var(\beta^T w) + Var(\epsilon w)$$
We assume the residual returns are uncorrelated and hence
$$Var(r) = y^T \Sigma_f y + \sum_i w_i^2 Var(\epsilon_i)$$
where $\Sigma_f$ is the covariance matrix of the factors and $Var(\epsilon_i)$ is the variance of the idiosyncratic returns.
Conditional Value at Risk (CVaR)
CVaR measures the expected loss in the worst-case scenarios:
import numpy as np
from cvx.risk.cvar import CVar
# Create some sample historical returns (deterministic)
np.random.seed(0)
historical_returns = np.random.randn(50, 14)
# Create and update the CVaR model
model = CVar(alpha=0.95, n=50, m=14)
model.update(
returns=historical_returns,
lower_assets=np.zeros(14),
upper_assets=np.ones(14),
)
# Verify the model parameters
print(model.alpha)
print(model.parameter["R"].value.shape)
0.95
(50, 14)
📚 Documentation
For more detailed documentation and examples, visit our documentation site.
🛠️ Development
cvxrisk uses modern Python development tools:
# Install development dependencies
make install
# Run tests
make test
# Format code
make fmt
# Start interactive notebooks
make marimo
📄 License
cvxrisk is licensed under the Apache License 2.0. See LICENSE 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
For more information, see CONTRIBUTING.md.
Metadata
Release files for cvxrisk 1.5.1
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 |
|---|---|---|---|---|
| cvxrisk-1.5.1.tar.gz | 293.6 kB | With provenance | Details for cvxrisk-1.5.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cvxrisk-1.5.1-py3-none-any.whl | Python 3 | none | any | Details for cvxrisk-1.5.1-py3-none-any.whl |
Total release size: 323.2 kB
Release files / cvxrisk-1.5.1.tar.gz
| Download URL | cvxrisk-1.5.1.tar.gz |
|---|---|
| Size | 293.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a8a85d3668445e796a9f5fdab506836fb780f6cd9c014f61bb1a22bf03ce6fe3
|
|
BLAKE2b-256 checksum How to use checksums |
3325d267edb526aa1d171262c61c5c844ea729263c19720e9dba09bcfd0223c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jun 5, 2026.
Transparency logRelease files / cvxrisk-1.5.1-py3-none-any.whl
| Download URL | cvxrisk-1.5.1-py3-none-any.whl |
|---|---|
| Size | 29.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
601a94dcfff5e66d65c8a5265e523466904f424d4069529f96429a9962d567fd
|
|
BLAKE2b-256 checksum How to use checksums |
70932728fde6f4f3d6b8e908cccf7579937cebe444a9e0eb220446f684fd78a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jun 5, 2026.
Transparency logSecurity for cvxrisk 1.5.1
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 cvxrisk-1.5.1.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 Jun 5, 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.