Skip to main content

Algorithms for finding maximally diversified portfolios using the log-determinant objective.

Project description

Diversifind

PyPI version Python License

Diversifind is a Python toolkit for finding the most diversified subset of assets from a large universe.

Given a correlation matrix and a target portfolio size $k$, the library searches for the portfolio that maximizes the determinant of the correlation matrix, which corresponds to selecting the most independent return streams.

This approach is particularly useful for systematic trading and strategy portfolios, where the goal is to combine independent signals rather than minimize variance.


Quick Example

import numpy as np
from diversifind import beam

# Example: random correlation matrix
np.random.seed(0)
n_assets = 20

A = np.random.randn(n_assets, n_assets)
cov = A @ A.T
std = np.sqrt(np.diag(cov))
corr = cov / np.outer(std, std)

symbols = [f"Asset_{i}" for i in range(n_assets)]

# Find the most diversified portfolio of size 5
results = beam(corr, symbols, k=5)

print(results.pretty())

Example output:

Top diversified portfolios:

Rank      LogDet  Symbols
-------------------------
1      -0.092668  Asset_8, Asset_9, Asset_12, Asset_16, Asset_19
2      -0.132573  Asset_2, Asset_4, Asset_11, Asset_14, Asset_15
3      -0.141984  Asset_1, Asset_2, Asset_4, Asset_16, Asset_17

The Problem

Suppose you have $M$ assets and want to choose $k$ assets such that the portfolio contains the most independent return streams.

A natural objective is to maximize the determinant of the correlation matrix:

$$ \max_{S \subseteq {1..M}, |S|=k} \det(C_S) $$

where $C_S$ is the correlation matrix of the selected assets.

A larger determinant implies:

  • lower pairwise correlations
  • higher effective rank
  • more independent sources of return

However, this becomes a combinatorial search problem:

$$ \binom{M}{k} $$

which grows extremely quickly.

For example:

Universe Portfolio size Combinations
50 5 2,118,760
50 10 10,272,278,170
100 10 17,310,309,456,440

Exhaustive search quickly becomes infeasible.


Algorithms Included

Diversifind implements several search strategies.

Greedy Search

A fast heuristic:

  1. Start with the best pair
  2. Iteratively add the asset that maximizes the log-determinant increase

Very fast but not guaranteed optimal.


Beam Search (Recommended)

Beam search maintains a pool of the best partial portfolios at each step.

Instead of exploring all possibilities, it expands only the most promising candidates.

Advantages:

  • dramatically faster than brute force
  • near-optimal results in practice
  • tunable accuracy via beam_width

Example:

results = beam(corr, symbols, k=10, beam_width=5000)

Brute Force (Benchmark)

The library also includes a multiprocessing brute-force search used for benchmarking.

from diversifind import bruteforce_mp

results = bruteforce_mp(corr, symbols, k=5)

This guarantees the optimal portfolio but becomes infeasible for large universes.


Analytics Tools

Diversifind includes tools to analyze the diversification properties of portfolios.

Example:

from diversifind import analyze_portfolio

best = results.best()

analysis = analyze_portfolio(
    corr=corr,
    combo=best.combo_indices,
    symbols=symbols
)

print(analysis["effective_rank"])
print(analysis["max_abs_corr"])

Diagnostics include:

  • effective rank
  • eigenvalue spectrum
  • max / mean correlations
  • correlation pair inspection

Installation

Install from PyPI (recommended)

Once the package is published, you will be able to install it directly with:

pip install diversifind

Install from source (development)

If you want the latest development version:

git clone https://github.com/fj-hsu-cy/diversifind.git
cd diversifind
pip install -e .

The -e flag installs the package in editable mode, so local code changes immediately affect the installed package.


Example Scripts

The repository includes examples:

examples/basic_usage.py

Additional examples are available in the repository, including a real data notebook demonstrating the workflow on historical market data:

examples/real_data_example.ipynb

This notebook walks through loading price data, computing returns and correlations, running the search algorithms, and analyzing the resulting diversified portfolios.


Research Report

This project began as an exploration of how to efficiently solve the maximum determinant portfolio selection problem.

The full write-up including experiments comparing greedy, beam search, and brute-force approaches is available here:

docs/research_report.md

For a reference of the public API and analytics utilities, see:

docs/api_guide.md

Project Structure

diversifind/
    analytics.py
    results.py
    search_methods.py
    utils.py

tests/
    test_beam.py
    test_bruteforce.py
    test_greedy.py
    test_results.py
    test_utils.py
    test_analytics.py

examples/
    basic_usage.py
    real_data_example.ipynb
    data/
        sample_closes.csv

docs/
    research_report.md
    api_guide.md

Use Cases

Diversifind can be useful for:

  • systematic trading portfolios
  • alpha stream diversification
  • factor portfolio construction
  • signal selection
  • machine learning ensemble diversification

License

MIT License

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

diversifind-0.1.1.tar.gz (18.3 kB view details)

Uploaded Source

Built Distribution

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

diversifind-0.1.1-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file diversifind-0.1.1.tar.gz.

File metadata

  • Download URL: diversifind-0.1.1.tar.gz
  • Upload date:
  • Size: 18.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for diversifind-0.1.1.tar.gz
Algorithm Hash digest
SHA256 a56147c29f18af64b529ebb87ca9d92b9a8ad33053802f5ebee05b12571f053e
MD5 afe00ba131437f7b6bb84e6bb2a0eac9
BLAKE2b-256 f628f771271f16f97c4e2949ce5e1412d74573f632bbc07303e365c16f9b6819

See more details on using hashes here.

File details

Details for the file diversifind-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: diversifind-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 13.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for diversifind-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 cc1c4368e9008da0c42292778d99a08c05a0808dd11eba660d881635a5cb1cb0
MD5 dc729a639c6ce2d8f4fb4405944b6a6f
BLAKE2b-256 614af38f63c85acabc6e03ae62573a844992e857e85d2aaa2824a94ddd451039

See more details on using hashes here.

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