Skip to content

roi: add period money-weighted return and gross-capital multiples (DPI/RVPI/TVPI) #2750

Description

@acinader

The following are metrics I found on a statement that I thought you might want to see.


Native outputs for a nonannualized money-weighted period return and gross-contributed-capital multiples to investment performance reporting, preferably roi. This is a missing-output request, not a claim that the existing annualized IRR is wrong.

Reproduction

Tested with hledger 1.99-g74d506cdc-20260927, mac-aarch64. The local build's Roi.hs and Holdings.hs are byte-identical to upstream main at ccaeb0d3. All dates, accounts and amounts below are fictional.

Save as private-fund.journal:

commodity $0.00

2022-01-01 Contribution
    assets:fund       $100.00
    assets:cash      $-100.00

2022-12-31 Valuation
    assets:fund       $100.00
    equity:valuation $-100.00

2023-01-01 Contribution
    assets:fund       $100.00
    assets:cash      $-100.00

2023-07-01 Distribution
    assets:cash        $60.00
    assets:fund       $-60.00

2023-12-31 Valuation
    assets:fund       $120.00
    equity:valuation $-120.00
hledger -f private-fund.journal check
hledger -f private-fund.journal roi \
  --investment assets:fund --pnl equity:valuation \
  --begin 2022-01-01 --end 2024-01-01 --cashflow --color=no --pager=no

The check passes. The report row is:

Begin End Value (begin) Cashflow Value (end) PnL IRR TWR/period TWR/year
2022-01-01 2023-12-31 0 $140.00 $360.00 $220.00 65.05% 188.13% 69.81%

--cashflow shows IRR cash flows of -$100 on 2022-01-01, -$100 on 2023-01-01, +$60 on 2023-07-01, and terminal +$360 on 2024-01-01.

Requested outputs and draft documentation

  • IRR/period: the nonannualized money-weighted return over the exact span used by IRR. With annual decimal rate r, use (1+r)^(days/365.25)-1, using the unrounded solver result and the same opening/closing dates as IRR. Keep the annualized IRR alongside it. For the fixture, annual IRR is approximately 65.05171978% and period MWR is 172.23389829%, or 172.23% displayed. An independent fixture-only root check reproduces the displayed annual IRR. This is neither the 188.13% period TWR nor the 110% simple gain/contributions ratio.
  • Contributed / Distributed: separately show gross external cash contributions C and cash distributions D for the stated coverage. For this complete since-inception example, C=$200, D=$60; the existing $140 Cashflow column is their net.
  • DPI (distributed to paid-in): D/C = 0.30x.
  • RVPI (residual value to paid-in): ending NAV V/C = 1.80x.
  • TVPI (total value to paid-in): (D+V)/C = 2.10x.

A possible optional output extension for this row:

IRR/year IRR/period Contributed Distributed NAV DPI RVPI TVPI
65.05% 172.23% $200.00 $60.00 $360.00 0.30x 1.80x 2.10x

Boundaries and classification

  • Preserve roi's existing [begin,end) convention: the printed End is end-1, while the IRR terminal NAV is currently placed at exclusive end. Here that makes the exponent 730/365.25. This request does not propose changing that date or day-count convention.
  • Multiples need complete, consistently scoped contribution/distribution history and an ending NAV for the same investment and cutoff. If --begin truncates history, do not silently present interval cash flows divided into cumulative NAV as since-inception DPI/RVPI/TVPI. A since-inception mode could retain the full cash history and label its coverage, or incomplete multiples could be unavailable. A synthetic opening NAV used for period IRR is not an actual contribution.
  • Contributions are gross: cash distributions, including returned capital, do not reduce C. Keep an explicitly recorded contribution and distribution separate even on the same date; netting first loses information. If only a net settlement was recorded, the gross components are missing evidence and should not be inferred.
  • Count external investor cash flows, excluding internal transfers, valuation/P&L postings and uncalled commitments. Cash-flow classification must be explicit enough to avoid treating every non-investment posting as paid-in capital; fees and reinvestments need a documented scope. This initial request is for single-currency, cash-distribution examples with complete history, not an implicit policy for in-kind or recallable distributions.
  • For C=0 or unknown/incomplete contributions, show unavailable rather than a misleading multiple.

Why existing fields do not supply these outputs

Roi.hs emits annual IRR, TWR/period and TWR/year, and nets the cashflow display. Its IRR implementation already has the needed span and annual rate.

holdings has annual XIRR, remaining cost basis and gains, but no contributed-capital multiples. Remaining lot cost is not gross contributed capital. For a second fictional control, save as partial-disposal.journal:

commodity EXAMPLE  ; lots:

2020-01-01 Purchase
    assets:example       20 EXAMPLE @ $10
    assets:cash

2021-01-01 Partial disposal
    assets:example      -10 EXAMPLE {} @ $6
    assets:cash

P 2021-12-31 EXAMPLE $18
hledger -f partial-disposal.journal check
hledger -f partial-disposal.journal holdings -e 2022-01-01 -O csv

This produces Cost=$100, Value=$180, RGain=$-40, XIRR=11.0%. Gross contributions remain $200 and cash proceeds are $60, so the corresponding cash multiples are 0.30x / 0.90x / 1.20x. Neither the $100 remaining basis nor the -$40 realized gain substitutes for those gross cash-flow totals.

Related work checked: #2068/#2069 added period TWR; #2624 changed TWR to linked IRR across valuation windows; #2683 added holdings/XIRR. This request is for a separately labeled whole-period MWR and contributed-capital multiples. I found no existing issue requesting these exact outputs.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-WISHSome kind of improvement request or proposal.investingRelated to investments, lots, capital gains, etc.roi

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions