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.

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.0},
  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.

Download files

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

Source Distribution

privateassets-0.7.0.tar.gz (80.3 kB view details)

Uploaded Source

Built Distribution

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

privateassets-0.7.0-py3-none-any.whl (43.4 kB view details)

Uploaded Python 3

File details

Details for the file privateassets-0.7.0.tar.gz.

File metadata

  • Download URL: privateassets-0.7.0.tar.gz
  • Upload date:
  • Size: 80.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for privateassets-0.7.0.tar.gz
Algorithm Hash digest
SHA256 b465c31f1216bfa938dd704f463a957c1d5f7a22d42c888fde584414bef3f1cf
MD5 ee74c2416864e4a1bcd6c2f63597ee39
BLAKE2b-256 776698d2816b2573e79d21d0110c50a63f24196f586bb837d51075119beb2ab6

See more details on using hashes here.

Provenance

The following attestation bundles were made for privateassets-0.7.0.tar.gz:

Publisher: release.yml on ArturSepp/privateassets

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

File details

Details for the file privateassets-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: privateassets-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 43.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for privateassets-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7e25615dd2720a647e4da2031b27f7f37d679e0d39a78af7f13eb764737a884d
MD5 f333c15ad8975fc6ed909fb7e112e336
BLAKE2b-256 aa31ff18764ce58711767de422f0697bdc325b8dc7933d99291c1d8874c35395

See more details on using hashes here.

Provenance

The following attestation bundles were made for privateassets-0.7.0-py3-none-any.whl:

Publisher: release.yml on ArturSepp/privateassets

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

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 files

0.6.2

2 files

0.6.1

2 files

0.1.0

1 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