mftool 2.8__tar.gz → 3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mftool
3
- Version: 2.8
3
+ Version: 3.0
4
4
  Summary: Library for getting real time Mutual funds info
5
5
  Home-page: https://github.com/NayakwadiS/mftool
6
6
  Author: SujitN
7
7
  Author-email: nayakwadi_sujit@rediffmail.com
8
8
  License: MIT
9
- Description: mftool is a library for getting real time Mutual Funds data in India. It can be used in various types of projects which requires getting live quotes for a given mutual fund scheme or build large data sets for further data analytics.
9
+ Description: mftool is a library getting publicly available Mutual Funds data in India. It can be used in various types of projects which requires getting live quotes for a given mutual fund scheme or build large data sets for further data analytics.
10
10
 
11
11
  Features
12
12
  =============
@@ -1,4 +1,4 @@
1
- mftool is a library for getting real time Mutual Funds data in India. It can be used in various types of projects which requires getting live quotes for a given mutual fund scheme or build large data sets for further data analytics.
1
+ mftool is a library getting publicly available Mutual Funds data in India. It can be used in various types of projects which requires getting live quotes for a given mutual fund scheme or build large data sets for further data analytics.
2
2
 
3
3
  Features
4
4
  =============
@@ -1,7 +1,7 @@
1
1
  """
2
2
  The MIT License (MIT)
3
3
 
4
- Copyright (c) 2024 Sujit Nayakwadi
4
+ Copyright (c) 2025 Sujit Nayakwadi
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  of this software and associated documentation files (the "Software"), to deal
@@ -21,5 +21,5 @@
21
21
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  SOFTWARE.
23
23
  """
24
- __VERSION__='2.8'
24
+ __VERSION__='3.0'
25
25
  from .mftool import Mftool
@@ -2,58 +2,60 @@
2
2
  "get_quote_url": "https://www.amfiindia.com/spages/NAVAll.txt",
3
3
  "get_scheme_url": "https://api.mfapi.in/mf/",
4
4
  "get_amc_details_url": "https://www.amfiindia.com/modules/AMCProfileDetail",
5
- "get_open_ended_equity_scheme_url": "http://www.valueresearchonline.com/amfi/fund-performance-data/?end-type=1&primary-category=SEQ&category=CAT&amc=ALL",
5
+ "get_open_ended_equity_scheme_url": "https://www.amfiindia.com/gateway/pollingsebi/api/amfi/fundperformance",
6
6
  "get_avg_aum_url": "https://www.amfiindia.com/modules/AverageAUMDetails",
7
7
  "user_agent": {
8
8
  "User-Agent": "Chrome/95.0.4638.69"
9
9
  },
10
10
  "open_ended_equity_category": {
11
- "Large Cap": "SEQ_LC",
12
- "Large & Mid Cap": "SEQ_LMC",
13
- "Multi Cap": "SEQ_MLC",
14
- "Mid Cap": "SEQ_MC",
15
- "Small Cap": "SEQ_SC",
16
- "Value": "SEQ_VAL",
17
- "ELSS": "SEQ_ELSS",
18
- "Contra": "SEQ_CONT",
19
- "Dividend Yield": "SEQ_DIVY",
20
- "Focused": "SEQ_FOC"
11
+ "1": "Large Cap",
12
+ "2": "Large & Mid Cap",
13
+ "3": "Flexi Cap",
14
+ "4": "Multi Cap",
15
+ "5": "Mid Cap",
16
+ "6": "Small Cap",
17
+ "7": "Value",
18
+ "8": "ELSS",
19
+ "9": "Contra",
20
+ "10": "Dividend Yield",
21
+ "11": "Focused",
22
+ "12": "Sectoral / Thematic"
21
23
  },
22
24
  "open_ended_debt_category": {
23
- "Long Duration": "SDT_LND",
24
- "Medium to Long Duration": "SDT_MLD",
25
- "Medium Duration": "SDT_MD",
26
- "Short Duration": "SDT_SD",
27
- "Low Duration": "SDT_LWD",
28
- "Ultra Short Duration": "SDT_USD",
29
- "Liquid": "SDT_LIQ",
30
- "Money Market": "SDT_MM",
31
- "Overnight": "SDT_OVNT",
32
- "Dynamic Bond": "SDT_DB",
33
- "Corporate Bond": "SDT_CB",
34
- "Credit Risk": "SDT_CR",
35
- "Banking and PSU": "SDT_BPSU",
36
- "Floater": "SDT_FL",
37
- "FMP": "SDT_FMP",
38
- "Gilt": "SDT_GL",
39
- "Gilt with 10 year constant duration": "SDT_GL10CD"
25
+ "13":"Long Duration",
26
+ "14":"Medium to Long Duration",
27
+ "16":"Medium Duration",
28
+ "15":"Short Duration",
29
+ "18":"Low Duration",
30
+ "19":"Ultra Short Duration",
31
+ "20":"Liquid",
32
+ "17":"Money Market",
33
+ "21":"Overnight",
34
+ "22":"Dynamic Bond",
35
+ "23":"Corporate Bond",
36
+ "24":"Credit Risk",
37
+ "25":"Banking and PSU",
38
+ "26":"Floater",
39
+ "27":"FMP",
40
+ "28":"Gilt",
41
+ "29":"Gilt with 10 year constant duration"
40
42
  },
41
43
  "open_ended_hybrid_category": {
42
- "Aggressive Hybrid": "SHY_AH",
43
- "Balanced Hybrid": "SHY_BH",
44
- "Conservative Hybrid": "SHY_CH",
45
- "Equity Savings": "SHY_EQS",
46
- "Arbitrage": "SHY_AR",
47
- "Multi Asset Allocation": "SHY_MAA"
44
+ "30":"Aggressive Hybrid",
45
+ "40":"Balanced Hybrid",
46
+ "31":"Conservative Hybrid",
47
+ "32":"Equity Savings",
48
+ "33":"Arbitrage",
49
+ "34":"Multi Asset Allocation"
48
50
  },
49
51
  "open_ended_solution_category": {
50
- "Children's": "SSO_CHILD",
51
- "Retirement": "SSO_RETR"
52
+ "36":"Children's",
53
+ "37":"Retirement"
52
54
 
53
55
  },
54
56
  "open_ended_other_category": {
55
- "Index Funds/ETFs": "SOTH_IXETF",
56
- "FoFs(Oversease/Domestic)": "SOTH_FOFS"
57
+ "38":"Index Funds/ETFs",
58
+ "39":"FoFs(Oversease/Domestic)"
57
59
 
58
60
  },
59
61
  "amc": [3, 53, 1, 4, 59, 46, 32, 6, 47, 54, 27, 9, 37, 20, 57, 48, 68, 62, 65, 63, 42, 70, 16, 17, 56, 18, 69, 45, 55, 21, 58, 64, 10, 13, 35,
@@ -20060,4 +20062,4 @@
20060
20062
  }, {
20061
20063
  "0P00019W5W": "Indiabulls Blue Chip Fund Direct Plan Quarterly Dividend Payout Option"
20062
20064
  }]
20063
- }
20065
+ }
@@ -1,6 +1,6 @@
1
1
  """
2
2
  The MIT License (MIT)
3
- Copyright (c) 2024 Sujit Nayakwadi
3
+ Copyright (c) 2025 Sujit Nayakwadi
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to deal
6
6
  in the Software without restriction, including without limitation the rights
@@ -24,7 +24,9 @@ from bs4 import BeautifulSoup
24
24
  import yfinance as yf
25
25
  import datetime
26
26
  from deprecated import deprecated
27
+ from matplotlib import pyplot as plt
27
28
  from .utils import Utilities, is_holiday, get_today, get_friday, render_response
29
+ import pandas as pd
28
30
 
29
31
 
30
32
  class Mftool:
@@ -173,7 +175,6 @@ class Mftool:
173
175
  scheme_info = {}
174
176
  url = self._get_scheme_url + code
175
177
  response = self._session.get(url).json()
176
-
177
178
  scheme_data = response['meta']
178
179
  scheme_info['fund_house'] = scheme_data['fund_house']
179
180
  scheme_info['scheme_type'] = scheme_data['scheme_type']
@@ -236,58 +237,25 @@ class Mftool:
236
237
  else:
237
238
  return None
238
239
 
239
- @deprecated(version='2.7',
240
- reason="This function will be in deprecated from next release, use mf.history() to get data")
241
- def get_scheme_historical_nav_year(self, code, year, as_json=False):
242
- """
243
- gets the scheme historical data of given year for a given scheme code
244
- :param code: scheme-code
245
- :param year: year
246
- :param as_json: default false
247
- :return: dict or None
248
- :raises: HTTPError, URLError
249
- """
250
- code = str(code)
251
- if self.is_valid_code(code):
252
- scheme_info = {}
253
- data = []
254
- url = self._get_scheme_url + code
255
- response = self._session.get(url).json()
256
- nav = self.get_scheme_historical_nav(code)
257
- scheme_info = self.get_scheme_details(code)
258
- for dat in nav['data']:
259
- navDate = dat['date']
260
- d = datetime.datetime.strptime(navDate, '%d-%m-%Y')
261
- if d.year == int(year):
262
- data.append(dat)
263
- if len(data) == 0:
264
- data.append({'Error': 'For Year '+str(year)+' Data is NOT available'})
265
-
266
- scheme_info.update(data=data)
267
- return render_response(scheme_info, as_json)
268
- else:
269
- return None
270
-
271
- @deprecated(version='2.7',
240
+ @deprecated(version='3.1',
272
241
  reason="This function will be in deprecated from next release, use mf.history() to get data")
273
- def get_scheme_historical_nav_for_dates(self, code, start_date, end_date, as_json=False):
242
+ def get_scheme_historical_nav_for_dates(self, code, start_date, end_date, as_json=False, as_dataframe=False):
274
243
  """
275
244
  gets the scheme historical data between start_date and end_date for a given scheme code
276
245
  :param start_date: string '%Y-%m-%d'
277
246
  :param end_date: string '%Y-%m-%d'
278
247
  :param code: scheme code
279
248
  :param as_json: default false
249
+ :param as_dataframe: default false
280
250
  :return: dict or None
281
251
  :raises: HTTPError, URLError
282
252
  """
283
253
  code = str(code)
284
254
  if self.is_valid_code(code):
285
- scheme_info = {}
255
+ # scheme_info = {}
286
256
  data = []
287
257
  start_date = datetime.datetime.strptime(start_date, '%d-%m-%Y').date()
288
258
  end_date = datetime.datetime.strptime(end_date, '%d-%m-%Y').date()
289
- url = self._get_scheme_url + code
290
- response = self._session.get(url).json()
291
259
  nav = self.get_scheme_historical_nav(code)
292
260
  scheme_info = self.get_scheme_details(code)
293
261
  for dat in nav['data']:
@@ -299,114 +267,107 @@ class Mftool:
299
267
  data.append({'Data is NOT available for selected range'})
300
268
 
301
269
  scheme_info.update(data=data)
302
- return render_response(scheme_info, as_json)
270
+ return render_response(scheme_info, as_json, as_dataframe)
303
271
  else:
304
272
  return None
305
273
 
306
- def get_open_ended_equity_scheme_performance(self, as_json=False):
274
+ def get_open_ended_equity_scheme_performance(self, report_date=None,as_json=False):
307
275
  """
308
276
  gets the daily performance of open-ended equity schemes for all AMCs
277
+ :param report_date: date in 'DD-MMM-YYYY' format, if None then it will take last working day
309
278
  :return: json format
310
279
  :raises: HTTPError, URLError
311
280
  """
312
281
  scheme_performance = {}
313
- for key in self._open_ended_equity_category.keys():
314
- scheme_performance_url = self._get_open_ended_equity_scheme_url.replace('CAT', self._open_ended_equity_category[key])
315
- scheme_performance[key] = self._get_daily_scheme_performance(scheme_performance_url)
282
+ subCategory = self._open_ended_equity_category
283
+ for key in subCategory:
284
+ scheme_performance[subCategory[key]] = self._get_daily_scheme_performance(self._get_open_ended_equity_scheme_url,report_date,1, key)
316
285
  return render_response(scheme_performance, as_json)
317
286
 
318
- def get_open_ended_debt_scheme_performance(self, as_json=False):
287
+ def get_open_ended_debt_scheme_performance(self, report_date=None, as_json=False):
319
288
  """
320
289
  gets the daily performance of open-ended debt schemes for all AMCs
290
+ :param report_date: date in 'DD-MMM-YYYY' format, if None then it will take last working day
321
291
  :return: json format
322
292
  :raises: HTTPError, URLError
323
293
  """
324
- get_open_ended_debt_scheme_url = self._get_open_ended_equity_scheme_url.replace('SEQ', 'SDT')
294
+ subCategory = self._open_ended_debt_category
325
295
  scheme_performance = {}
326
- for key in self._open_ended_debt_category.keys():
327
- scheme_performance_url = get_open_ended_debt_scheme_url.replace('CAT', self._open_ended_debt_category[key])
328
- scheme_performance[key] = self._get_daily_scheme_performance(scheme_performance_url)
296
+ for key in subCategory:
297
+ scheme_performance[subCategory[key]] = self._get_daily_scheme_performance(self._get_open_ended_equity_scheme_url,report_date,2,key)
329
298
  return render_response(scheme_performance, as_json)
330
299
 
331
- def get_open_ended_hybrid_scheme_performance(self, as_json=False):
300
+ def get_open_ended_hybrid_scheme_performance(self, report_date=None, as_json=False):
332
301
  """
333
302
  gets the daily performance of open-ended hybrid schemes for all AMCs
303
+ :param report_date: date in 'DD-MMM-YYYY' format, if None then it will take last working day
334
304
  :return: json format
335
305
  :raises: HTTPError, URLError
336
306
  """
337
- get_open_ended_debt_scheme_url = self._get_open_ended_equity_scheme_url.replace('SEQ', 'SHY')
307
+ subCategory = self._open_ended_hybrid_category
338
308
  scheme_performance = {}
339
- for key in self._open_ended_hybrid_category.keys():
340
- scheme_performance_url = get_open_ended_debt_scheme_url.replace('CAT',self._open_ended_hybrid_category[key])
341
- scheme_performance[key] = self._get_daily_scheme_performance(scheme_performance_url)
309
+ for key in subCategory:
310
+ scheme_performance[subCategory[key]] = self._get_daily_scheme_performance(
311
+ self._get_open_ended_equity_scheme_url,report_date, 3, key)
342
312
  return render_response(scheme_performance, as_json)
343
313
 
344
- def get_open_ended_solution_scheme_performance(self, as_json=False):
314
+ def get_open_ended_solution_scheme_performance(self, report_date=None, as_json=False):
345
315
  """
346
316
  gets the daily performance of open-ended Solution-Oriented schemes for all AMCs
317
+ :param report_date: date in 'DD-MMM-YYYY' format, if None then it will take last working day
347
318
  :return: json format
348
319
  :raises: HTTPError, URLError
349
320
  """
350
- get_open_ended_solution_scheme_url = self._get_open_ended_equity_scheme_url.replace('SEQ', 'SSO')
321
+ subCategory = self._open_ended_solution_category
351
322
  scheme_performance = {}
352
- for key in self._open_ended_solution_category.keys():
353
- scheme_performance_url = get_open_ended_solution_scheme_url.replace('CAT',
354
- self._open_ended_solution_category[key])
355
- scheme_performance[key] = self._get_daily_scheme_performance(scheme_performance_url)
323
+ for key in subCategory:
324
+ scheme_performance[subCategory[key]] = self._get_daily_scheme_performance(
325
+ self._get_open_ended_equity_scheme_url, report_date,4, key)
356
326
  return render_response(scheme_performance, as_json)
357
327
 
358
- def get_open_ended_other_scheme_performance(self, as_json=False):
328
+ def get_open_ended_other_scheme_performance(self, report_date=None, as_json=False):
359
329
  """
360
330
  gets the daily performance of open-ended index and FoF schemes for all AMCs
331
+ :param report_date: date in 'DD-MMM-YYYY' format, if None then it will take last working day
361
332
  :return: json format
362
333
  :raises: HTTPError, URLError
363
334
  """
364
- get_open_ended_other_scheme_url = self._get_open_ended_equity_scheme_url.replace('SEQ', 'SOTH')
335
+ subCategory = self._open_ended_other_category
365
336
  scheme_performance = {}
366
- for key in self._open_ended_other_category.keys():
367
- scheme_performance_url = get_open_ended_other_scheme_url.replace('CAT', self._open_ended_other_category[key])
368
- scheme_performance[key] = self._get_daily_scheme_performance(scheme_performance_url)
337
+ for key in subCategory:
338
+ scheme_performance[subCategory[key]] = self._get_daily_scheme_performance(
339
+ self._get_open_ended_equity_scheme_url, report_date,5, key)
369
340
  return render_response(scheme_performance, as_json)
370
341
 
371
- def _get_daily_scheme_performance(self, performance_url, as_json=False):
342
+ def _get_daily_scheme_performance(self, performance_url,report_date, category,key, as_json=False):
372
343
  fund_performance = []
373
- if is_holiday():
374
- url = performance_url + '&nav-date=' + get_friday()
375
- else:
376
- url = performance_url + '&nav-date=' + get_today()
377
- # html = requests.get(url, headers=self._user_agent)
378
- html = httpx.get(url, headers=self._user_agent,timeout=25)
379
- soup = BeautifulSoup(html.text, 'html.parser')
380
- rows = soup.select("table tbody tr")
344
+ if not report_date:
345
+ if is_holiday():
346
+ report_date = get_friday()
347
+ else:
348
+ report_date = get_today()
381
349
  try:
382
- for tr in rows:
350
+ data = {"maturityType": 1,"category": category,"subCategory": int(key),"mfid": 0,"reportDate": report_date}
351
+ html = httpx.post(performance_url,headers={"User-Agent":"Mozilla/5.0"},timeout=25, json=data)
352
+ for result in html.json()['data']:
383
353
  scheme_details = {}
384
- cols = tr.select("td.nav.text-right")
385
- scheme_details['scheme_name'] = tr.select("td")[0].get_text()
386
- scheme_details['benchmark'] = tr.select("td")[1].get_text()
387
-
388
- scheme_details['latest NAV- Regular'] = tr.select("td")[2].get_text().strip()
389
- scheme_details['latest NAV- Direct'] = tr.select("td")[3].get_text().strip()
390
-
391
- regData = tr.find_all("td", recursive=False,class_="text-right period-return-reg", limit=1)
392
- dirData = tr.find_all("td", recursive=False, class_="text-right period-return-dir", limit=1)
393
-
394
- scheme_details['1-Year Return(%)- Regular'] = regData[0]['data-1y']
395
- scheme_details['1-Year Return(%)- Direct'] = dirData[0]['data-1y']
396
-
397
- scheme_details['3-Year Return(%)- Regular'] = regData[0]['data-3y']
398
- scheme_details['3-Year Return(%)- Direct'] = dirData[0]['data-3y']
399
-
400
- scheme_details['5-Year Return(%)- Regular'] = regData[0]['data-5y']
401
- scheme_details['5-Year Return(%)- Direct'] = dirData[0]['data-5y']
402
-
354
+ scheme_details['scheme_name'] = result['schemeName']
355
+ scheme_details['benchmark'] = result['benchmark']
356
+ scheme_details['latest NAV- Regular'] = result['navRegular']
357
+ scheme_details['latest NAV- Direct'] = result['navDirect']
358
+ scheme_details['1-Year Return(%)- Regular'] = result['return1YearRegular']
359
+ scheme_details['1-Year Return(%)- Direct'] = result['return1YearDirect']
360
+ scheme_details['3-Year Return(%)- Regular'] = result['return3YearRegular']
361
+ scheme_details['3-Year Return(%)- Direct'] = result['return3YearDirect']
362
+ scheme_details['5-Year Return(%)- Regular'] = result['return5YearRegular']
363
+ scheme_details['5-Year Return(%)- Direct'] = result['return5YearDirect']
403
364
  fund_performance.append(scheme_details)
404
-
405
365
  except Exception:
406
366
  return render_response(['The underlying data is unavailable for Today'], as_json)
407
-
408
367
  return render_response(fund_performance, as_json)
409
368
 
369
+ @deprecated(version='3.1',
370
+ reason="This function will be in deprecated from next release")
410
371
  def get_all_amc_profiles(self, as_json=True):
411
372
  """
412
373
  gets profiles for all Fund houses
@@ -476,7 +437,7 @@ class Mftool:
476
437
  code = str(code)
477
438
  if self.is_code(code):
478
439
  def get_Dataframe(df, as_dataframe):
479
- df = df.drop(columns=['Open', 'High', 'Low','Adj Close','Volume'])
440
+ df = df.drop(columns=['Open', 'High', 'Low','Volume'])
480
441
  df = df.rename(columns={'Close': 'nav'})
481
442
  df['dayChange'] = df['nav'].diff()
482
443
  df = df.rename_axis('date')
@@ -510,3 +471,31 @@ class Mftool:
510
471
  mf = yf.Ticker(code)
511
472
  response = mf.info
512
473
  return render_response(response, as_json)
474
+
475
+ def compare_trend(self, codes, start_date, end_date):
476
+ """
477
+ plot and Compare trend of mutual funds
478
+ :param start_date: string '%Y-%m-%d'
479
+ :param end_date: string '%Y-%m-%d'
480
+ :param code: scheme code
481
+ :param as_json: default false
482
+ :param as_dataframe: default false
483
+ :return: dict or None
484
+ :raises: HTTPError, URLError
485
+ """
486
+ all_mf = pd.DataFrame()
487
+ for code in codes:
488
+ mf_data = self.get_scheme_historical_nav_for_dates(code, start_date, end_date, as_dataframe=True)
489
+ mf_data = mf_data.drop(columns=['dayChange'])
490
+ mf_name = self.get_scheme_details(code)['scheme_name']
491
+ mf_data[mf_name] = mf_data['nav'].astype(float)
492
+ mf_data['date'] = mf_data.index
493
+ all_mf[mf_name] = mf_data[mf_name]
494
+ all_mf['date'] = mf_data['date']
495
+
496
+ all_mf = all_mf[::-1]
497
+ all_mf.plot(x='date')
498
+ plt.title("Compare mutual funds")
499
+ plt.xlabel("Date")
500
+ plt.ylabel("NAV")
501
+ plt.show()
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mftool
3
- Version: 2.8
3
+ Version: 3.0
4
4
  Summary: Library for getting real time Mutual funds info
5
5
  Home-page: https://github.com/NayakwadiS/mftool
6
6
  Author: SujitN
7
7
  Author-email: nayakwadi_sujit@rediffmail.com
8
8
  License: MIT
9
- Description: mftool is a library for getting real time Mutual Funds data in India. It can be used in various types of projects which requires getting live quotes for a given mutual fund scheme or build large data sets for further data analytics.
9
+ Description: mftool is a library getting publicly available Mutual Funds data in India. It can be used in various types of projects which requires getting live quotes for a given mutual fund scheme or build large data sets for further data analytics.
10
10
 
11
11
  Features
12
12
  =============
@@ -3,4 +3,4 @@ bs4
3
3
  httpx
4
4
  pandas
5
5
  yfinance
6
- Deprecated
6
+ matplotlib
@@ -7,13 +7,13 @@ with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
7
7
 
8
8
  setup(
9
9
  name="mftool",
10
- version="2.8",
10
+ version="3.0",
11
11
  author="SujitN",
12
12
  author_email="nayakwadi_sujit@rediffmail.com",
13
13
  description="Library for getting real time Mutual funds info",
14
14
  license="MIT",
15
15
  keywords="amfi, quote, mutual-funds, funds, bse, nse, market, stock, stocks",
16
- install_requires=['requests', 'bs4', 'httpx','pandas','yfinance','Deprecated'],
16
+ install_requires=['requests', 'bs4', 'httpx', 'pandas', 'yfinance', 'matplotlib'],
17
17
  url="https://github.com/NayakwadiS/mftool",
18
18
  packages=find_packages(),
19
19
  long_description=long_description,
File without changes
File without changes
File without changes
File without changes