Getting Mutual Funds Net Asset Value via Python using mftools API

Getting Mutual Funds Net Asset Value via Python using mftools API

Net Asset Value (NAV) is one of the most fundamental data points when it comes to the Mutual Funds industry. Today we will learn about NAV and how to fetch NAV details in python using mftools API.

**Net Asset Value(NAV) **is the market value of all assets less any liabilities divided by the total shares outstanding of the fund. This figure is published daily by Association of Mutual Funds in India (AMFI) in India. You might have heard the tagline somewhere "Mutual Funds Sahi Hai", Yes, that's by AMFI.

Coming back to calculation of NAV:
\[ NAV = (Assets - Liabilities) / Total_Outstanding_Shares \]

Daily change in NAV of a mutual fund scheme indicates a rise or dip in the scheme's assets. While NAV helps us to analyze how the mutual fund performs daily, it does not indicate how lucrative a fund is, i.e., a fund with higher NAV is not superior to a fund with lower NAV, it is quite just possible that the fund with Higher NAV has less outstanding shares than the fund with lower NAV.

Economic Times has summarized NAV in a good article here. You can collect NAV to build your own database of mutual fund prices, you can then wish to analyze this data over a certain time period which can tell you about the performance of a certain mutual fund.

Let’s look at the Python Implementation Now

Installing the necessary Library.

As we mentioned, we will be using the open-source mftool library, which is basically a wrapper to scrape data from the AMFIs website in a very easy-to-use manner.

You can install mftool via pip install mftool in your Anaconda prompt.

Making the Necessary Imports

import pandas as pd
from mftool import Mftool

The documentation of the API can be found by clicking here.

In the next step, we will initialize an instance of the API and use the function get_scheme_codes to get all available scheme codes in India right now. If you are confused, scheme_code is basically a unique code assigned by AMFI to each and every Mutual Fund scheme.

mf = Mftool()
scheme_codes = mf.get_scheme_codes()

Screen Shot 2021-05-11 at 2.14.07 PM.png

Note:- The output of this code snippet will be in dictionary format, so we will further take the keys from the output.

Taking only keys from the dictionary as our next function only requires the scheme_code and not scheme_name

scheme_code_list = [x for x in scheme_codes.keys()]
#the above is list comprehension which is a 
#much efficient way of creating lists.

Screen Shot 2021-05-11 at 2.17.14 PM.png

Before we go and start collecting this data in a loop for all scheme codes, let's see how we can use the function get_scheme_historical_nav_for_dates to fetch data for AMFI code 119551 between dates 01-01-2021 and 11-05-2021

nav_data = mf.get_scheme_historical_nav_for_dates('119551', '01-01-2021', '11-05-2021')


Did you notice, how simple this was? It's amazing; you do not have to directly deal with the AMFI website; just call the function and job done. Let's now build our own function, HistoricalNav, which will take a list of scheme codes, to & from date, and return a dataframe with all price information.

If you prefer, you can directly skip to the Google Collab Notebook by clicking here.

Let us learn some keywords before entering the code:-

  1. **Assert:- **Used when debugging the code. Raises an assertion value error message if the assertion is false. It is very similar to try and except in python error handling.

  2. Series:- A Pandas Series is like a column in a table. It is a one-dimensional array holding data of any type.

def HistoricalNav(scheme_code_list, start_date, end_date):
  # Assert keyword is a debugging tool.
  # Below assert keyword check whehther the scheme_code_list is a list and it is present, if not it raises an assertion failure message.
  assert (isinstance(scheme_code_list, list) is True), "Arguement scheme_code_list should be a list" 
  assert (isinstance(start_date, str) is True), "start_date must be a str in %d-%m-%Y format" # checks whether start date is present and is in correct format.
  assert (isinstance(end_date, str) is True), "end_date must be a str in %d-%m-%Y format" # checks whether end date is present and is in correct format

  main_df = pd.DataFrame() #empty dataframe

  for schemes in scheme_code_list:
    data = mf.get_scheme_historical_nav_for_dates(schemes, start_date, end_date) # requesting NAV data from the api.

    df = pd.DataFrame(data['data']) 
    df['scheme_code'] = pd.Series([data['scheme_code'] for x in range(len(df.index))]) #adding Pandas Series(scheme_code) as a column in Pandas Dataframe.
    df['scheme_name'] = pd.Series([data['scheme_name'] for x in range(len(df.index))]) #adding Pandas Series(scheme_name) as a column in Pandas Dataframe.

    df = df.sort_values(by = 'date') # sorting the values of every Scheme code based on Date

    main_df = main_df.append(df) # appending the data in the main_df dataframe.

  main_df = main_df[['scheme_code', 'scheme_name', 'date', 'nav']] #creating names of dataframe columns 
  main_df.reset_index(drop = True, inplace = True) 

  return main_df #Returning the required Dataframe.

The NAV_Data returns the data frame by checking if the values are present or not. For example when it encounters a day when the market was closed. It returns the latest Value of NAV when the market last opened.

# Function to return NAV data 
def NAV_Data(start,end): 
    values_df = HistoricalNav(scheme_code_list = scheme_code_list[0:5], start_date= start, end_date= end) #to get the data
    return values_df
  except KeyError:
    #if the data is not available on that date, going on previous date to get latest data 
    start=datetime.strptime(start, '%d-%m-%Y') - timedelta(1) # gets to previous day where the data is available.
    return NAV_Data(start.strftime("%d-%m-%Y"),end) #returns the required data.

We will call this function and save the output in a variable.

# Calling the function and saving the output in a variable.
# To get the latest NAV set the start_date and end_date as the last traded date in 'dd/mm/yyyy' format.
# Note:- To get data of a particular date, enter same start_date and end_date. 
start_date= "01-05-2021" # enter the date in "dd-mm-yyyy" format
end_date = "10-05-2021" # enter the date in "dd-mm-yyyy" format
values_df = NAV_Data(start_date,end_date) #calling function NAV_Data

The Output of the function will be the data frame.

Screen Shot 2021-05-11 at 2.52.36 PM.png

Note:- Here, I have used only 5 scheme codes to show the output.

If we want NAV for a single scheme code from the above data frame:-

values_df[values_df['scheme_code'] == 119552]

Screen Shot 2021-05-11 at 2.24.07 PM.png

Pro Tip: To get the latest NAV set the start_date and end_date as the last traded date in 'DD-MM-YYYY' format in the HistoricalNav function itself.

We have also uploaded the whole code on Github in the tradewithpython-blogs repository. You can access the .py file for this article by clicking here.

That's it. I hope you like the content. Constructive criticism is appreciated.

Feel free to reach out to me on Linkedin if you have any suggestions about the blog, you can use the Feedback widget on the right hand of your screen, and if you wish to Contact Us, you can fill in the form here.

Please note we haven't made any new posts since Nov 2021 on this blog, you are free to subscribe to the mailing list, however, you will be auto-added to the new blog's ( mailing list as well.

P.s- We hope to connect with you via LinkedIn or any social media platform to discuss ideas, and feel free to subscribe to the newsletter. If you liked this article, you could also buy me a book to show some appreciation. 😇

Did you find this article valuable?

Support Trade With Python by becoming a sponsor. Any amount is appreciated!