Skip to content

Commit

Permalink
new version
Browse files Browse the repository at this point in the history
  • Loading branch information
debpal committed Oct 2, 2024
1 parent c3288ea commit 3cf34f4
Show file tree
Hide file tree
Showing 15 changed files with 319 additions and 56 deletions.
4 changes: 3 additions & 1 deletion BharatFinTrack/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from .nse_product import NSEProduct
from .nse_index import NSEIndex
from .nse_tri import NSETRI


__all__ = [
'NSEProduct',
'NSEIndex',
'NSETRI'
]


__version__ = '0.1.0'
__version__ = '0.1.1'
Binary file modified BharatFinTrack/data/equity_indices.xlsx
Binary file not shown.
194 changes: 194 additions & 0 deletions BharatFinTrack/nse_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import os
import tempfile
import typing
import datetime
import dateutil.relativedelta
import pandas
import requests
import bs4
import matplotlib
from .nse_product import NSEProduct
from .core import Core


class NSEIndex:

'''
Download and analyze NSE index price data.
'''

def all_equity_index_cagr_from_inception(
self,
excel_file: str,
http_headers: typing.Optional[dict[str, str]] = None
) -> pandas.DataFrame:

'''
Returns a DataFrame with the CAGR(%) of all NSE equity indices
(excluding dividend reinvestment) from inception.
Parameters
----------
excel_file : str
Path to an Excel file to save the DataFrame.
http_headers : dict, optional
HTTP headers for the web request. Defaults to
:attr:`BharatFinTrack.core.Core.default_http_headers` if not provided.
Returns
-------
DataFrame
A multi-index DataFrame with the CAGR(%) for all NSE equity indices from inception,
sorted in descending order by CAGR(%) within each index category.
'''

# web request headers
headers = Core().default_http_headers if http_headers is None else http_headers

# download data
main_url = 'https://www.niftyindices.com'
csv_url = main_url + '/reports/daily-reports'
response = requests.get(csv_url, headers=headers)
soup = bs4.BeautifulSoup(response.content, 'html.parser')
for anchor in soup.find_all('a'):
if anchor['href'].endswith('.csv') and anchor['id'] == 'dailysnapOneDaybefore':
csv_link = main_url + anchor['href']
else:
pass
response = requests.get(csv_link, headers=headers)
with tempfile.TemporaryDirectory() as tmp_dir:
daily_file = os.path.join(tmp_dir, 'daily.csv')
with open(daily_file, 'wb') as daily_data:
daily_data.write(response.content)
daily_df = pandas.read_csv(daily_file)

# processing downloaded data
date_string = datetime.datetime.strptime(
daily_df.loc[0, 'Index Date'], '%d-%m-%Y'
)
daily_date = date_string.date()
daily_df = daily_df[['Index Name', 'Index Date', 'Closing Index Value']]
daily_df.columns = ['Index Name', 'Date', 'Close']
daily_df['Index Name'] = daily_df['Index Name'].apply(lambda x: x.upper())
exclude_word = [
'G-SEC',
'1D RATE',
'INDIA VIX',
'DIVIDEND POINTS'
]
exclude_index = daily_df['Index Name'].apply(
lambda x: any(word in x for word in exclude_word)
)
daily_df = daily_df[~exclude_index].reset_index(drop=True)
daily_df['Date'] = daily_date

# processing base DataFrame
base_df = NSEProduct()._dataframe_equity_index
base_df = base_df.reset_index()
category = list(base_df['Category'].unique())
base_df = base_df.drop(columns=['ID', 'API TRI'])
base_df['Base Date'] = base_df['Base Date'].apply(lambda x: x.date())

# checking absent indices in both files
base_unmatch = {
'NIFTY 50 FUTURES INDEX': 'NIFTY 50 FUTURES PR',
'NIFTY 50 FUTURES TR INDEX': 'NIFTY 50 FUTURES TR',
'NIFTY HEALTHCARE INDEX': 'NIFTY HEALTHCARE'
}
daily_df['Index Name'] = daily_df['Index Name'].apply(
lambda x: base_unmatch.get(x, x)
)
# base_index = base_df['Index Name']
# daily_index = daily_df['Index Name']
# unavailable_base = list(base_index[~base_index.isin(daily_index)])
# print(f'Base indices {unavailable_base} are not available in daily indices.')
# unavailable_daily = list(daily_index[~daily_index.isin(base_index)])
# print(f'Daily indices {unavailable_daily} are not available in base indices.')

# merging data
cagr_df = base_df.merge(daily_df)
cagr_df['Return(1 INR)'] = (cagr_df['Close'] / cagr_df['Base Value']).round(2)
cagr_df['Years'] = list(
map(
lambda x: dateutil.relativedelta.relativedelta(daily_date, x).years, cagr_df['Base Date']
)
)
cagr_df['Days'] = list(
map(
lambda x, y: (daily_date - x.replace(year=x.year + y)).days, cagr_df['Base Date'], cagr_df['Years']
)
)
total_years = cagr_df['Years'] + (cagr_df['Days'] / 365)
cagr_df['CAGR(%)'] = 100 * (pow(cagr_df['Close'] / cagr_df['Base Value'], 1 / total_years) - 1)

# Convert 'Category' column to categorical data types with a defined order
cagr_df['Category'] = pandas.Categorical(
cagr_df['Category'],
categories=category,
ordered=True
)

# Sort the dataframe
cagr_df = cagr_df.sort_values(
by=['Category', 'CAGR(%)', 'Years', 'Days'],
ascending=[True, False, False, False]
)

# output
dfs_category = map(lambda x: cagr_df[cagr_df['Category'] == x], category)
dataframes = list(
map(
lambda x: x.drop(columns=['Category']).reset_index(drop=True), dfs_category
)
)
output = pandas.concat(
dataframes,
keys=[word.upper() for word in category],
names=['Category', 'ID']
)

# saving the DataFrame
excel_ext = Core()._excel_file_extension(excel_file)
if excel_ext != '.xlsx':
raise Exception(
f'Input file extension "{excel_ext}" does not match the required ".xlsx".'
)
else:
with pandas.ExcelWriter(excel_file, engine='xlsxwriter') as excel_writer:
output.to_excel(excel_writer, index=True)
workbook = excel_writer.book
worksheet = excel_writer.sheets['Sheet1']
# number of columns for DataFrame indices
index_cols = len(output.index.names)
# format columns
worksheet.set_column(0, index_cols - 1, 15)
worksheet.set_column(index_cols, index_cols, 60)
worksheet.set_column(index_cols + 1, index_cols + output.shape[1] - 2, 15)
worksheet.set_column(
index_cols + output.shape[1] - 1,
index_cols + output.shape[1] - 1, 15,
workbook.add_format({'num_format': '#,##0.0'})
)
# Dataframe colors
get_colormap = matplotlib.colormaps.get_cmap('Pastel2')
colors = [
get_colormap(count / len(category)) for count in range(len(category))
]
hex_colors = [
'{:02X}{:02X}{:02X}'.format(*[int(num * 255) for num in color]) for color in colors
]
# coloring of DataFrames
start_col = index_cols - 1
end_col = index_cols + len(output.columns) - 1
start_row = 1
for df, color in zip(dataframes, hex_colors):
color_format = workbook.add_format({'bg_color': color})
end_row = start_row + len(df) - 1
worksheet.conditional_format(
start_row, start_col, end_row, end_col,
{'type': 'no_blanks', 'format': color_format}
)
start_row = end_row + 1

return output
3 changes: 2 additions & 1 deletion BharatFinTrack/nse_tri.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
class NSETRI:

'''
Download and analyze NSE TRI (Total Return Index) data.
Download and analyze NSE TRI (Total Return Index) data,
including both price index and dividend reinvestment.
'''

@property
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ It is designed to simplify the process of downloading and analyzing financial da
* [Nifty Indices](https://www.niftyindices.com/)

- Provides access to the characteristics of NSE equity indices.
- Facilitates downloading TRI (Total Return Index) data for all NSE equity indices.
- Calculates the CAGR(%) of all NSE equity indices (excluding dividend reinvestment) from inception.
- Facilitates downloading Total Return Index, including both price and dividend reinvestment, data for all NSE equity indices.


## Roadmap
Expand Down
19 changes: 16 additions & 3 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,35 @@
Release Notes
===============


Version 0.1.1
--------------

* **Release date:** 02-Oct-2024

* **Feature Additions:** Introduced the :class:`BharatFinTrack.NSEIndex` class, which currently calculates the CAGR(%) of all NSE equity indices
(excluding dividend reinvestment) from inception. Additional features are planned for future releases.

* **Documentation:** Updated to reflect the newly introduced features.

* **Development Status:** Upgraded from Pre-Alpha to Alpha.


Version 0.1.0
---------------

* **Release date:** 30-Sep-2024.

* **Feature Additions:** Introduced :class:`BharatFinTrack.NSETRI` class, which facilitates downloading Total Return Index (TRI) data for all NSE equity indices.



* **Changes:**

* Renamed class :class:`BharatFinTrack.NSETrack` to :class:`BharatFinTrack.NSEProduct` for improved clarity.
* Updated and renamed methods in the new class :class:`BharatFinTrack.NSEProduct`.

* **Documentation:** Added a tutorial on how to use the newly introduced features.

* **Development status:** Upgraded to Pre-Alpha from Planning.
* **Development status:** Upgraded from Planning to Pre-Alpha.


Version 0.0.3
Expand Down
44 changes: 0 additions & 44 deletions docs/data_download.rst

This file was deleted.

29 changes: 29 additions & 0 deletions docs/functionality.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
===============
Functionality
===============


Index CAGR(%)
---------------
Save the CAGR(%) of all NSE equity indices (excluding dividend reinvestment) from inception to an Excel file.

.. code-block:: python
import BharatFinTrack
nse_index = BharatFinTrack.NSEIndex()
nse_index.all_index_cagr_from_inception(
excel_file=r"C:\Users\Username\Folder\file.xlsx"
)
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Welcome to BharatFinTrack's documentation!
introduction
installation
quickstart
data_download
functionality
modules
changelog

Expand Down
33 changes: 32 additions & 1 deletion docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,35 @@ Expected output:
.. code-block:: text
'03-Nov-1995'
1000.0
1000.0
Download Data
---------------

Total Return Index (TRI)
^^^^^^^^^^^^^^^^^^^^^^^^^^
Download historical daily TRI data, including both price and dividend reinvestment, for the NIFTY 50 index:

.. code-block:: python
import BharatFinTrack
nse_tri = BharatFinTrack.NSETRI()
nse_tri.download_historical_daily_data(
index='NIFTY 50',
start_date='23-SEP-2024',
end_date='27-SEP-2024'
)
Expected output:

.. code-block:: text
Date Close
0 2024-09-23 38505.51
1 2024-09-24 38507.55
2 2024-09-25 38602.21
3 2024-09-26 38916.76
4 2024-09-27 38861.64
2 changes: 2 additions & 0 deletions docs/requirements-docs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ pandas>=2.2.2
requests>=2.32.3
openpyxl>=3.1.5
xlsxwriter>=3.2.0
beautifulsoup4>=4.12.3
matplotlib>=3.9.2


Loading

0 comments on commit 3cf34f4

Please sign in to comment.