Skip to main content

cvxrisk: Convex Optimization for Portfolio Risk Management

PyPI version Apache 2.0 License Downloads Renovate enabled Coverage

📋 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.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. 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)

Source distribution for cvxrisk 1.5.1
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)

Table of built distributions (wheels) for cvxrisk 1.5.1
File Interpreter ABI Platform Actions
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 log

Release 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 log

Security 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.

Select from 2 files

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 log

A 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.

Release history Release notifications | RSS feed

This release

1.5.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page