Skip to content

sthibod/drawdown-fund-performance

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Drawdown Fund Performance Engine (public showcase)

A public-market-equivalent (PME) analysis engine for portfolios of private drawdown funds (capital calls and distributions). It ingests per-fund cash flows, computes PME and return metrics against daily benchmark series, FX-converts non-USD funds, ranks results against vintage quartiles, builds a fund-of-funds composite, and renders a branded PDF and Excel report plus a methodology guide.

Two things to know up front

  1. All data here is fictional. Every fund, manager, client, commitment, cash flow, benchmark price, and FX rate is synthetic and for demonstration only. The firm ("Hypothetical Capital Partners") and client ("Sample Client") are invented. Public ETF ticker symbols are kept (they are public), but all price and return values are a seeded random walk, not licensed market data.
  2. The proprietary calculation engine is intentionally withheld. The modules that implement the analytics are present as documented stubs that raise NotImplementedError. This repository shows the full architecture, data model, ingestion, configuration, templates, sample-data generation, and example output, but not the formulas. The engine is available under a commercial or consulting license.

Methodology (what the engine implements)

The analytics implement established techniques. This repository names them and shows their output; it does not reproduce their formulas.

  • Public-market equivalent: PME 1 (Kaplan-Schoar), PME 1b (Modified PME), PME 2 (Long-Nickels).
  • XIRR via Newton-Raphson with a bisection fallback.
  • Excess IRR / direct alpha, MIRR, NAV-to-NAV IRR (rolling horizons), and a capital-deployment factor.
  • DPI / TVPI / RVPI multiples and remaining-commitment tracking (with recallable distributions and outside-commitment expenses).
  • Vintage quartile ranking by strategy and region.
  • FX conversion of benchmark returns for non-USD funds.
  • A pooled-cash-flow fund-of-funds composite.

See examples/Methodology_Guide.pdf for a capability-level description of each metric.

Architecture

ingestion (CSV / Excel / YAML, validated with Pydantic)
   -> SQLite data model
   -> analytics engine  [proprietary, withheld]
   -> Jinja2 / WeasyPrint PDF and openpyxl Excel output
Module Role In this repo
src/loader.py, src/models.py Ingestion + validation Runs publicly
src/excel_config.py Excel <-> YAML config round-trip Runs publicly
src/benchmarks.py, src/fx.py, src/quartiles.py Benchmark / FX / quartile lookups Runs publicly
src/report.py, templates/ PDF + Excel rendering Runs publicly
src/db/ SQLite schema + repository Runs publicly
src/cli.py Command-line interface Runs publicly
scripts/generate_sample_data.py Synthetic dataset generator Runs publicly
src/engine.py PME / IRR / KPI / composite orchestration Stub (licensed)
src/xirr.py XIRR solver Stub (licensed)
src/composite.py Fund-of-funds composite Stub (licensed)
src/core/cash_flow_processor.py Sign-convention + period processing Stub (licensed)

Every computed figure (multiples, IRRs, PME, composite, quartile ranks) requires the licensed engine. Without it, the report cannot be generated; the committed examples/ show representative output produced before redaction.

Install

  • Python 3.11+
  • pip install -e . (dev extras: pip install -e ".[dev]")
  • PDF output uses WeasyPrint, which needs its system libraries (the GTK stack on Windows).

CLI entry point: drawdown-pme (or python -m src.cli).

What you can run here

pip install -e .
python scripts/generate_sample_data.py   # writes the full synthetic dataset
python -m src.cli validate               # ingestion + validation (no engine)
python -m src.cli --help                 # all commands

Ingestion, validation, config round-trip, benchmark/FX/quartile parsing, report templating, and sample-data generation all run with the public code. The analysis run (python -m src.cli run) stops at the first call into the withheld engine and raises NotImplementedError; that path requires a license.

The synthetic portfolio

generate_sample_data.py builds ten invented funds chosen to exercise every report branch, across VC / PE / Real Estate / Real Assets / FoF strategies and Europe / North America regions, with strategy-appropriate benchmarks (for example real estate vs a REIT index, energy vs an oil and gas index, growth VC vs a Nasdaq index, never one index for everything), plus a money-market series for the risk-free leg. The roster includes active, realized (fully wound down), evaluation, an archived fund, an early-vintage J-curve fund, a single-period fund, two EUR funds (FX path), and examples of recallable distributions and outside-commitment expenses. The generator is seeded, so its output is byte-reproducible.

Data layout and what is tracked

config/                 fund + quartile + benchmark-currency config   (tracked, synthetic)
data/cash_flows/        per-fund cash-flow CSVs                        (tracked, synthetic)
data/benchmark_returns/ consolidated daily benchmark return CSV        (tracked, synthetic)
data/fx_rates/          daily FX series                                (tracked, synthetic)
data/commentary/        per-fund narrative + fund-terms workbook       (tracked, synthetic)
db/sample.sqlite        synthetic sample database                      (tracked, synthetic)
examples/               pre-built sample PDFs + Excel                  (tracked)
src/                    pipeline (engine modules are stubs)
templates/              Jinja2 HTML + placeholder logo
scripts/                synthetic-data generator
tests/                  pytest suite (engine tests removed)
output/                 generated reports                              (gitignored)
db/pme.sqlite           live benchmark cache                           (gitignored)

The synthetic config/, data/, and db/sample.sqlite inputs are committed so the public capabilities run out of the box, and can be regenerated at any time with python scripts/generate_sample_data.py.

Testing

python -m pytest -q

The suite covers the parts that run without the engine: ingestion and validation, config round-trip, benchmark / FX parsing, quartile lookups, and commentary parsing. Tests that exercised the withheld engine (and encoded its expected values) have been removed.

License

MIT for the public code in this repository. See LICENSE. The proprietary analytics engine is licensed separately.

About

Public showcase of a private-fund drawdown PME analysis engine. Synthetic data; proprietary calculation engine withheld.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors