Skip to main content

privateassets

Multi-factor money-weighted PME for private-asset cash flows: risk-adjusted alpha and factor exposures

You supply fund cash flows and NAVs together with benchmark levels for classical PME, or factor index levels and the matching risk-free-rate series for MATF estimation. No fund records, market data, or licensed datasets ship with the package.

Install: pip install privateassets · Import: privateassets · Status: Alpha

PyPI Python CI Docs License Downloads Monthly

Documentation: user guide · offline first success


Why privateassets

A single-benchmark PME divides fund cash flows by the return of one index. That charges the fund for one exposure and credits everything else to skill. The MATF deflator divides them by the return of a tradable multi-factor portfolio, so a distressed-credit fund is measured against the credit and equity basket it actually loaded on rather than against equities alone.

privateassets generalises Direct Alpha, KS-PME and GPME from one benchmark to a multi-factor deflator, and ships the classical measures alongside so the two can be compared on the same cash flows.

Key differentiators

Fund reporting to alpha in one call. estimate_matf_alpha takes cash flows, NAVs and factor levels and returns capital-weighted and per-vintage alpha, factor loadings, bootstrap intervals and full provenance. It returns every intermediate it computed, and writes nothing. Each stage — NAV-implied returns, unsmoothing, factor betas, deflators — is also usable on its own.

Point-in-time by construction. The covariance inside the deflator uses only returns observed by each quarter end: deleting every observation after a vintage closes leaves its alpha unchanged to 1e-12, which test_no_look_ahead_end_to_end asserts.

One panel, one reporting frequency. Nothing is forward-filled or interpolated; a panel whose vintages report at different frequencies raises, naming the offenders. Interpolating them onto a common grid is an assumption about an unobserved path, and this package does not make it for you.

The incumbents ship alongside. kn24_benchmark_deflator and kn16_gpme_deflator price the same cash flows against one market index, so the multi-factor result is reported next to what it replaces — and passing a single benchmark's reciprocal index ratio as the deflator reproduces classical Direct Alpha to root-finder tolerance, pinned by a test.

Built on the stack, not duplicating it. Unsmoothing, covariance estimation and block resampling delegate to qis; sign-constrained shrinkage betas to factorlasso through the optional [factors] extra.

When to use it — and when not

Use privateassets to estimate risk-adjusted alpha and systematic factor exposures of private-equity and private-credit funds from their cash flows and NAVs, to unsmooth appraisal-based NAV returns with bias-corrected AR(1) estimates, and to report multi-factor and classical PME side by side on the same panel.

Do not reach for it for portfolio construction — that is its sibling optimalportfolios. The reporting and factsheet layer is not in this release, no data ships with the package, and the factor loadings are in-sample by construction — one beta over the whole panel — so it is a measurement tool, not a live risk system. The caveats travel with every number in provenance.


Installation

pip install privateassets

Sign-constrained shrinkage betas need the factors extra:

pip install "privateassets[factors]"

Five-minute quickstart

The repository's deterministic example uses only core dependencies and synthetic values. From a source checkout (the examples/ directory is not included in the wheel), run:

python examples/first_success.py

Expected evidence for this release:

privateassets 0.6.2: core PME calculation succeeded

See the docs quickstart for the complete inputs and call, included from examples/first_success.py.

Core workflows

See the core workflows guide.

Unsmoothing

Appraisal NAVs are reported with a lag and anchored to the previous mark, so reported returns are a moving average of true ones. Estimate the AR(1) coefficient across a panel of funds here, then apply it with qis:

import qis
from privateassets.matf import fit_panel_ar1

result = fit_panel_ar1(demeaned_series_by_fund)
unsmoothed = qis.unsmooth_returns_glm(returns, ar_order=1, theta=result['theta_hat'])

The inversion itself is qis.unsmooth_returns_glm. This package does not carry a second copy of it.

The estimate is biased down by two separate mechanisms, and only one is correctable.

Demeaning a short AR(1) biases the coefficient by about -(1 + 3θ)/n. Pass bias_correction=BiasCorrection.BOOTSTRAP to remove it — a parametric simulation from the fitted model, which cuts mean absolute error by roughly an order of magnitude and handles heterogeneous series lengths that the analytic KENDALL formula only approximates.

What remains is measurement error. Modified Dietz returns are noisiest while capital is still being called, and error in a regressor attenuates its coefficient. On the end-to-end synthetic panel with a true θ of 0.30, the raw estimate is 0.161, correcting the demeaning bias gives 0.196, and the remaining 0.104 is measurement error that no small-sample correction reaches. It is the larger of the two.

Corrections are off by default and theta_raw is always reported.

Comparing against the single-factor incumbents

kn24_benchmark_deflator and kn16_gpme_deflator price the same cash flows against one market index, so the multi-factor result can be reported next to what it replaces. Both take the equity factor as an excess log return and add the risk-free leg back where the economics needs a total return.

from privateassets.matf import kn16_gpme_deflator, kn16_sdf_params

delta, gamma, sigma2 = kn16_sdf_params(equity_excess_log_returns, rf_quarterly)
kn_deflators = kn16_gpme_deflator(cf_dates=dates, t0=dates[0],
                                  cum_log_equity_excess=cum_log_equity,
                                  cum_log_rf=cum_log_rf, quarter_ends=quarter_ends,
                                  delta=delta, gamma=gamma)
kn_alpha = vintage_direct_alpha(cf_v, rvpi_nav, dates, kn_deflators)

Inference

Loadings are resampled in blocks through qis, with the asset and its factors resampled together:

from privateassets.matf import bootstrap_factor_betas

boot = bootstrap_factor_betas(asset_returns, factor_returns,
                              num_samples=1000, block_size=12, seed=1)
print(boot.lower, boot.upper, boot.qis_version)

share_at_zero reports how often a sign constraint binds. It is not a p-value: under a binding constraint the mass sits on the boundary, so the quantity tracks the constraint, not the evidence.

Conventions

See the conventions guide.

Dependencies

Built on qis for unsmoothing, covariance estimation and resampling, and optionally on factorlasso for sign-constrained shrinkage betas. It does not depend on optimalportfolios, which is a sibling.

Licence note. This package is MIT. factorlasso is GPL-3, so a redistributed work combining the two takes on GPL-3 obligations. Installing the factors extra is what creates that combination. The core PME and deflator paths do not import it.

Data

No data ships with this repository, and none may be added. Every input is licensed and read from a path you supply. Fund-level analysis requires user-supplied cash flows and NAVs; classical PME also needs benchmark levels, while MATF estimation needs factor levels and a matching risk-free-rate series. See DATA_README.md.

Paper workspaces

The paper index describes the local research workspaces and their six-section layout. All paper folders remain local and Git-ignored, including summaries, manuscripts, replication code, tests and data. Only the shared paper policy and index are tracked.

Tests

uv sync --locked --group test
uv run --no-sync pytest
uv sync --locked --group test --extra factors
uv run --no-sync pytest

The suite uses no network or data files. tests/synthetic_data.py draws a seeded panel carrying the defects real panels carry: irregular cash-flow dates, a J-curve, unrealised residual NAVs, and a factor panel that starts after the first fund does.

Tests needing the [factors] extra skip rather than fail, so a core install stays green.

Component development runners belong in src/privateassets/run/<subject>_local.py. Each runner exposes Locals and run_local(local=...); the run/ directory has no __init__.py and is excluded from wheels and source distributions. Automated checks remain in tests/test_*.py, and production modules never import development runners.

Enforcement tests fail the suite if package imports have filesystem side effects, documentation drifts from signatures, proprietary identifiers or competing-stack imports enter the package, release metadata diverges, or automated tests, development runners, production modules and built distributions cross their declared boundaries.

Status

0.6.2 runs from fund reporting to alpha in one call, and each stage is usable on its own. The reporting and factsheet layer is not in this release. See CHANGELOG.md.

Two caveats travel with every number and are recorded in provenance: the loadings are in-sample, and the smoothing coefficient is attenuated by measurement noise in the J-curve period even after bias correction.

Ecosystem

privateassets uses qis for time-series analytics and resampling. The optional factors extra adds factorlasso for sign-constrained shrinkage betas. optimalportfolios is a sibling for portfolio construction, not a dependency. The ArturSepp profile is the canonical ten-package catalogue.

Feedback & contributing

  • Report a reproducible bug, using synthetic or anonymised inputs and including the package version, Python/platform, and expected versus actual result.
  • Request a feature, explaining which fund-reporting convention or benchmark input is blocking adoption, the current workaround, and the smallest useful API.
  • Read CONTRIBUTING.md for the public-data boundary, development commands, numerical-change rules, and pull-request guidance.

Citation

Machine-readable metadata is available in CITATION.cff. A copyable software citation is:

@software{sepp2026privateassets,
  author = {Sepp, Artur},
  title = {privateassets: Multi-factor Money-weighted PME for Private-asset Cash Flows},
  year = {2026},
  version = {0.7.1},
  url = {https://github.com/ArturSepp/privateassets}
}

License

This project is licensed under the MIT License; see LICENSE.txt. The optional GPL-3 combination created by installing privateassets[factors] is described under Dependencies.

Metadata

Release files for privateassets 0.7.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 privateassets 0.7.1
File Size Uploaded
privateassets-0.7.1.tar.gz 83.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for privateassets 0.7.1
File Interpreter ABI Platform
privateassets-0.7.1-py3-none-any.whl Python 3 none any Details

Total release size: 127.0 kB

Release files / privateassets-0.7.1.tar.gz

Download URL privateassets-0.7.1.tar.gz
Size 83.5 kB
Tags Source
SHA-256 checksum
How to use checksums
ccec5354e73b0fcb83223e25ac4646c7b7ff8f42776c872c22687c10ee30fb09
BLAKE2b-256 checksum
How to use checksums
58466409cd70de599a6d1f7ccb595b95a6b1dda51e25fe9332d04cb5355f0a2a
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 Oct 7, 2026.

Transparency log

Release files / privateassets-0.7.1-py3-none-any.whl

Download URL privateassets-0.7.1-py3-none-any.whl
Size 43.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c5bf28609d2718cce8041f546ab6f36a62d4e37e0cae871af6e22a31106694db
BLAKE2b-256 checksum
How to use checksums
35b6d82334ea3d146e8aa7d6226d0e721eec816ff11a218d8179b0d0d049f496
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 Oct 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.7.1 This release

2 release files

0.7.0

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.1.0

1 release file

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