---
title: "Aggregating performance returns for a portfolio"
slug: "aggregating-performance-returns-for-a-portfolio"
updated: 2025-07-31T15:34:36Z
published: 2025-07-31T15:34:36Z
canonical: "support.lusid.com/aggregating-performance-returns-for-a-portfolio"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://support.lusid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Aggregating performance returns for a portfolio

You can ask LUSID to aggregate performance returns for a portfolio over a particular period, for example the preceding 5 days, the year to date, since fund inception, or all of these.

- To aggregate performance for a [transaction portfolio](/v1/docs/how-do-i-create-a-transaction-portfolio), you must upload your own [simple performance returns](/v1/docs/aggregating-performance-returns-for-a-portfolio#uploading-a-simple-performance-return-for-a-transaction-portfolio) to record the rate of return of the portfolio, either per day (the default) or per month. LUSID can then use geometric linking to calculate cumulative rate of return over any period.
- To aggregate performance for a [reference portfolio](/v1/docs/how-do-i-create-a-reference-portfolio), you do not need to upload your own performance return data but instead you must upload [quotes for each constituent instrument](/v1/docs/how-do-i-upload-a-market-price-or-fx-spot-rate-to-the-quote-store) in the portfolio to the LUSID Quote Store.

## Uploading a simple performance return for a transaction portfolio

To create or update a simple performance return for a transaction portfolio, call the [UpsertPortfolioReturns](https://www.lusid.com/docs/api#operation/UpsertPortfolioReturns) API, specifying the `scope` and `code` of the transaction portfolio and then the `returnScope` and `returnCode` of a particular set of simple performance returns, to which you can add as many individual returns as you like. You should supply a `PerformanceReturn` object in the body of your API request with the following data:

| **Field** | **Status** | **Explanation** |
| --- | --- | --- |
| `effectiveAt` | Required | An effective datetime marking the end of the return period. |
| `rateOfReturn` | Required | The net gain or loss of the investment over `period`. |
| `openingMarketValue` | Optional | The market value at the start of `period`. Though optional, you should specify either this or `closingMarketValue`; do not omit both. LUSID uses the formula below this table to calculate missing market values. |
| `closingMarketValue` | Optional | Specify the market value at the end of `period`. Though optional, you should specify either this or `openingMarketValue`; do not omit both. |
| `period` | Optional | Determines the source of [simple performance returns](/v1/docs/aggregating-performance-returns-for-a-portfolio#uploading-a-simple-performance-return-for-a-transaction-portfolio) to use, either `Daily` or `Monthly`. The default is `Daily`; this constitutes a return for one day. Specify `Monthly` to specify a return for one month. |

You can specify any number you like for the `rateOfReturn`. For example, you could calculate it as a simple percentage difference between the opening and closing market values:

`rateOfReturn = (closingMarketValue – openingMarketValue) / openingMarketValue`

Note an individual simple performance return may not have either an `openMarketValue` or a `closingMarketValue` (these fields are optional). If no `openingMarketValue` is provided, then LUSID calculates it as follows:

- If it is the first performance return, then:
  - If `rateOfReturn` is `0`, then `openingMarketValue` is `0` as well.
  - If `rateOfReturn` has a value then `openingMarketValue` is calculated using the formula: `openingMarketValue = closingMarketValue / (rateOfReturn + 1)`
- If it is not the first performance return, then `openingMarketValue` is the previous `closingMarketValue`.

If no `closingMarketValue` is provided, then LUSID calculates it using the formula:

`closingMarketValue = (rateOfReturn + 1) * openingMarketValue`

Note you can:

- List all the simple performance returns you have uploaded to a transaction portfolio using the [GetPortfolioReturns](https://www.lusid.com/docs/api#operation/GetPortfolioReturns) API.
- Delete a particular simple performance using the [DeletePortfolioReturns](https://www.lusid.com/docs/api#operation/DeletePortfolioReturns) API.

## Calculating aggregated performance return for a transaction or reference portfolio

Call the [GetPortfolioAggregatedReturns](https://www.lusid.com/docs/api#operation/GetPortfolioAggregatedReturns) API, passing in the `scope` and `code` of the portfolio and, optionally, `fromEffectiveAt` and `toEffectiveAt` dates to restrict the returns to aggregate. For an example, see [this Jupyter Notebook](https://github.com/finbourne/finbourne-notebooks/blob/main/V1/product/ibor/Loading%20and%20calculating%20returns.ipynb).

> **Note**: If the portfolio is a [composite portfolio](/v1/docs/what-is-a-composite-portfolio), LUSID automatically aggregates performance for all constituent portfolios. Note if you want the dispersion metric you should call the [GetAggregatedReturnsDispersionMetrics](https://www.lusid.com/docs/api#operation/GetAggregatedReturnsDispersionMetrics) API instead, providing the composite has at least six constituent portfolios and each has been in for the whole year. If you want to analyse how the composite return has been calculated afterward, call the [GetCompositeBreakdown](https://www.lusid.com/docs/api#operation/GetCompositeBreakdown) API. For an example, see [this Jupyter Notebook](https://github.com/finbourne/finbourne-notebooks/blob/main/V1/product/ibor/Returns%20on%20composite%20portfolios.ipynb).

You should supply an `AggregatedReturnsRequest` object in the body of your API request with the following data to control how LUSID aggregates returns:

| **Field** | **Status** | **Explanation** |
| --- | --- | --- |
| `metrics` | Required | You must provide at least one `PerformanceReturnsMetric` object; [see the following table](/v1/docs/aggregating-performance-returns-for-a-portfolio#performancereturnsmetric). |
| `returnIds` | Required for a transaction portfolio | This is the `returnScope` and `returnCode` of the set of [simple performance returns](/v1/docs/aggregating-performance-returns-for-a-portfolio#uploading-a-simple-performance-return-for-a-transaction-portfolio) to aggregate. |
| `recipeId` | Optional | This is the scope and code of a [recipe](/v1/docs/what-is-a-recipe) from which to get FX rates to convert returns into the base currency of the portfolio (including inferring from an inverse FX rate if the appropriate parameter is set). If not specified, this is the built-in default recipe. |
| `compositeMethod` | Optional | The default is `Asset`; if the portfolio is a composite, a weighted average of all constituent portfolios is used to determine the result. Specify `Equal` to determine that all the constituent portfolios in the composite are weighted equally. |
| `period` | Optional | The default is `Daily`. You can change this to `Monthly`. Note if you specify `Monthly` but have no monthly performance returns then daily returns are used to calculate a monthly return if sufficient of the former are available. |
| `outputFrequency` | Optional | The default is `Daily`; you can change this to either `Weekly`, `Monthly`, `Quarterly`, `HalfYearly` or `Yearly`. See also the `PERIODRETURN` constant window in the [following table](/v1/docs/aggregating-performance-returns-for-a-portfolio#performancereturnsmetric). |
| `alternativeInceptionDate` | Optional | The date from which to include performance returns if this is different from the date when returns begin. Can be a date string or a portfolio property. Defaults to the actual inception date. |
| `holidayCalendars` | Optional | The [holiday calendar](/v1/docs/using-calendars-in-lusid) code(s) that should be used to determine the date schedule as a comma-separated list (for example `CoppClark`). |
| `currency` | Optional | Converts the results to the specified currency. If omitted, results are in the portfolio currency. Can be a ISO 4217 currency code string or a portfolio property. |
| `runMode` | Optional | Defaults to `ReturnData`, in which case LUSID calculates results for the returns uploaded to the system. Specify: - `AllDays` to calculate results for all dates including weekends (if there is no return for a particular date, it is treated as 0 rather than omitted). - `WeekDays` to calculate results for all dates excluding weekends (if there is no return for a particular date, it is treated as 0 rather than omitted). - If `period` is `Monthly`, `MonthEnd` to use the last return found for a particular month as the return for the *last day* of the month, rather than not returning a result. |

### Understanding the `PerformanceReturnsMetric` object

For the `metrics` field (above), supply at least one `PerformanceReturnsMetric` object containing the following data:

| **Field** | **Status** | **Explanation** |
| --- | --- | --- |
| `type` | Optional | Specify: - `Return` to calculate the cumulative return using geometric linking. This is the default. - `Volatility` to return a value based on the statistical dispersion of returns (how much an asset's price swings around the mean price). - `IndicativeAmount` to return a value based on the `seedAmount` (see below), calculated using the formula `seedAmount * (1 + Return-for-window)`. |
| `window` | Required | Specify the window to aggregate. This should be a string constituting either a **Constant window**, a **Multi-X metric** or a **Since** metric. **Constant window** \| **String** \| **Explanation** \| \| --- \| --- \| \| `PERIODRETURN` \| Aggregation depends upon the value of `outputFrequency` (see the table above): - If `outputFrequency` is `Daily`, this is a ‘1 day return’. - If `outputFrequency` is `Weekly`, this is a ‘1 week return’. - If `outputFrequency` is `Monthly`, this is a ‘1 month return’. - If `outputFrequency` is `Quarterly`, this is a ‘quarter return’. - If `outputFrequency` is `HalfYearly`, this is a ‘half year return’. - If `outputFrequency` is `Yearly`, this is a ‘1 year return’. \| \| `WTD` \| Aggregates returns for the week to date, where Monday is the first day of the week. \| \| `MTD` \| Aggregates returns for the month to date. \| \| `QTD` \| Aggregates returns for the quarter to date. \| \| `YTD` \| Aggregates returns for the year to date. \| \| `INC` \| Aggregates returns since inception. \| **Multi-X metric** Since months may be of varying length, there is special handling for the last day of the month. Month-end dates look back to prior month-end dates. So, one month rolling for the 28th February will look back to the 31st of January, not the 28th January. \| **String** \| **Explanation** \| \| --- \| --- \| \| `XD` \| Aggregates returns for X days (eg. `3D`) \| \| `XW` \| Aggregates returns for X weeks (eg. `3W`) \| \| `XM` \| Aggregates returns for X months (eg. `3M`) \| \| `XY` \| Aggregates returns for X years (eg. `3Y`) \| **Since metric** \| **String** \| **Explanation** \| \| --- \| --- \| \| `Since(yyyy-mm-dd)` \| Aggregates returns since a particular date (eg. `Since(2012-12-20)`) \| \| `Since(YYYY-mm-dd)` \| Aggregates returns since the most recent occurrence of a day in a year (eg. `Since(YYYY-12-20)`) \| \| `Since(PropertyKey)` \| Aggregates returns since the value of a particular property (eg. `Since(Portfolio/Test/ReturnDate)`) \| |
| **String** | **Explanation** |
| `PERIODRETURN` | Aggregation depends upon the value of `outputFrequency` (see the table above): - If `outputFrequency` is `Daily`, this is a ‘1 day return’. - If `outputFrequency` is `Weekly`, this is a ‘1 week return’. - If `outputFrequency` is `Monthly`, this is a ‘1 month return’. - If `outputFrequency` is `Quarterly`, this is a ‘quarter return’. - If `outputFrequency` is `HalfYearly`, this is a ‘half year return’. - If `outputFrequency` is `Yearly`, this is a ‘1 year return’. |
| `WTD` | Aggregates returns for the week to date, where Monday is the first day of the week. |
| `MTD` | Aggregates returns for the month to date. |
| `QTD` | Aggregates returns for the quarter to date. |
| `YTD` | Aggregates returns for the year to date. |
| `INC` | Aggregates returns since inception. |
| **String** | **Explanation** |
| `XD` | Aggregates returns for X days (eg. `3D`) |
| `XW` | Aggregates returns for X weeks (eg. `3W`) |
| `XM` | Aggregates returns for X months (eg. `3M`) |
| `XY` | Aggregates returns for X years (eg. `3Y`) |
| **String** | **Explanation** |
| `Since(yyyy-mm-dd)` | Aggregates returns since a particular date (eg. `Since(2012-12-20)`) |
| `Since(YYYY-mm-dd)` | Aggregates returns since the most recent occurrence of a day in a year (eg. `Since(YYYY-12-20)`) |
| `Since(PropertyKey)` | Aggregates returns since the value of a particular property (eg. `Since(Portfolio/Test/ReturnDate)`) |
| `allowPartial` | Optional | Defaults to False; returns are only aggregated if the date range is fully covered by the return history. For example, a one year return is only aggregated if the portfolio has returns posted for at least one year. Specify True to aggregate returns from the current state of the return history. Note results will be partial. |
| `annualised` | Optional | Defaults to False. Specify True to annualise the result. The calculation is as follows: given return `r` and "time-window" `y` measured in years, then: `annualised return = power(1+r,1/y)-1`. For example, imagine we have a 10% return for the period 29 January 2020 to 29 January 2025. This is for 5 years, so the calculation is `power(1.1,1/5)-1 &nbsp;= 1.9245%` (to 4 decimal places). **Note**: LUSID calculates the number of years factoring in leap years, hence the example above raises to the power 1/5. 29 January 2020 to 29 January 2025 is 5 years. Another common approach is to use days/365.25 - which for the example above would be 1827/365.25 = 5.002053388 years, giving an annualised return of 1.9237%. |
| `withFee` | Optional | Defaults to False. Specify True if `period` is `Monthly` to include model fees in the performance calculation, and apply the monthly rate of fees using the `Portfolio/default/ModelFees` [system property](/v1/docs/what-is-a-system-property#portfolio-system-properties). Please note this is only supported for monthly returns. |
| `seedAmount` | Optional | Specify a decimal value to use as the seed amount when `type` is `IndicativeAmount` (see above). |
| `alias` | Optional | Specify a name to display for the metric in the response. |
