Skip to content

Commit

Permalink
Merge pull request #26 from NayakwadiS/release/feature
Browse files Browse the repository at this point in the history
v2.2 resolved #23 #24 #25 and removed deprecated function get_mutual_fund_ranking
  • Loading branch information
NayakwadiS committed Aug 4, 2021
2 parents b68a97c + 75569ba commit 4d6ffa8
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 86 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.pytest_cache
*pyc
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2020 Sujit Nayakwadi
Copyright (c) 2021 Sujit Nayakwadi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ Features
* Getting list of all schemes with there Scheme codes.
* Get daily scheme performance.
* Cent percent unittest coverage.
* There are no external dependencies.

Documentation
====================================
Expand Down
4 changes: 2 additions & 2 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
The MIT License (MIT)
Copyright (c) 2020 Sujit Nayakwadi
Copyright (c) 2021 Sujit Nayakwadi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -21,5 +21,5 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
__VERSION__='1.1'
__VERSION__='2.2'
from .mftool import Mftool
98 changes: 28 additions & 70 deletions mftool.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,30 @@ def is_valid_code(self, code):
"""
if code:
# Performance improvement
# scheme_codes = self.get_scheme_codes()
# if code in scheme_codes.keys():
if code in self._scheme_codes:
return True
else:
return False
return True if code in self._scheme_codes else False
else:
return False

def is_holiday(self):
if date.today().strftime("%a") in ['Sat', 'Sun', 'Mon']:
return True
else:
return False

def get_friday(self):
days = {'Sat': 1, 'Sun': 2, 'Mon': 3}
diff = int(days[date.today().strftime("%a")])
return (date.today() - timedelta(days=diff)).strftime("%d-%b-%Y")

def get_today(self):
return (date.today() - timedelta(days=1)).strftime("%d-%b-%Y")

def render_response(self, data, as_json=False):
if as_json is True:
return json.dumps(data)
else:
return data

def get_scheme_quote(self, code, as_json=False):
"""
gets the quote for a given scheme code
Expand Down Expand Up @@ -193,12 +208,6 @@ def calculate_balance_units_value(self, code, balance_units, as_json=False):
else:
return None

def render_response(self, data, as_json=False):
if as_json is True:
return json.dumps(data)
else:
return data

def get_scheme_historical_nav_year(self, code, year, as_json=False):
"""
gets the scheme historical data of given year for a given scheme code
Expand Down Expand Up @@ -260,20 +269,6 @@ def get_scheme_historical_nav_for_dates(self, code, start_date, end_date, as_jso
else:
return None

def is_holiday(self):
if date.today().strftime("%a") in ['Sat', 'Sun', 'Mon']:
return True
else:
return False

def get_friday(self):
days = {'Sat': 1, 'Sun': 2, 'Mon': 3}
diff = int(days[date.today().strftime("%a")])
return (date.today() - timedelta(days=diff)).strftime("%d-%b-%Y")

def get_today(self):
return (date.today() - timedelta(days=1)).strftime("%d-%b-%Y")

def get_open_ended_equity_scheme_performance(self, as_json=False):
"""
gets the daily performance of open ended equity schemes for all AMCs
Expand All @@ -283,7 +278,7 @@ def get_open_ended_equity_scheme_performance(self, as_json=False):
scheme_performance = {}
for key in self._open_ended_equity_category.keys():
scheme_performance_url = self._get_open_ended_equity_scheme_url.replace('CAT',self._open_ended_equity_category[key])
scheme_performance[key] = self.get_daily_scheme_performance(scheme_performance_url, False)
scheme_performance[key] = self.get_daily_scheme_performance(scheme_performance_url)
return self.render_response(scheme_performance,as_json)

def get_open_ended_debt_scheme_performance(self, as_json=False):
Expand All @@ -296,7 +291,7 @@ def get_open_ended_debt_scheme_performance(self, as_json=False):
scheme_performance = {}
for key in self._open_ended_debt_category.keys():
scheme_performance_url = get_open_ended_debt_scheme_url.replace('CAT',self._open_ended_debt_category[key])
scheme_performance[key] = self.get_daily_scheme_performance(scheme_performance_url, False)
scheme_performance[key] = self.get_daily_scheme_performance(scheme_performance_url)
return self.render_response(scheme_performance,as_json)

def get_open_ended_hybrid_scheme_performance(self, as_json=False):
Expand All @@ -309,7 +304,7 @@ def get_open_ended_hybrid_scheme_performance(self, as_json=False):
scheme_performance = {}
for key in self._open_ended_hybrid_category.keys():
scheme_performance_url = get_open_ended_debt_scheme_url.replace('CAT',self._open_ended_hybrid_category[key])
scheme_performance[key] = self.get_daily_scheme_performance(scheme_performance_url, False)
scheme_performance[key] = self.get_daily_scheme_performance(scheme_performance_url)
return self.render_response(scheme_performance,as_json)

def get_open_ended_solution_scheme_performance(self, as_json=False):
Expand All @@ -323,7 +318,7 @@ def get_open_ended_solution_scheme_performance(self, as_json=False):
for key in self._open_ended_solution_category.keys():
scheme_performance_url = get_open_ended_solution_scheme_url.replace('CAT',
self._open_ended_solution_category[key])
scheme_performance[key] = self.get_daily_scheme_performance(scheme_performance_url, False)
scheme_performance[key] = self.get_daily_scheme_performance(scheme_performance_url)
return self.render_response(scheme_performance, as_json)

def get_open_ended_other_scheme_performance(self, as_json=False):
Expand All @@ -336,17 +331,17 @@ def get_open_ended_other_scheme_performance(self, as_json=False):
scheme_performance = {}
for key in self._open_ended_other_category.keys():
scheme_performance_url = get_open_ended_other_scheme_url.replace('CAT',self._open_ended_other_category[key])
scheme_performance[key] = self.get_daily_scheme_performance(scheme_performance_url, False)
scheme_performance[key] = self.get_daily_scheme_performance(scheme_performance_url)
return self.render_response(scheme_performance, as_json)

def get_daily_scheme_performance(self, performance_url,as_json):
def get_daily_scheme_performance(self, performance_url,as_json=False):
fund_performance = []
if self.is_holiday():
url = performance_url + '&nav-date=' + self.get_friday()
else:
url = performance_url + '&nav-date=' + self.get_today()
#html = requests.get(url,headers=self._user_agent)
html = httpx.get(url,headers=self._user_agent)
html = httpx.get(url,headers=self._user_agent,timeout=15)
soup = BeautifulSoup(html.text, 'html.parser')
rows = soup.select("table tbody tr")
try:
Expand Down Expand Up @@ -416,40 +411,3 @@ def get_average_aum(self,year_quarter,as_json=True):
all_funds_aum.append(aum_fund)
aum_fund = None
return self.render_response(all_funds_aum, as_json)

def get_mutual_fund_ranking(self, as_json):
"""
gets the daily CRICIL Ranking of all types of Mutual funds
:return: json / dict format
:raises: HTTPError, URLError
"""
response = self._session.get(url=self._get_fund_ranking, headers=self._user_agent).json()
schemes_data = response['docs']
scheme_category = {'ELSS': [], 'Focused Fund': [], 'Mid Cap Fund': ['None'], 'Large Cap Fund': [],
'Small Cap Fund': [],
'Large and Mid Cap Fund': [], 'Index Funds/ETFs': [], 'Multi Cap Fund': [],
'Banking and PSU Fund': [],
'Dynamic Bond Fund': [], 'Gilt Fund': [], 'Money Market Fund': [], 'Value/Contra Fund': [],
'Low Duration Fund': [], 'Medium Duration Fund': [], 'Medium to Long Duration Fund': [],
'Conservative Hybrid Fund': [], 'Credit Risk Fund': [], 'Ultra Short Duration Fund': [],
'Short Duration Fund': [], 'Liquid Fund': [], 'Arbitrage Fund': []
}

for scheme in schemes_data:
scheme_info = {}
if scheme['categoryName'] in scheme_category:
scheme_info['crisilRanking'] = scheme['crisilCprRanking']
scheme_info['category'] = scheme['categoryName']
scheme_info['type'] = scheme['invtype']
scheme_info['fund'] = scheme['fundName']
scheme_info['scheme'] = scheme['schemeName']
scheme_info['planName'] = scheme['planName']
scheme_info['3MonthReturn'] = scheme['scheme3MonthReturn']
scheme_info['6MonthReturn'] = scheme['scheme6MonthReturn']
scheme_info['1YearReturn'] = scheme['scheme1YearReturn']
if scheme['categoryName'] not in ['Short Duration Fund', 'Liquid Fund', 'Corporate Bond Fund',
'Arbitrage Fund', 'Ultra Short Duration Fund', 'Credit Risk Fund']:
scheme_info['3YearReturn'] = scheme['scheme3YearReturn']
scheme_category[scheme['categoryName']].append(scheme_info.copy())
scheme_info = None
return self.render_response(scheme_category, as_json)
18 changes: 9 additions & 9 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
from setuptools import setup, Extension ,find_packages
from setuptools import setup, Extension, find_packages
from os import path

this_directory = path.abspath(path.dirname(__file__))
with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
long_description = f.read()

setup(
name="mftool",
version="2.1",
author="Sujit Nayakwadi",
author_email="nayakwadi.sujit@gmail.com",
version="2.2",
author="Nayakwadi S",
author_email="nayakwadi_sujit@rediffmail.com",
description="Library for extracting real time Mutual funds data in India",
license="MIT",
keywords="amfi, quote, mutual-funds, funds, bse, nse, market, stock, stocks",
install_requires=['requests','bs4','httpx'],
install_requires=['requests', 'bs4', 'httpx'],
url="https://github.com/NayakwadiS/mftool",
packages=find_packages(),
long_description = long_description,
long_description_content_type='text/markdown',
package_data = {'': ['*.json']}
long_description=long_description,
long_description_content_type='text/markdown',
package_data={'': ['*.json']}
)
62 changes: 59 additions & 3 deletions tests/mftool_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import json
import six
from mftool import Mftool
from bs4 import BeautifulSoup

log = logging.getLogger('mftool')
logging.basicConfig(level=logging.DEBUG)
Expand Down Expand Up @@ -38,13 +37,16 @@ def test_get_scheme_quote(self):
code = '101305'
self.assertIsInstance(self.mftool.get_scheme_quote(code), dict)
# with json respomftool
self.assertIsInstance(self.mftool.get_scheme_quote(code, as_json=True),str)
self.assertIsInstance(self.mftool.get_scheme_quote(code, as_json=True), str)
# with wrong code
code = 'wrong code'
self.assertIsNone(self.mftool.get_scheme_quote(code))
# with code in 'int' format
code = 101305
self.assertIsInstance(self.mftool.get_scheme_quote(code), dict)
# verify data present
result = self.mftool.get_scheme_quote(code)
self.assertIsNotNone(result)

def test_get_scheme_historical_nav(self):
code = '101305'
Expand All @@ -57,6 +59,9 @@ def test_get_scheme_historical_nav(self):
# with code in 'int' format
code = 101305
self.assertIsInstance(self.mftool.get_scheme_historical_nav(code), dict)
# verify data present
result = self.mftool.get_scheme_historical_nav(code)
self.assertIsNotNone(result)

def test_get_scheme_details(self):
code = '101305'
Expand All @@ -69,9 +74,60 @@ def test_get_scheme_details(self):
# with code in 'int' format
code = 101305
self.assertIsInstance(self.mftool.get_scheme_details(code), dict)
# verify data present
result = self.mftool.get_scheme_details(code)
self.assertIsNotNone(result)

# TODO: test calculate_balance_units_value
def test_calculate_balance_units_value(self):
code = '101305'
result = self.mftool.calculate_balance_units_value(code, 221)
self.assertIsNotNone(result)

def test_get_scheme_historical_nav_year(self):
code = '101305'
self.assertIsInstance(self.mftool.get_scheme_historical_nav_year(code, 2018), dict)
# with json respomftool
self.assertIsInstance(self.mftool.get_scheme_historical_nav_year(code, 2018, as_json=True), str)
# with wrong code
code = 'wrong code'
self.assertIsNone(self.mftool.get_scheme_historical_nav_year(code, 2018))
# with code in 'int' format
code = 101305
self.assertIsInstance(self.mftool.get_scheme_historical_nav_year(code, 2018), dict)
# verify data present
result = self.mftool.get_scheme_historical_nav_year(code, 2018)
self.assertIsNotNone(result)

def test_get_day(self):
if self.mftool.is_holiday():
self.assertTrue((self.mftool.get_friday()))
else:
self.assertTrue((self.mftool.get_today()))

def test_get_scheme_historical_nav_for_dates(self):
code = '101305'
self.assertIsInstance(self.mftool.get_scheme_historical_nav_for_dates(code,'1-1-2018','31-12-2018'), dict)
# with json respomftool
self.assertIsInstance(self.mftool.get_scheme_historical_nav_for_dates(code,'1-1-2018','31-12-2018', as_json=True), str)
# with wrong code
code = 'wrong code'
self.assertIsNone(self.mftool.get_scheme_historical_nav_for_dates(code,'1-1-2018','31-12-2018'))
# with code in 'int' format
code = 101305
self.assertIsInstance(self.mftool.get_scheme_historical_nav_for_dates(code,'1-1-2018','31-12-2018'), dict)
# verify data present
result = self.mftool.get_scheme_historical_nav_for_dates(code,'1-1-2018','31-12-2018')
self.assertIsNotNone(result)

def test_get_open_ended_equity_scheme_performance(self):
self.assertIsInstance(self.mftool.get_open_ended_equity_scheme_performance(False), dict)
# verify data present
result = self.mftool.get_open_ended_equity_scheme_performance(False)
self.assertNotEqual(result,{'Large Cap': [],'Large & Mid Cap': [],'Multi Cap': [],'Mid Cap': [],
'Small Cap': [],'Value': [],'ELSS': [],'Contra': [],'Dividend Yield': [],
'Focused': []})

# ToDO : Add remaining test

if __name__ == '__main__':
unittest.main()

0 comments on commit 4d6ffa8

Please sign in to comment.