Performance & ValueDevelopment
One of the most important aspects of an investment platform is for investors to view and understand how their investments are doing. The GiroPro API offers multiple endpoints and multiple different ways to calculate an asset’s or portfolio’s performance and value development.
What’s the difference?
- Performance is considered the extent to which an investment has achieved its goal (growth) over a specific period of time. These periods are configurable but always result in a single performance over that period.
- Value development is a collection of values and performances over a specific period with specific intervals. For example, the value and performance of an asset or portfolio for every month of a year.
Use cases
- Performance is used in cases where we want to show the user how their investments have developed since a certain date or within a certain range. For example: since start of investment, since start of the year, over a specific year, since three months ago, etcetera. This is useful to show how the total portfolio or individual assets have performed and to what extent the individual assets in a portfolio are responsible for that performance.
- Value development is used in cases where historical changes in value and performance are relevant. This is useful for plotting historical performance of an asset or porfolio in a diagram.
Performance calculations (IRR & TWR)
Due to the nature of most investment platforms, calculating the performance of a portfolio or the assets within it isn’t as straight forward as one might think. Whilst calculating the performance of a single unit of an assets is relatively straightforward, it becomes a lot more complicated when we want to calculate the performance of a portfolio in which assets can be purchased, sold or rebalanced at any given moment.
Thankfully, performance calculation methodologies for both scenarios already exist and are used extensively in GiroPro. GiroPro generally expresses performance in both IRR and TWR:
- IRR: Internal Rate of Return is generally used when expressing the performance of something static, like a single unit of an asset to show the value development of a stock, bond or index offered by an investment platform. The value of the assets can change but the amount remains constant.
- TWR: Time-Weighted Return is used to express the performance of something more dynamic, like a portfolio or the assets within it as the amount of each asset in the portfolio is likely to change.
Both IRR and TWR are heavily documented methodologies used throughout the finance industry. Within GiroPro both rates are expressed as decimal-form percentages.
Cumulative and Annualized result types
GiroPro offers two different ways to express the performance rate: cumulative and annualized.
- Cumulative performance is the total over a certain period of time.
- Annualized performance is the average performance per year over a certain period of time.
Performance
Performance is considered the extent to which an investment has achieved its goal (growth) over a specific period of time. These periods are configurable but always result in a single performance over that period.
GET /PortfolioGetByInvestorAccountId/
The specifics of this endpoint can be found here. Like many of the other aspects relevant to the portfolio, performance is included in the portfolio by default as PerformancePortfolioItems. Here’s what a PerformancePortfolioItem looks like:
{
"labelId": "00000000-0000-0000-0000-000000000000",
"investorAccountId": "00000000-0000-0000-0000-000000000000",
"performancePercentage": 0.06, // percentage expressed as a floating point decimal
"performanceCalculationMethod": "IRR", // either IRR or TWR
"assets": [
{
"assetId": "1c092ed5-1bfb-44fa-9748-1af365962298",
"performancePercentage": 0.09 // performance of this specific asset
},
{
"assetId": "45320bbc-5f92-4ac3-a04c-6dcdf53f533e",
"performancePercentage": 0.04 // performance of this specific asset
}
]
}
This endpoint always contains a PerformancePortfolioItem for both the IRR and TWR calculation method. Both results are annualized and cover the entire period since the first investment was made until now.
GET /PerformanceGetByPortfolio/
The /PerformanceGetByPortfolio/ endpoint returns the performance of a portfolio based on the provided labelId, investorAccountId and query parameters:
| Parameters | Potential values |
|---|---|
| PerformanceMethods (required) | IRR and/or TWR |
| performanceCalculationResultType | Cumulative(default) or Annualized |
| includeIndividualAssetPerformance | true or false(default) |
| fromDate | 1970-01-01T00:00:00Z |
| tillDate | 1970-01-01T00:00:00Z |
const url = 'https://api.dev.giropro.pengine.com/PENGINE/Aggregator/DataAggregator/PerformanceGetByPortfolio/<labelId>/<investorAccountId>?performanceMethods=IRR&performanceMethods=TWR&performanceCalculationResultType=Annualized&includeIndividualAssetPerformance=true';
const options = {
method: 'GET',
headers: {
accept: 'application/json',
authorization: 'bearer <token>'
}
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));
{
"success": true,
"httpStatusCode": 200,
"errors": [],
"totalCount": 2,
"items": [
{
"return_type": "PerformancePortfolioAggregatedItem",
"labelId": "00000000-0000-0000-0000-000000000000",
"investorAccountId": "00000000-0000-0000-0000-000000000000",
"performancePercentage": 0.067921985,
"performanceCalculationMethod": "IRR",
"assets": [
{
"assetId": "1c092ed5-1bfb-44fa-9748-1af365962298",
"performancePercentage": 0.036715175
},
{
"assetId": "45320bbc-5f92-4ac3-a04c-6dcdf53f533e",
"performancePercentage": 0.081342594
},
{
"assetId": "8823cbb4-1ccc-4682-b8ea-cd4c67857cbf",
"performancePercentage": 0.046656396
},
{
"assetId": "be5f5770-2301-4296-9230-69c88ac6a637",
"performancePercentage": 0.147668203
}
]
},
{
"return_type": "PerformancePortfolioAggregatedItem",
"labelId": "00000000-0000-0000-0000-000000000000",
"investorAccountId": "00000000-0000-0000-0000-000000000000",
"performancePercentage": 0.067921985,
"performanceCalculationMethod": "TWR",
"assets": [
{
"assetId": "1c092ed5-1bfb-44fa-9748-1af365962298",
"performancePercentage": 0.036052502
},
{
"assetId": "45320bbc-5f92-4ac3-a04c-6dcdf53f533e",
"performancePercentage": 0.080972398
},
{
"assetId": "8823cbb4-1ccc-4682-b8ea-cd4c67857cbf",
"performancePercentage": 0.046561915
},
{
"assetId": "be5f5770-2301-4296-9230-69c88ac6a637",
"performancePercentage": 0.147077508
}
]
}
]
}
GET /PerformanceGetByAsset/
Similarly to the /PerformanceGetByPortfolio/ endpoint, the /PerformanceGetByAsset/ returns performance based on the specified parameters, but on the asset-level instead. It requires the addition of an assetId in the path and takes one fewer query parameter:
| Parameters | Potential values |
|---|---|
| PerformanceMethods (required) | IRR and/or TWR |
| performanceCalculationResultType | Cumulative(default) or Annualized |
| fromDate | 1970-01-01T00:00:00Z |
| tillDate | 1970-01-01T00:00:00Z |
const url = 'https://api.dev.giropro.pengine.com/PENGINE/Aggregator/DataAggregator/PerformanceGetByAsset/<labelId>/<investorAccountId>/<assetId>?performanceMethods=IRR&performanceMethods=TWR&performanceCalculationResultType=Annualized';
const options = {
method: 'GET',
headers: {
accept: 'application/json',
authorization: 'bearer <token>'
}
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));
{
"success": true,
"httpStatusCode": 200,
"errors": [],
"totalCount": 2,
"items": [
{
"return_type": "PerformanceAssetAggregatedItem",
"labelId": "cd3a71f1-b9ac-4e44-a06b-f89f35beafa7",
"investorAccountId": "488ff6a0-c7b1-4690-b886-23076b7f01e2",
"performancePercentage": 0.0,
"performanceCalculationMethod": "IRR",
"assetId": "1c092ed5-1bfb-44fa-9748-1af365962298",
"beginDate": "2008-01-31",
"endDate": "2024-12-31"
},
{
"return_type": "PerformanceAssetAggregatedItem",
"labelId": "cd3a71f1-b9ac-4e44-a06b-f89f35beafa7",
"investorAccountId": "488ff6a0-c7b1-4690-b886-23076b7f01e2",
"performancePercentage": 0.119792,
"performanceCalculationMethod": "TWR",
"assetId": "1c092ed5-1bfb-44fa-9748-1af365962298",
"beginDate": "2008-01-31",
"endDate": "2024-12-31"
}
]
}
When to use
The /PortfolioGetByInvestorAccountId/ returns the performance of the portfolio and its assets according to both performance calculation methods but the results are annualized. If you want to get the cumulative result of a portfolio or its assets its better to use the other endpoints.
ValueDevelopment
Value development is a collection of values and performances over a specific period with specific intervals. For example, the performance of an asset or portfolio for every month of a year.
GiroPro offers two endpoints to retrieve the ValueDevelopment. One which returns the values of a portfolio per marketDay for a specified period, and one that returns values and performances of a portfolio per specified interval for a specified period.
GET /ValueDevelopment/
The /ValueDevelopment/ endpoint returns a PengineResult containing a list of ValueDevelopmentAggregatedItems based on the provided labelId and investorAccountId and the specified period.
| Parameters | Potential values |
|---|---|
| fromDate | 1970-01-01T00:00:00Z |
| tillDate | 1970-01-01T00:00:00Z |
const url = 'https://api.dev.giropro.pengine.com/PENGINE/Aggregator/DataAggregator/ValueDevelopment/<labelId>/<InvestorAccountId>';
const options = {
method: 'GET',
headers: {
accept: 'application/json',
authorization: 'bearer <token>'
}
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));
This endpoint returns a PengineResult with a list of ValueDevelopmentAggregatedItems for every marketDay between the (optionally) specified fromDate and tillDate.
{
"success": true,
"httpStatusCode": 200,
"errors": [],
"totalCount": 123,
"items": [
{
"return_type": "ValueDevelopmentAggregatedItem",
"date": "2008-01-31", // date of marketDay
"portfolioValue": 50500.00, // total value of portfolio
"cashMain": 0.00,
"cashReserved": 0.0,
"deposits": 50000.00, // totals value of deposits until this date
"withdraws": 0.0 // total value of withdraws until this date
},
// ...more items
]
}
GET /ValueDevelopmentOverview/
The /ValueDevelopmentOverview/ endpoint returns a PengineResult containing a list of ValueDevelopmentOverviewAggregatedItems based on the provided labelId, investorAccountId, performanceCalculationResultType, interval and the specified period.
| Parameters | Potential values |
|---|---|
| performanceCalculationResultType (required) | Cumulative or Annualized(default) |
| interval | Weekly or Monthly or Yearly(default) |
| fromDate | 1970-01-01T00:00:00Z |
| tillDate | 1970-01-01T00:00:00Z |
const url = 'https://api.dev.giropro.pengine.com/PENGINE/Aggregator/DataAggregator/ValueDevelopmentOverview/<labelId>/<investorAccountId>?performanceCalculationResultType=Annualized';
const options = {
method: 'GET',
headers: {
accept: 'application/json',
authorization: 'bearer <token>'
}
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error(err));
This endpoint returns a PengineResult with a list of ValueDevelopmentOverviewAggregatedItems at every specified interval between the (optionally) specified fromDate and tillDate. The ValueDevelopmentOverviewAggregatedItems contains additional fields for costs and performances.
{
"success": true,
"httpStatusCode": 200,
"errors": [],
"totalCount": 12,
"items": [
{
"return_type": "ValueDevelopmentOverviewAggregatedItem",
"startDate": "2007-12-31",
"endDate": "2008-12-31",
"startValue": 0.00,
"endValue": 50500.00,
"deposits": 50000.00,
"withdraws": 0.0,
"dividend": 0.0,
"realizedResult": 0.0,
"ocfCosts": 123.45,
"transactionCosts": 456.78,
"periodTwr": 0.01,
"totalTwr": 0.01,
"periodIrr": 0.01,
"totalIrr": -0.3793
},
// ...more items
]
}
When to use
These are the best use cases for both endpoints:
- /ValueDevelopment/ is mostly used for plotting a graph of the value of the portfolio over time with the possibility to make a distinction between invested/withdrawn funds and results.
- /ValueDevelopmentOverview/ is effectively the same but offers more controls and fields for more specific use cases like a yearly or monthly summary, a breakdown of costs or an annual report.
It might be tempting to always want to use /ValueDevelopmentOverview/ as it contains more data, but the added performance calculations strongly affect the response time of the endpoint. Therefore it should only be used in situations where the performance calculations are required.