Data AnalyticsPortfolio projects with Indian public data

Parse AMFI's NAVAll.txt and compare mutual fund category returns

PK
Pankit Kumar
Sr. Data Scientist at Parexel (a Goldman Sachs–backed company) · 27 September 2026 · 6 min read
In this article (7 sections)

Related programme: the Data Analytics with Generative AI course (3–4 months; ₹90,000 (inclusive of GST) · EMI from ₹4,000/month).

The short answer

AMFI publishes the latest net asset value of every Indian mutual fund scheme in one plain-text file. Parsing it properly is a small, satisfying project with a real payoff. You recover each scheme's category and fund house from header lines that sit between data rows, then use NAVs from two dates to compare one-year returns within categories. The result is a table showing how widely funds in the same category differ, which is more useful to a reader than any single fund's return.

The file and its quirks

Download NAVAll.txt from AMFI. The first line is the header:

text
Scheme Code;ISIN Div Payout/ ISIN Growth;ISIN Div Reinvestment;Scheme Name;Plan;Option;Net Asset Value;Date

After that the file is not a clean table. In the copy we downloaded on 27 September 2026 (about 18,100 lines) we found:

  • Category lines such as Open Ended Schemes(Debt Scheme - Banking and PSU Fund).
  • Fund-house lines, a bare name such as Axis Mutual Fund.
  • "Blank" lines that contain a single space, so a simple line == "" test misses them.
  • Placeholder ISINs written as -.
  • Mixed dates. The file is "latest NAV per scheme", not "NAV on one date". About 8,000 rows were dated 25 September, about 700 were dated 27 September, and thousands carried old dates (113 from 2 July 2018 alone) for schemes whose NAV has not been updated in years.
  • Empty Plan and Option fields on roughly 5,800 of about 14,400 schemes. Where Option is filled, it is spelt many ways: "Growth", "Growth Option", "GROWTH", "IDCW", "IDCW Option" and longer variants. Often the plan and option must be read from the scheme name.
  • Zero NAVs on segregated portfolios, whose names contain "Segregated".
  • A curly apostrophe in a category name, which garbles if you read the file with the wrong encoding.
  • Two rows with the same scheme name, plan and option but different scheme codes. The scheme code, not the name, is the identifier. It was unique across the whole file.

For history, AMFI's NAV History section (Net Asset Value → NAV History) lets you download NAVs for a date or a period. Check the downloaded file's header, because its layout may differ from NAVAll.

Why this is worth an employer's time

Wealth platforms, fund distributors and research desks in Gurugram and Mumbai all maintain loaders like this, and they break when a source changes format. Showing a parser that carries context from header lines is a real skill. So is testing for malformed rows and keeping the identifier straight. The category comparison then shows you can turn raw prices into a fair like-for-like view.

A parser that carries context forward

The input below is synthetic. It copies the real layout, but the schemes, codes and NAVs are invented.

python
import io
import pandas as pd

text = """Scheme Code;ISIN Div Payout/ ISIN Growth;ISIN Div Reinvestment;Scheme Name;Plan;Option;Net Asset Value;Date
 
Open Ended Schemes(Equity Scheme - Large Cap Fund)
 
Example One Mutual Fund
 
900001;INF000A01AA1;-;Example One Large Cap Fund;Direct Plan;Growth Option;120.5000;25-Sep-2026
900002;INF000A01AB9;INF000A01AC7;Example One Large Cap Fund;Direct Plan;IDCW Option;31.2000;25-Sep-2026
 
Example Two Mutual Fund
 
900101;INF000B01AA4;-;Example Two Large Cap Fund;Direct Plan;Growth Option;88.1000;25-Sep-2026
900102;INF000B01AB2;-;Example Two Large Cap Fund - Regular Plan - Growth;;;N.A.;25-Sep-2026
900103;INF000B01AC0;-;Example Two Large Cap Fund (Segregated - 01012026);;;0;25-Sep-2026
900104;INF000B01AD8;-;Example Two Old Fund;Regular Plan;GROWTH;15.2000;02-Jul-2018
 
Open Ended Schemes(Equity Scheme - Mid Cap Fund)
 
Example One Mutual Fund
 
900201;INF000A01AD5;-;Example One Mid Cap Fund;Direct Plan;Growth Option;64.7300;25-Sep-2026
"""

def parse_navall(fh):
    header = fh.readline().strip().split(";")
    rows, category, amc = [], None, None
    for line in fh:
        line = line.strip()
        if not line:
            continue
        if ";" in line:
            rows.append(dict(zip(header, line.split(";")), category=category, amc=amc))
        elif line.startswith(("Open Ended", "Close Ended", "Interval Fund")):
            category = line
        else:
            amc = line
    df = pd.DataFrame(rows)
    df["nav"] = pd.to_numeric(df["Net Asset Value"], errors="coerce")
    df["date"] = pd.to_datetime(df["Date"], format="%d-%b-%Y")
    df["category_name"] = df["category"].str.extract(r"\((.*)\)")[0]
    return df

nav = parse_navall(io.StringIO(text))
print(nav[["Scheme Code", "amc", "category_name", "Plan", "Option", "nav"]])
print("non-numeric NAVs:", int(nav["nav"].isna().sum()))
assert nav["Scheme Code"].is_unique

# Keep only NAVs on the file's most common date, and drop zero NAVs (segregated portfolios)
latest = nav["date"].mode()[0]
usable = nav[(nav["date"] == latest) & (nav["nav"] > 0)]
print("usable rows:", len(usable), "of", len(nav), "on", latest.date())

# Normalise the many spellings of Option, falling back to the scheme name when Option is blank
def option_kind(row):
    text = (row["Option"] or row["Scheme Name"]).lower()
    return "IDCW" if ("idcw" in text or "dividend" in text) else ("Growth" if "growth" in text else "Unknown")
print(nav.apply(option_kind, axis=1).value_counts())

Our parser run on the real file loaded every scheme, with a unique code and a category on each row. On the real file, open it with encoding="utf-8" and confirm the curly apostrophe survives. If it doesn't, try the encoding the server declares, and record which one worked.

From NAVs to category returns

With a second NAV snapshot from a year earlier, one-year return per scheme is nav_now / nav_then - 1. The rules that keep it fair:

  1. 1Join on Scheme Code, never on name, and only use NAVs whose date is the snapshot date you intended.
  2. 2Use Growth options only. IDCW payouts reduce NAV and make returns look worse than they were.
  3. 3Keep Direct and Regular separate. Mixing them blends a cost difference into your category spread. Direct is the cleaner comparison; the gap itself is a separate project.
  4. 4Require both dates. Schemes launched within the year have no return and must not be treated as zero.
  5. 5Check the category did not change. SEBI's scheme categorisation means a fund can be recategorised. Compare the category label on both dates and flag any changes.

Analysis plan

  • Parse both snapshots, filter to Direct Growth, and join on code.
  • For each category, compute count, median, 25th and 75th percentiles, and the spread between the best and worst quartile.
  • Rank categories by dispersion, not by median return. The point is how much fund choice matters inside a category.
  • Mark any category with fewer than ten schemes as too small to summarise.

The deliverable

ArtefactWhat it shows
Box plotOne-year Direct Growth returns by category, sorted by median
TableCategory, n, median, interquartile range, count of recategorised schemes
parse_navall.pyTested parser with the malformed-line cases above
READMESource URLs, download dates, parsing rules, return rules, limitations

State in the README that past returns do not predict future returns. Also state that the analysis ignores taxes, exit loads and the timing of flows. It is a description, not advice.

What interviewers will ask

  • How does your parser know which category a row belongs to?
  • Why did you not join on scheme name?
  • What goes wrong if you include IDCW options?
  • A category has a huge spread. Name two explanations that are not fund-manager skill.
  • How would you run this daily and detect when AMFI changes the file?

Parsing semi-structured files and building fair comparisons are central to the Data Analyst programme. The skill check will tell you whether you are ready to start with Python or should begin with spreadsheets.

Frequently asked questions

Where does AMFI publish daily mutual fund NAVs?

The latest NAV of every scheme is in a single text file at amfiindia.com/spages/NAVAll.txt. It is semicolon-delimited, with category and fund-house header lines between the data rows. Historical NAVs are available from the NAV History section of AMFI's site.

Why use only growth options when comparing returns?

An IDCW (dividend) option pays money out, and its NAV drops by the payout. A point-to-point NAV change on an IDCW option understates what an investor earned. Growth options keep returns inside the NAV, so their NAV change is a fair return measure.

PK
Pankit Kumar
Lead Instructor, NeuraPath Academy

Pankit Kumar has 10 years in Data Science & AI, building and shipping production systems in regulated pharma and clinical environments. He is a freelance trainer at Boston Institute of Analytics, AnalytixLabs and Scaler, and has taught this material to thousands of working professionals.

This article is part of our Data Analytics with Generative AI programme — 3–4 months. The full analyst stack — Excel, SQL, Power BI and Python pipelines — then a generative-AI layer you can prove is right.

Explore Data Analytics with Generative AI
Counselling is free · no obligation

Not sure which programme fits?

Tell us your background and we will map it to the right entry point — including saying so when a cheaper programme is the better fit. A counsellor replies within one working day.