Mutual fund CAGR and rolling returns

The rolling-summary endpoint returns annualised returns for 1, 3, 5 and 10 years. This guide reads them, checks them against your own calculation from NAV history, and then goes further to rolling one-year returns.

You need an API key: request a free beta key. Keep it in an environment variable, never in code you publish.

Script

import os
import requests
import pandas as pd

BASE = os.environ.get("EJI_BASE", "https://fin.ejiapi.com")
HEADERS = {"x-api-key": os.environ.get("EJI_KEY", "YOUR_KEY")}

def get(path, **params):
    r = requests.get(BASE + path, params=params, headers=HEADERS, timeout=60)
    r.raise_for_status()
    return r.json()["data"]

# Ready-made annualised returns (percent). A value is None when the scheme lacks that much history.
print(get("/api/mf/scheme-code/122639/rolling-summary"))

# Check one figure yourself from the history
nav = pd.DataFrame(get("/api/mf/nav-history/scheme-code/122639"))
nav["date"] = pd.to_datetime(nav["date"])
nav = nav.set_index("date")["nav"]

def cagr(years):
    end_date = nav.index[-1]
    start_date = end_date - pd.DateOffset(years=years)
    start_nav = nav[:start_date].iloc[-1]  # last NAV on or before the start date
    return ((nav.iloc[-1] / start_nav) ** (1 / years) - 1) * 100

for y in (1, 3, 5):
    print(f"{y}y CAGR computed: {cagr(y):.2f}")

# Rolling 1-year returns: for each day, the return over the previous 365 days
s = nav.resample("D").last().ffill()
roll = (s / s.shift(365) - 1) * 100
print(roll.dropna().describe().round(2))

Output

{'cagr1y': 0.18, 'cagr3y': 13.48, 'cagr5y': 11.9, 'cagr10y': 17.43}
1y CAGR computed: 0.18
3y CAGR computed: 13.63
5y CAGR computed: 11.90
count    4546.00
mean       20.05
std        18.38
min       -21.27
25%         5.91
50%        17.06
75%        31.56
max       100.06
Name: nav, dtype: float64

Why 3 years differs slightly

The 1 and 5 year figures match exactly; the 3 year figure is 13.48 from the API and 13.63 from the script. That is a date-convention difference, not an error: the script takes the last NAV on or before the exact start date, and the stored calculation may pick a neighbouring trading day. A one or two day shift in the start NAV moves a 3-year CAGR by a few hundredths. If you need a specific convention, compute it yourself from the history as shown.

Reading the distribution

The last block is the spread of every rolling one-year return since the fund's history begins. The maximum of 100% is an early-period outlier, which is why the median (17.06) says more than the mean. Past returns do not predict future returns.

Get a free API key All guides

Data comes from public disclosures and is for information, not investment advice. Sample outputs were produced on 2026-11-08 and change as new data is published.