---
title: "Fund performance data explained: cumulative, calendar-year, annualised and rebased to 100"
description: "The four ways fund performance is reported, what each one hides, how to compute tracking difference, and how to chart fund vs benchmark from API data."
canonical: https://fundfactsapi.com/blog/fund-performance-data-explained
published: 2026-09-02
updated: 2026-09-02
publisher: FundFacts API
---

# Fund performance data explained: cumulative, calendar-year, annualised and rebased to 100

> The four ways fund performance is reported, what each one hides, how to compute tracking difference, and how to chart fund vs benchmark from API data.

Performance is the number everyone looks at first and the one most often misread. Factsheets present it four different ways, each answering a different question. This guide explains them, shows how they map to the `data` payload of [FundFacts API](https://fundfactsapi.com/), and gives you the code to chart a fund against its benchmark.

## The four views

| View | API field | Question it answers |
| --- | --- | --- |
| Cumulative | `data.cumulativePerformance` | "If I had invested at the start, how much would I be up today?" |
| Rebased to 100 | `data.indexedPerformance` | "Show me the growth curve of fund and benchmark side by side" |
| Calendar-year | `data.calendarReturns` | "How did it do in 2022 specifically?" |
| Annualised (trailing) | `data.annualisedReturns` | "What did it compound at per year over 3, 5, 10 years?" |

## Cumulative and rebased series

`cumulativePerformance` is an array of `{ date, fund, benchmark }` where the values are cumulative percentage returns from the first point. `indexedPerformance.points` is the same series expressed as **growth of 100** — `{ date, fund, index }` starting at 100 — with `indexedPerformance.hasIndex` telling you whether the benchmark line exists.

```json
{
  "indexedPerformance": {
    "hasIndex": true,
    "points": [
      { "date": "2009-09", "fund": 100, "index": 100 },
      { "date": "2026-08", "fund": 596.6, "index": 598.0 }
    ]
  }
}
```

Rebased series are what you want for a chart: both lines start at the same point, so the gap between them at any date is the cumulative relative performance.

## Calendar-year returns

```json
{
  "calendarReturns": {
    "years": ["2021", "2022", "2023", "2024", "2025", "2026"],
    "fund": [21.9, -18.0, 23.9, 18.7, 21.2, 13.5],
    "benchmark": [null, null, null, null, null, null]
  }
}
```

The arrays are aligned by index. The last year is **year-to-date**, and `benchmark` may be `null` when the document does not publish it. Calendar returns are the honest view of volatility: a fund that shows "+11 % annualised over 5 years" may hide a −18 % year, and this is where you see it.

## Annualised returns and why they mislead

```json
{
  "annualisedReturns": [
    { "label": "1 Year", "fund": 19.68, "index": 19.55 },
    { "label": "3 Years p.a.", "fund": 17.11, "index": 19.78 },
    { "label": "5 Years p.a.", "fund": 11.45, "index": 10.98 },
    { "label": "10 Years p.a.", "fund": 12.82, "index": 12.90 },
    { "label": "Since Inception", "fund": 11.01, "index": null }
  ]
}
```

Annualised (or "p.a.") returns are geometric averages: `(end / start)^(1 / years) − 1`. They are the right way to compare funds with different histories, but two things to remember:

- **End-point sensitivity.** A 3-year figure measured a month after a crash looks very different from one measured a month before it.
- **They are not what an investor experienced** unless the investment was a single lump sum at the start of the window.

## Tracking difference in one line

For an index fund the key number is not the return, it is the gap to the index. With `annualisedReturns` it is trivial:

```typescript
const td = fund.data.annualisedReturns.map((r) => ({
  period: r.label,
  trackingDifference: r.fund != null && r.index != null ? +(r.fund - r.index).toFixed(2) : null,
}));
// [{ period: "1 Year", trackingDifference: 0.13 }, { period: "3 Years p.a.", trackingDifference: -2.67 }, ...]
```

Negative numbers roughly equal to the [TER](https://fundfactsapi.com/blog/ter-ongoing-charges-fund-fees) are expected; large deviations mean sampling, securities-lending income or a benchmark mismatch (a *net* return index versus *gross*, for example).

## Charting fund vs benchmark

Because the series is already rebased, the SVG is short. Here is a dependency-free version:

```tsx
export function GrowthChart({ points }: { points: { date: string; fund: number; index: number | null }[] }) {
  const W = 720, H = 280;
  const all = points.flatMap((p) => [p.fund, p.index ?? p.fund]);
  const min = Math.min(...all), max = Math.max(...all);
  const x = (i: number) => (i / (points.length - 1)) * W;
  const y = (v: number) => H - ((v - min) / (max - min)) * H;
  const path = (key: "fund" | "index") =>
    points.map((p, i) => (p[key] == null ? "" : `${i ? "L" : "M"}${x(i)},${y(p[key] as number)}`)).join(" ");
  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%">
      <path d={path("index")} fill="none" stroke="#F27A1A" strokeDasharray="4 3" />
      <path d={path("fund")} fill="none" stroke="#1F5EFF" strokeWidth={2.5} />
    </svg>
  );
}
```

The [landing page](https://fundfactsapi.com/#showcase) shows this exact chart running on the live sample response.

## Things to state next to any performance number

1. **Currency.** `keyFacts.currency` — a USD share class in a EUR portfolio adds FX return you did not choose.
2. **Income treatment.** `keyFacts.distribution` — accumulating share classes reinvest dividends, so their growth curve is higher than a distributing class of the same fund.
3. **As-of date.** `data.dataAsOf` and the envelope's `generatedAt`.
4. **Fees included.** Published fund returns are net of ongoing charges but before any platform fee or entry charge.

## Next

Read how fees eat into these numbers in [TER and ongoing charges](https://fundfactsapi.com/blog/ter-ongoing-charges-fund-fees), or [create a free key](https://fundfactsapi.com/signup) and pull the full series for one of your funds.

## About FundFacts API

FundFacts turns any fund or ETF ISIN into one dated factsheet (fees and KID costs, the 1–7 risk indicator, holdings, sector and country exposure, returns) read from the fund house's own documents: as a client-ready PDF under your firm's name for advisers and wealth managers, as JSON through its API for developers, or inside ChatGPT and Claude through its MCP server.

FundFacts works inside ChatGPT and Claude as a connector (a remote MCP server): ask about any fund or ETF by ISIN, ticker or name and the assistant answers from FundFacts' dated figures, fees, risk, holdings, exposure and returns, with fund cards, side-by-side comparisons, holdings overlap and portfolio look-through.

- Free API key, no card: https://fundfactsapi.com/signup
- Documentation: https://fundfactsapi.com/docs (OpenAPI: https://fundfactsapi.com/openapi.json)
- MCP server: https://fundfactsapi.com/api/mcp (set-up for every client: https://fundfactsapi.com/mcp-server)
- Pricing: https://fundfactsapi.com/pricing
- Site index for AI assistants: https://fundfactsapi.com/llms.txt
- Informational data, not investment advice.
