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
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
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()
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_code_list = [x for x in scheme_codes.keys()] #the above is list comprehension which is a #much efficient way of creating lists.
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
nav_data = mf.get_scheme_historical_nav_for_dates('119551', '01-01-2021', '11-05-2021') nav_data
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:-
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.
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.
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): try: 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 values_df
The Output of the function will be the data frame.
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]
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.
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. 😇