Real-Time Financial Data: How to Automate Mutual Fund NAV Tracking with Python

Tracking NAV data of Mututal funds from mfapi

API-First Financial Data Architecture 🔝


How to Automate Mutual Fund NAV Tracking with Python & MFAPI (Part 1)

While AMFI ( Association of Mutual Funds in India) provides the foundational NAV data, this guide focuses on the engineering required to build high-performance retrieval systems.

Each Mutual Fund scheme is identified by a unique, standardized scheme code; by programmatically targeting this identifier, we can retrieve real-time data points including the latest NAV (Net Asset Value), the most recent valuation date, and the official scheme nomenclature.
import requests

def get_latest_nav(scheme_code):
    url = f"https://api.mfapi.in/mf/{scheme_code}/latest"
    response = requests.get(url)
    data = response.json()
    
    latest_nav = data['data'][0]['nav']
    date = data['data'][0]['date']
    fund_name = data['meta']['scheme_name']
    
    return fund_name, latest_nav, date

# Example: Quant Small Cap Fund (Direct Plan)
name, nav, date = get_latest_nav("120847")
print(f"Fund: {name} | Current NAV: {nav} | Date: {date}")

Sample Output is here
Fund: quant ELSS Tax Saver Fund - Growth Option - Direct Plan | Current NAV: 414.31430 | Date: 09-01-2026

Code Walkthrough

  • /latest — Appended to the URL to fetch only the most recent data point, reducing payload size.
  • data['data'][0]['date'] — Specifically extracts the timestamp of the last updated NAV from the API response.
  • return fund_name, latest_nav, date — Returns a tuple containing all three critical data points for further processing.
  • print(f"... Date: {date}") — Uses Python f-strings to display the formatted output in the console.

Tracking multiple funds 🔝


Track Multiple Mutual Funds with Python & Matplotlib (Part 2)

The existing logic can be scaled to support a comprehensive portfolio by utilizing the structured input list below. This approach centralizes data management, allowing you to easily modify scheme tracking by simply updating the list entries.
# Input scheme list
input_schemes = [
{"schemeCode": 120251, "schemeName": "ICICI Prudential Equity & Debt Fund Direct Growth"},
{"schemeCode": 118955, "schemeName": "HDFC Flexi Cap Direct Plan Growth"},
{"schemeCode": 120334, "schemeName": "ICICI Prudential Multi Asset Fund Direct Growth"}
]
For production environments, this input list can be dynamically retrieved from databases such as SQLite or MySQL. Furthermore, the processed outputs can be archived back into storage for historical analysis and reporting. Below is the complete, integrated implementation.

import requests
import json
from datetime import datetime

def fetch_latest_navs(scheme_list):
    """
    Retrieves the most recent NAV and corresponding date for a list of funds.
    """
    base_url = "https://api.mfapi.in/mf/"
    final_report = []

    print(f"{'SCHEME NAME':<65} | {'NAV':<10} | {'DATE':<12}")
    print("=" * 92)

    for scheme in scheme_list:
        code = scheme['schemeCode']
        name = scheme['schemeName']
        
        try:
            # Request data from MFAPI
            response = requests.get(f"{base_url}{code}/latest", timeout=10)
            response.raise_for_status()
            data = response.json()

            if "data" in data and len(data["data"]) > 0:
                # API data is usually in reverse chronological order.
                latest = data["data"][0]
                nav = latest["nav"]
                date = latest["date"]

                final_report.append({
                    "name": name,
                    "code": code,
                    "nav": nav,
                    "date": date
                })

                # Truncated name for table alignment
                short_name = (name[:62] + '..') if len(name) > 65 else name
                print(f"{short_name:<65} | {nav:<10} | {date:<12}")
            else:
                print(f"Data missing for: {name}")

        except Exception as e:
            print(f"Could not retrieve {code}: {e}")

    return final_report

if __name__ == "__main__":
    # Input scheme list
    input_schemes = [
        {"schemeCode": 120251, "schemeName": "ICICI Prudential Equity & Debt Fund Direct Growth"},
        {"schemeCode": 118955, "schemeName": "HDFC Flexi Cap Direct Plan Growth"},
        {"schemeCode": 120334, "schemeName": "ICICI Prudential Multi Asset Fund Direct Growth"}
    ]

    print(f"Querying MFAPI for latest records...\n")
    results = fetch_latest_navs(input_schemes)

Output
Querying MFAPI for latest records...

SCHEME NAME                                             | NAV        | DATE
=================================================================================
ICICI Prudential Equity & Debt Fund Direct Growth       | 453.09000  | 09-01-2026  
HDFC Flexi Cap Direct Plan Growth                       | 2264.30200 | 09-01-2026  
ICICI Prudential Multi Asset Fund Direct Growth         | 898.67790  | 09-01-2026  
import requests
import matplotlib.pyplot as plt
from datetime import datetime

def fetch_and_plot_nav(scheme_code):
    """
    Fetches historical NAV data for a given scheme code from mfapi.in
    and plots the variation over time.
    """
    api_url = f"https://api.mfapi.in/mf/{scheme_code}"
    
    print(f"Fetching data for Scheme Code: {scheme_code}...")
    
    try:
        response = requests.get(api_url, timeout=10)
        response.raise_for_status()
        data = response.json()
        
        if data.get("status") != "SUCCESS":
            print("Error: Could not find data for this scheme code.")
            return

        scheme_name = data['meta']['scheme_name']
        nav_data = data['data']
        
        # Extract dates and NAV values
        # We take the last 60 entries for a clear 2-month view
        subset = nav_data[:60]
        
        # Parse dates and convert NAVs to floats
        dates = [datetime.strptime(item['date'], '%d-%m-%Y') for item in subset]
        nav_values = [float(item['nav']) for item in subset]
        
        # Sort by date
        plot_data = sorted(zip(dates, nav_values))
        dates, nav_values = zip(*plot_data)
        
        # Plotting
        plt.figure(figsize=(10, 6))
        plt.plot(dates, nav_values, marker='o', linestyle='-', 
		color='b', markersize=4)
        
        plt.title(f"NAV Variation: {scheme_name}", fontsize=12)
        plt.xlabel("Date")
        plt.ylabel("Net Asset Value (NAV)")
        plt.grid(True, linestyle='--', alpha=0.7)
        plt.xticks(rotation=45)
        plt.tight_layout()
        
        print("Displaying graph...")
        plt.show()

    except requests.exceptions.RequestException as e:
        print(f"Network error: {e}")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")

if __name__ == "__main__":
    print("--- Mutual Fund NAV Tracker ---")
    user_code = input("Enter the Mutual Fund Scheme Code: ").strip()
    
    if user_code.isdigit():
        fetch_and_plot_nav(user_code)
    else:
        print("Please enter a valid numeric scheme code.")

Calculating Portfolio Valuation

Once the current Net Asset Value (NAV) is retrieved for each scheme, you can determine your total investment value by multiplying the NAV by the number of units held. This provides a real-time snapshot of your portfolio's worth:

Current Value = NAV multipled Units Held

Integrating this logic allows for automated tracking of gains, losses, and overall asset allocation.

Automating Mutual Fund Portfolio Tracking 🔝

Calculate Mutual Fund Investment Value with Python ( part III)

Keeping track of multiple Mutual Fund investments can be tedious if done manually. This Python script automates the process by connecting directly to the Open Source Mutual Fund API (mfapi.in) to fetch real-time Net Asset Values (NAV) and calculate your total portfolio valuation instantly.

Advanced Error Handling

The script features Exponential Backoff logic. If the API is busy, the script intelligently waits and retries (1s, 2s, 4s, etc.), ensuring your data is fetched even under unstable network conditions.

Real-Time Valuation

By mapping your specific schemeCodes and units, the code performs automated multiplication and aggregation to provide a "Grand Total" of your net worth across various fund houses.

Key Technical Highlights

  • 1
    REST API Integration: Uses the requests library to pull live JSON data from the AMFI-linked API endpoints.
  • 2
    Data Structuring: Leverages Python dictionaries to maintain a clean relationship between Fund Names, Scheme Codes, and current Units.
  • 3
    Formatted Output: Utilizes f-strings for professional console-based table formatting, supporting Indian Rupee (₹) symbol and comma-separated thousands.
  • 4
    Time-Stamped Reporting: Automatically extracts the latest NAV date provided by the fund house to ensure you know exactly how recent the valuation is.
import requests
import json
import time
from datetime import datetime

def fetch_nav_with_retry(scheme_code):
    """
    Fetches the latest NAV for a given scheme code from the AMFI API.
    Implements exponential backoff for reliability.
    """
    api_url = f"https://api.mfapi.in/mf/{scheme_code}"
    retries = 5
    delay = 1
    
    for i in range(retries):
        try:
            response = requests.get(api_url, timeout=10)
            response.raise_for_status()
            data = response.json()
            
            # The API returns a list of NAVs, we take the most recent one (index 0)
            if "data" in data and len(data["data"]) > 0:
                latest_nav_data = data["data"][0]
                return {
                    "nav": float(latest_nav_data["nav"]),
                    "date": latest_nav_data["date"]
                }
            return None
        except (requests.RequestException, ValueError, KeyError):
            if i < retries - 1:
                time.sleep(delay)
                delay *= 2  # Exponential backoff: 1s, 2s, 4s, 8s, 16s
            else:
                return None

def calculate_portfolio():
    # User Input Data , expand this list based 
    input_schemes = [
        {"schemeCode": 120251, 
         "schemeName": "ICICI Prudential Equity & Debt Fund Direct Growth",
           "Units": 100.02},

        {"schemeCode": 118955, 
         "schemeName": "HDFC Flexi Cap Direct Plan Growth",
           "Units": 250.589},

        {"schemeCode": 120334, 
         "schemeName": "ICICI Prudential Multi Asset Fund Direct Growth",
           "Units": 200.567}
    ]

    results = []
    total_portfolio_value = 0.0

    print("Fetching real-time data from AMFI...")

    for scheme in input_schemes:
        nav_info = fetch_nav_with_retry(scheme["schemeCode"])
        
        if nav_info:
            current_value = nav_info["nav"] * scheme["Units"]
            total_portfolio_value += current_value
            
            results.append({
                "Date": nav_info["date"],
                "Fund Name": scheme["schemeName"],
                "NAV": nav_info["nav"],
                "Units": scheme["Units"],
                "Investment": round(current_value, 2)
            })
        else:
            print(f"Error: Could not fetch data for {scheme['schemeName']}")

    # --- OUTPUT ---
    print("\n" + "="*80)
    print(f" TOTAL INVESTMENT VALUE: ₹{total_portfolio_value:,.2f}")
    print("="*80)
    
    # Header
    print(f"{'Date':<12} | {'Fund Name':<50} | {'NAV':<8} | {'Units':<10} | {'Investment':<12}")
    print("-" * 105)
    
    # Rows
    for r in results:
        print(f"{r['Date']:<12} | {r['Fund Name'][:50]:<50} | {r['NAV']:<8.2f} | {r['Units']:<10.3f} | ₹{r['Investment']:<12,.2f}")

if __name__ == "__main__":
    calculate_portfolio()

Using Excel or CSV file to store investment details 🔝


Excel file to store Scheme code name and number of units

Enhancing Scalability with External Data Inputs In the updated script below, we have replaced the hardcoded input_schemes variable with a dynamic data-loading process. By utilizing the Pandas library, specifically the read_excel() or read_csv() functions, the script now pulls your investment details directly from an external file named input_schemes.xlsx.

This approach offers two major advantages:
  1. Ease of Maintenance: You can update your portfolio, add new funds, or adjust your unit balances within Excel without ever touching the Python code.
  2. Versatility: While the example uses an Excel file, the script can be easily adapted to handle .csv files by simply swapping the method to read_csv().
Download sample Excel file

import requests
import json
import time
import pandas as pd
from datetime import datetime

def fetch_nav_with_retry(scheme_code):
    """
    Fetches the latest NAV for a given scheme code from the AMFI API.
    Implements exponential backoff for reliability.
    """
    api_url = f"https://api.mfapi.in/mf/{scheme_code}"
    retries = 5
    delay = 1
    
    for i in range(retries):
        try:
            response = requests.get(api_url, timeout=10)
            response.raise_for_status()
            data = response.json()
            
            # The API returns a list of NAVs, we take the most recent one (index 0)
            if "data" in data and len(data["data"]) > 0:
                latest_nav_data = data["data"][0]
                return {
                    "nav": float(latest_nav_data["nav"]),
                    "date": latest_nav_data["date"]
                }
            return None
        except (requests.RequestException, ValueError, KeyError):
            if i < retries - 1:
                time.sleep(delay)
                delay *= 2  # Exponential backoff
            else:
                return None

def calculate_portfolio():
    # --- LOAD DATA FROM FILE ---
    try:
        # Update filename here if needed. Using pd.read_csv for your uploaded file.
        #df = pd.read_csv('input_schemes.xlsx - Sheet1.csv')
        df = pd.read_excel('E:\\testing3\\input_schemes.xlsx', sheet_name='Sheet1')
        # Convert dataframe to a list of dictionaries to maintain the loop logic
        input_schemes = df.to_dict('records')
    except Exception as e:
        print(f"Error reading the file: {e}")
        return

    results = []
    total_portfolio_value = 0.0

    print(f"Fetching real-time data for {len(input_schemes)} funds from AMFI...")

    for scheme in input_schemes:
        # Note: Ensure keys match the column names in your CSV exactly
        nav_info = fetch_nav_with_retry(scheme["schemeCode"])
        
        if nav_info:
            current_value = nav_info["nav"] * scheme["Units"]
            total_portfolio_value += current_value
            
            results.append({
                "Date": nav_info["date"],
                "Fund Name": scheme["schemeName"],
                "NAV": nav_info["nav"],
                "Units": scheme["Units"],
                "Investment": round(current_value, 2)
            })
        else:
            print(f"Error: Could not fetch data for {scheme['schemeName']}")

    # --- OUTPUT ---
    print("\n" + "="*85)
    print(f" TOTAL PORTFOLIO VALUE: ₹{total_portfolio_value:,.2f}")
    print("="*85)
    
    # Header
    print(f"{'Date':<12} | {'Fund Name':<40} | {'NAV':<8} | {'Units':<10} | {'Value (₹)':<12}")
    print("-" * 95)
    
    # Rows
    for r in results:
        print(f"{r['Date']:<12} | {r['Fund Name'][:40]:<40} | {r['NAV']:<8.2f} | {r['Units']:<10.3f} | ₹{r['Investment']:<12,.2f}")

if __name__ == "__main__":
    calculate_portfolio()



AMFI NAV Data Resource

Official Mutual Fund Net Asset Value Portal

The AMFI NAV Download page provides the authoritative daily and historical pricing data required for portfolio valuation and financial analysis in India.

Daily Reports

Live end-of-day NAVs for all Open/Close-ended schemes.

Historical Data

Query price history for any specific date range up to 90 days.

Automated Sync

Standardized text formats (.txt) for easy integration into Excel or Python.

Verified Accuracy

The primary data source used by brokers and wealth platforms.

Technical Note

The data is usually updated by 9:00 PM IST every business day.

Access AMFI Portal
DATA FEED
Scheme Data Download

Access raw master data for all mutual fund schemes including scheme codes, types, and classification categories via the official AMFI portal.


Stock Data Logic

Curious how the stock prices are fetched in the background? Check out the Backend Data Logic for this monitor.

View Backend Fetching Logic




Python for Finance: Automate Mutual Fund Tracking & Portfolio Valuation

Upgrade to mftool Library

Ready to simplify your code? Learn how to use the mftool wrapper to fetch AMFI data even faster without manual API handling.


Mutual Fund NAV Tracker using Tkinter GUI

Subhendu Mohapatra — author at plus2net
Subhendu Mohapatra

Author

🎥 Join me live on YouTube

Passionate about coding and teaching, I publish practical tutorials on PHP, Python, JavaScript, SQL, and web development. My goal is to make learning simple, engaging, and project‑oriented with real examples and source code.



Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
©2000-2025   plus2net.com   All rights reserved worldwide Privacy Policy Disclaimer