Skip to main content

Simple riskengine for portfolio optimization

Project description

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cvxrisk-1.5.0.tar.gz (278.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cvxrisk-1.5.0-py3-none-any.whl (29.6 kB view details)

Uploaded Python 3

File details

Details for the file cvxrisk-1.5.0.tar.gz.

File metadata

  • Download URL: cvxrisk-1.5.0.tar.gz
  • Upload date:
  • Size: 278.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cvxrisk-1.5.0.tar.gz
Algorithm Hash digest
SHA256 8639d1c091960602cca583ecee25c04db33934cf71aff8cb9ed68bdccd6d1014
MD5 432d2d73a51a4a74222e05771e167aef
BLAKE2b-256 cc62f00d559d197078b63e0f6a664af20340307c23c2262bdc87710a52dce14a

See more details on using hashes here.

Provenance

The following attestation bundles were made for cvxrisk-1.5.0.tar.gz:

Publisher: release.yml on cvxgrp/cvxrisk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cvxrisk-1.5.0-py3-none-any.whl.

File metadata

  • Download URL: cvxrisk-1.5.0-py3-none-any.whl
  • Upload date:
  • Size: 29.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cvxrisk-1.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5a5ebbbf1c31733067abc1468e35671d65852f7527f1d24e0f534ef7e92d8aba
MD5 122778d7251507af90aad0b7e68d382f
BLAKE2b-256 74a69944f433d41053b7020597f2fc1f04e7c90b056fd7787814218ad0242cec

See more details on using hashes here.

Provenance

The following attestation bundles were made for cvxrisk-1.5.0-py3-none-any.whl:

Publisher: release.yml on cvxgrp/cvxrisk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page