Type annotations

Amount = Union[int, float, Decimal]  # also supports numpy types
AmountArray = Iterable[Amount]

DPI

def dpi(amounts: AmountArray) -> float:
    ...


def dpi_2(
    contributions: AmountArray,
    distributions: AmountArray,
) -> float:
    ...

Distributed to Paid-In Capital (DPI) is a term used to measure the total capital that a private equity fund has returned thus far to its investors. It is also referred to as the realisation multiple. The DPI value is the cumulative value of all investor distributions expressed as a multiple of all the capital paid into the fund up to that time.

Formula: DPI = Cumulative Distributions / Paid-In Capital

See also:

RVPI

def rvpi(
    contributions: AmountArray,
    nav: Amount,
) -> float:
    ...

Residual Value to Paid-In Capital (RVPI) is a term used to measure the residual value (NAV) of a private equity fund as a multiple of the capital paid in by the investors. The residual value is the current fair value of all assets held by the fund and the paid-in capital by the investors is the total of all contributed capital up to that time.

Formula: Residual Value / Paid-In Capital

See also:

TVPI

def tvpi(
    amounts: AmountArray,
    nav: Amount = 0,
) -> float:
    ...


def tvpi_2(
    contributions: AmountArray,
    distributions: AmountArray,
    nav: Amount = 0,
) -> float:
    ...

Total Value to Paid-In Capital (also known as the ‘Investment Multiple’) is a measure of the performance of a private equity fund. It represents the total value of a fund relative to the amount of capital paid into the fund to date. The total value of a fund is the sum of realised value (all distributions made to investors to date) plus the unrealised value (residual value of investments) still held by the fund.

Formula: (Distributed Capital + residual Value) / Paid-In Capital

See also:

MOIC

def moic(
    amounts: AmountArray,
    nav: Amount = 0,
) -> float:
    ...


def moic_2(
    contributions: AmountArray,
    distributions: AmountArray,
    nav: Amount = 0,
) -> float:
    ...

The Multiple on Invested Capital (MOIC) measures the performance of an investment today relative to the initial investment.

Formula: (Realized investment + Unrealized investment) / Initial Investment

Unrealised value, also referred to as residual value (or NAV), is the total value of the remaining portfolio’s active investments that have not yet been liquidated.

See also:

LN-PME

def ln_pme(
    amounts: AmountArray,
    index: AmountArray,
) -> Optional[float]:
    ...


def ln_pme_2(
    contributions: AmountArray,
    distributions: AmountArray,
    index: AmountArray,
) -> Optional[float]:
    ...

The basic idea of Long Nickels method is that the cash flows of a VC fund i.e. contributions and distributions are invested in a stock market index and to generate a net asset value (NAV) at the end of each period. The last NAV is used to calculate the IRR and this IRR is the Long Nickels PME.

See also:

LN-PME NAV

def ln_pme_nav(
    amounts: AmountArray,
    index: AmountArray,
) -> float:
    ...


def ln_pme_nav_2(
    contributions: AmountArray,
    distributions: AmountArray,
    index: AmountArray,
) -> float:
    ...

Use the Long-Nickels method to re-calculate the private equity nav to match the public market equivalents (PME) for comparison. This method just re-calculates the nav. Instead of relying on the given nav, it is calculated as the future valued contributions less the future valued distributions.

This will look like (for two periods with a contribution and distribution in each):

nav = c[1] * index[-1]/index[1] + c[2] * index[-1]/index[2]
        - d[1] * index[-1]/index[1] - d[2] * index[-1]/index[2]

See also:

KS-PME Flows

def ks_pme_flows(
    amounts: AmountArray,
    index: AmountArray,
) -> List[float]:
    ...


def ks_pme_flows_2(
    contributions: AmountArray,
    distributions: AmountArray,
    index: AmountArray,
) -> Tuple[List[float], List[float]]:
    ...

Use the Kaplan-Schoar method to re-scale the private equity flows to match the public market equivalents (PME) for comparison.

This method works as follows, for each period, re-scale the amount as: amount * (index[final_period] / index[current_period]). Basically you are future-valuing the amount to the final period based on the returns of the PME.

See also:

KS-PME

def ks_pme(
    amounts: AmountArray,
    index: AmountArray,
    nav: Amount = 0,
) -> Optional[float]:
    ...


def ks_pme_2(
    contributions: AmountArray,
    distributions: AmountArray,
    index: AmountArray,
    nav: Amount = 0,
) -> Optional[float]:
    ...

KS PME represents a market adjusted equivalent of the Total Value to Paid-In-Capital (TVPI). KS PME is calculated by finding the future value of each contribution and distribution using the stock market index returns.

Formula: FV(Distributions) + NAV / FV(Contributions)

See also:

mPME

def m_pme(
    amounts: AmountArray,
    index: AmountArray,
    nav: AmountArray,
) -> float:
    ...


def m_pme_2(
    contributions: AmountArray,
    distributions: AmountArray,
    index: AmountArray,
    nav: AmountArray,
) -> float:
    ...

mPME is similar to PME+ in the sense that it uses a scaling factor. However, mPME uses different scaling factors for cash flows at different time intervals. Thus, it attempts to improve the limitations of PME+ where a single coefficient λ is used to scale all distributions.

See also:

PME+ Flows

def pme_plus_flows(
    amounts: AmountArray,
    index: AmountArray,
    nav: Amount = 0,
) -> List[float]:
    ...


def pme_plus_flows_2(
    contributions: AmountArray,
    distributions: AmountArray,
    index: AmountArray,
    nav: Amount = 0,
) -> Tuple[List[float], List[float]]:
    ...

Use the PME+ method to re-scale the private equity flows to match the public market equivalents (PME) for comparison. This method works as follows: create an equation that sets the NAV equal to the contributions future valued based on the PME returns, minus the distributions multiplied by a scalar (lambda) future valued based on the PME returns.

This will look like (for two periods with a contribution and distribution in each):

nav = c[1] * index[-1]/index[1] + c[2] * index[-1]/index[2]
        - d[1] * λ * index[-1]/index[1] - d[2] * λ * index[-1]/index[2]

Solve for lambda so that the two sides of the equation are equal. Then multiply all the distributions by lambda to re-scale them.

See also:

PME+ Lambda

def pme_plus_lambda(
    amounts: AmountArray,
    index: AmountArray,
    nav: Amount = 0,
) -> float:
    ...


def pme_plus_lambda_2(
    contributions: AmountArray,
    distributions: AmountArray,
    index: AmountArray,
    nav: Amount = 0,
) -> float:
    ...

Find λ used in PME+ method.

Formula: λ = (Scaled Distributions - NAV) / Scaled Contributions Where:

See also:

PME+

def pme_plus(
    amounts: AmountArray,
    index: AmountArray,
    nav: Amount = 0,
) -> Optional[float]:
    ...


def pme_plus_2(
    contributions: AmountArray,
    distributions: AmountArray,
    index: AmountArray,
    nav: Amount = 0,
) -> Optional[float]:
    ...

PME+ discount every distribution by a factor computed so that the NAV of the index investment matches the NAV of the fund. The PME+ returns an IRR value of discounted distributions.

See also:

Direct Alpha

def direct_alpha(
    amounts: AmountArray,
    index: AmountArray,
    nav: Amount = 0,
) -> Optional[float]:
    ...


def direct_alpha_2(
    contributions: AmountArray,
    distributions: AmountArray,
    index: AmountArray,
    nav: Amount = 0,
) -> Optional[float]:
    ...

The concept of direct alpha is closely related to the KS PME as it uses the same method to calculate an IRR which is then compared to the fund’s IRR. However, the difference between KS PME and direct alpha method is that in direct alpha the under or out performance is quantified by calculating the compounded cash flows plus the fund’s NAV.

See also: