atoti.finance.irr()#

atoti.finance.irr(*, cash_flows, market_value, date, precision=0.001, period='total', guess=None)#

Return the Internal Rate of Return based on the underlying cash flows and market values.

Warning

This feature is experimental, its key is "finance.irr".

The IRR is the rate \(r\) that nullifies the Net Present Value:

\[NPV = \sum_{{i=0}}^{{T}} CF_i (1 + r)^{{\frac{{-t_i}}{{P}}}} = 0\]

With:

  • \(T\) the total number of days since the beginning

  • \(t_i\) the number of days since the beginning for date \(i\)

  • \(P\) the unit period in days in which the rate is expressed

  • \(CF_i\) the enhanced cashflow for date \(i\)

    • CF of the first day is the opposite of the market value for this day: \(CF_0 = - MV_0\).

    • CF of the last day is increased by the market value for this day: \(CF_T = cash\_flow_T + MV_T\).

    • Otherwise CF is the input cash flow: \(CF_i = cash\_flow_i\).

This equation is solved using Newton’s method.

Parameters:
  • cash_flows (VariableMeasureConvertible) – The measure representing the cash flows.

  • market_value (VariableMeasureConvertible) – The measure representing the market value, used to enhanced the cashflows first and last value. If the cash flows don’t need to be enhanced then 0 can be used.

  • date (Hierarchy) – The date hierarchy. It must have a single date level.

  • precision (float) – The precision of the IRR value.

  • period (Literal['annualized', 'total']) –

    Unit period in which to express the rate.

    • annualized: The measure evaluates to a rate as a percentage per 365-day period, i.e. \(P = 365\).

    • total: The measure evaluates to a rate over the entire date range, i.e. \(P = T\).

  • guess (float | None) – Estimated value of the IRR, used when the default guesses do not converge to a solution.

Return type:

MeasureDefinition

Example

>>> from datetime import date
>>> df = pd.DataFrame(
...     columns=["Date", "Market value", "Cash flow"],
...     data=[
...         (date(2023, 1, 1), 10000, 0),
...         (date(2023, 7, 1), 10500, 400),
...         (date(2024, 1, 1), 11500, 700),
...         (date(2024, 12, 31), 12000, 1300),
...         (date(2025, 7, 1), 13000, 1100),
...     ],
... )
>>> table = session.read_pandas(df, table_name="Cash flows")
>>> cube = session.create_cube(table)
>>> h, m = cube.hierarchies, cube.measures
>>> with tt.experimental({"finance.irr"}):
...     m["Annualized IRR"] = tt.finance.irr(
...         cash_flows=m["Cash flow.SUM"],
...         market_value=m["Market value.SUM"],
...         date=h["Date"],
...         precision=1e-8,
...         period="annualized",
...     )
...     m["Total IRR"] = tt.finance.irr(
...         cash_flows=m["Cash flow.SUM"],
...         market_value=m["Market value.SUM"],
...         date=h["Date"],
...         precision=1e-8,
...         period="total",
...     )
>>> m["Annualized IRR"].formatter = m["Total IRR"].formatter = "DOUBLE[0.00%]"
>>> cube.query(m["Annualized IRR"], m["Total IRR"])
  Annualized IRR Total IRR
0         24.04%    71.30%

See also

The IRR Wikipedia page.