---
title: Calculating the internal rate of return (XIRR)
description: We'd like to calculate the internal rate of return (XIRR) for a schedule of cash flows that is not necessarily periodic.
hidden: true
---

## Use case

We'd like to calculate the internal rate of return (XIRR) for a schedule of cash
flows that is not necessarily periodic.

## Data modeling

XIRR calculation is enabled by the `XIRR` function, implemented in [SQL API][ref-sql-api]
and DAX API. It means that queries to any of these APIs can use the this function.

The `XIRR` function is also implemented in Cube Store, meaning that queries to the SQL API
or the [REST (JSON) API][ref-rest-api] that hit pre-aggregations can also use this function.
That function would need to be used in a measure that makes use of [multi-stage
calculations][ref-multi-stage-calculations].

<Info>

Consequently, queries that don't hit pre-aggregations would fail with the following error:
`function xirr(numeric, date) does not exist`.

</Info>

<Warning>

Multi-stage calculations are powered by Tesseract, the [next-generation data modeling
engine][link-tesseract]. In versions before v1.7.0, it was not enabled by default.

</Warning>

Consider the following data model:

<CodeGroup>

```yaml title="YAML"
cubes:
  - name: payments
    sql: |
      SELECT '2014-01-01'::date AS date, -10000.0 AS payment UNION ALL
      SELECT '2014-03-01'::date AS date,   2750.0 AS payment UNION ALL
      SELECT '2014-10-30'::date AS date,   4250.0 AS payment UNION ALL
      SELECT '2015-02-15'::date AS date,   3250.0 AS payment UNION ALL
      SELECT '2015-04-01'::date AS date,   2750.0 AS payment

    dimensions:
      - name: date
        sql: date
        type: time

      - name: payment
        sql: payment
        type: number

    # Everything below this line is only needed for querying
    # pre-aggregations in Cube Store
      - name: date__day
        sql: "{date.day}"
        type: time

    measures:
      - name: total_payments
        sql: payment
        type: sum

      - name: xirr
        multi_stage: true
        sql: "XIRR({total_payments}, {date__day})"
        type: number_agg
        grain:
          include:
            - date__day

    pre_aggregations:
      - name: main_xirr
        measures:
          - total_payments
        time_dimension: date
        granularity: day
```

```javascript title="JavaScript"
cube(`payments`, {
  sql: `
    SELECT '2014-01-01'::date AS date, -10000.0 AS payment UNION ALL
    SELECT '2014-03-01'::date AS date,   2750.0 AS payment UNION ALL
    SELECT '2014-10-30'::date AS date,   4250.0 AS payment UNION ALL
    SELECT '2015-02-15'::date AS date,   3250.0 AS payment UNION ALL
    SELECT '2015-04-01'::date AS date,   2750.0 AS payment
  `,

  dimensions: {
    date: {
      sql: `date`,
      type: `time`
    },

    payment: {
      sql: `payment`,
      type: `number`
    },

    // Everything below this line is only needed for querying
    // pre-aggregations in Cube Store
    date__day: {
      sql: `${CUBE.date.day}`,
      type: `time`
    }
  },

  measures: {
    total_payments: {
      sql: `payment`,
      type: `sum`
    },

    xirr: {
      multi_stage: true,
      sql: `XIRR(${CUBE.total_payments}, ${CUBE.date__day})`,
      type: `number_agg`,
      grain: {
        include: [date__day]
      }
    }
  },

  pre_aggregations: {
    main_xirr: {
      measures: [
        total_payments
      ],
      time_dimension: date,
      granularity: `day`
    }
  }
})
```

</CodeGroup>

## Query

### DAX API

You can use the `XIRR` function in DAX.

### SQL API

[Query with post-processing][ref-query-wpp] in the SQL API:

```sql
SELECT                                                                                   
  XIRR(payment, date) AS xirr
FROM (
  SELECT
    DATE_TRUNC('DAY', date) AS date,
    SUM(payment) AS payment
  FROM payments
  GROUP BY 1
) AS payments;
```

[Regular query][ref-query-regular] in the SQL API that hits a pre-aggregation in Cube Store:

```sql
SELECT MEASURE(xirr) AS xirr
FROM payments;
```

## Result

All queries above would yield the same result:

```text
        xirr        
--------------------
 0.3748585976775555
```


[ref-sql-api]: /reference/core-data-apis/sql-api/reference#custom-functions
[ref-rest-api]: /reference/core-data-apis/rest-api
[ref-query-wpp]: /reference/core-data-apis/queries#query-with-post-processing
[ref-query-regular]: /reference/core-data-apis/queries#regular-query
[link-tesseract]: https://cube.dev/blog/introducing-next-generation-data-modeling-engine
[ref-multi-stage-calculations]: /docs/data-modeling/measures#multi-stage-measures
