Skip to content

Commit

Permalink
version 0.1.5
Browse files Browse the repository at this point in the history
  • Loading branch information
debpal committed Oct 13, 2024
1 parent 696aeb2 commit f0850b3
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 71 deletions.
6 changes: 4 additions & 2 deletions BharatFinTrack/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from .nse_product import NSEProduct
from .nse_index import NSEIndex
from .nse_tri import NSETRI
from .visual import Visual


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


__version__ = '0.1.4'
__version__ = '0.1.5'
34 changes: 33 additions & 1 deletion BharatFinTrack/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import datetime
import pandas
import requests
import matplotlib.pyplot


class Core:

'''
Core functionality of :mod:`BharatFinTrack` module.
Provides common functionality used throughout
the :mod:`BharatFinTrack` package.
'''

def _excel_file_extension(
Expand All @@ -35,6 +37,36 @@ def _excel_file_extension(

return output

def is_valid_figure_extension(
self,
file_path: str
) -> bool:

'''
Returns whether the given path is a valid figure file.
Parameters
----------
file_path : str
Path of the figure file.
Returns
-------
bool
True if the file path is valid, False otherwise.
'''

figure = matplotlib.pyplot.figure(
figsize=(1, 1)
)
file_ext = os.path.splitext(file_path)[-1][1:]
supported_ext = list(figure.canvas.get_supported_filetypes().keys())
output = file_ext in supported_ext

matplotlib.pyplot.close(figure)

return output

def string_to_date(
self,
date_string: str
Expand Down
4 changes: 2 additions & 2 deletions BharatFinTrack/nse_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
class NSEIndex:

'''
Download and analyze NSE index price data
(excluding dividend reinvestment).
Provides functionality for downloading and analyzing
NSE index price data (excluding dividend reinvestment).
'''

def download_daily_summary_report(
Expand Down
6 changes: 3 additions & 3 deletions BharatFinTrack/nse_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
class NSEProduct:

'''
Represents characteristics of NSE (National Stock Exchange)
related financial products.
Provides functionality for accessing the characteristics of
NSE related financial products.
'''

@property
Expand Down Expand Up @@ -49,7 +49,7 @@ def save_dataframe_equity_index_parameters(
Parameters
----------
excel_file : str
Excel file to save the multi-index DataFrame.
Path of an Excel file to save the multi-index DataFrame.
Returns
-------
Expand Down
64 changes: 8 additions & 56 deletions BharatFinTrack/nse_tri.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
import dateutil.relativedelta
import pandas
import matplotlib
import warnings
import matplotlib.pyplot
from .nse_product import NSEProduct
from .core import Core


class NSETRI:

'''
Download and analyze NSE TRI (Total Return Index) data,
including both price index and dividend reinvestment.
Provides functionality for downloading and analyzing
NSE Equity Total Return Index (TRI) data,
including both price and dividend reinvestment.
'''

@property
Expand Down Expand Up @@ -255,7 +256,7 @@ def download_daily_summary_equity_closing(

# processing base DataFrame
base_df = NSEProduct()._dataframe_equity_index
base_df = base_df.groupby(level='Category').head(1) if test_mode is True else base_df
base_df = base_df.groupby(level='Category').head(2) if test_mode is True else base_df
base_df = base_df.reset_index()
base_df = base_df.drop(columns=['ID', 'API TRI'])
base_df['Base Date'] = base_df['Base Date'].apply(lambda x: x.date())
Expand Down Expand Up @@ -301,55 +302,6 @@ def download_daily_summary_equity_closing(

return base_df

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

'''
Returns updated TRI values for all NSE indices.
Parameters
----------
excel_file : str, optional
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.
test_mode : bool, optional
If True, the function will use a mocked DataFrame for testing purposes
instead of the actual data. This parameter is intended for developers
for testing purposes only and is not recommended for use by end-users.
Returns
-------
DataFrame
A DataFrame containing updated TRI values for all NSE indices.
Warnings
--------
The method :meth:`BharatFinTrack.NSETRI.download_equity_indices_updated_value` is deprecated.
Use the :meth:`BharatFinTrack.NSETRI.download_daily_summary_equity_closing` instead.
'''

warnings.warn(
'download_equity_indices_updated_value(excel_file) is deprecated. Use download_daily_summary_equity_closing(excel_file) instead.',
DeprecationWarning,
stacklevel=2
)

output = self.download_daily_summary_equity_closing(
excel_file=excel_file,
http_headers=http_headers,
test_mode=test_mode
)

return output

def sort_equity_value_from_launch(
self,
input_excel: str,
Expand All @@ -365,7 +317,7 @@ def sort_equity_value_from_launch(
Path to the input Excel file.
output_excel : str
Path to an output Excel file to save the output DataFrame.
Path to an Excel file to save the output DataFrame.
Returns
-------
Expand Down Expand Up @@ -421,7 +373,7 @@ def sort_equity_cagr_from_launch(
Path to the input Excel file.
output_excel : str
Path to an output Excel file to save the output DataFrame.
Path to an Excel file to save the output DataFrame.
Returns
-------
Expand Down Expand Up @@ -509,7 +461,7 @@ def category_sort_equity_cagr_from_launch(
Path to the input Excel file.
output_excel : str
Path to an output Excel file to save the output DataFrame.
Path to an Excel file to save the output DataFrame.
Returns
-------
Expand Down
172 changes: 172 additions & 0 deletions BharatFinTrack/visual.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import typing
import pandas
import matplotlib
import matplotlib.pyplot
import matplotlib.figure
from .core import Core


class Visual:

'''
Provides functionality for plotting data.
'''

def plot_category_sort_index_cagr_from_launch(
self,
excel_file: str,
figure_file: str,
threshold_cagr: typing.Optional[float] = None,
threshold_close: typing.Optional[float] = None
) -> matplotlib.figure.Figure:

'''
Returns a bar plot of indices' clsong value since launch.
Parameters
----------
excel_file : str
Path to the input Excel file.
figure_file : str
Path to a file to save the output figue.
threshold_close : float, optional
Only plot indices with a closing value higher than the specified threshold.
threshold_cagr : float, optional
Only plot indices with a CAGR (%) higher than the specified threshold.
Returns
-------
Figure
A bar plot displaying indices' closing values along with
CAGR (%), Multiplier (X), and Age (Y) since launch.
'''

# input DataFrame
df = pandas.read_excel(excel_file, index_col=[0, 1])
df = df[df['Close Value'] >= threshold_close] if threshold_close is not None else df
df = df[df['CAGR(%)'] >= threshold_cagr] if threshold_cagr is not None else df

# check filtered dataframe
if len(df) == 0:
raise Exception('Threshold values return an empty DataFrame.')
else:
pass

categories = df.index.get_level_values('Category').unique()
close_date = df['Close Date'].iloc[0].strftime('%d-%b-%Y')

# color for NSE indices category
colormap = matplotlib.colormaps.get_cmap('Set2')
category_color = {
categories[count]: colormap(count / len(categories)) for count in range(len(categories))
}

# figure
fig_height = int(len(df) / 3.5) + 1 if len(df) > 7 else 3
xtick_gap = 10000
xaxis_max = int(((df['Close Value'].max() + 20000) / xtick_gap) + 1) * xtick_gap
fig_width = int((xaxis_max / xtick_gap) * 1.2) + 1
figure = matplotlib.pyplot.figure(
figsize=(fig_width, fig_height)
)
subplot = figure.subplots(1, 1)

# check validity of input figure file path
check_file = Core().is_valid_figure_extension(figure_file)
if check_file is True:
pass
else:
# close the figure to prevent a blank plot from appearing
matplotlib.pyplot.close(figure)
raise Exception('Input figure file extension is not supported.')

# plotting indices closing values
categories_legend = set()
for count, (index, row) in enumerate(df.iterrows()):
category = index[0]
color = category_color[category]
if category not in categories_legend:
subplot.barh(
row['Index Name'], row['Close Value'],
color=color,
label=category
)
categories_legend.add(category)
else:
subplot.barh(
row['Index Name'], row['Close Value'],
color=color
)
age = row['Years'] + (row['Days'] / 365)
bar_label = f"({row['CAGR(%)']:.1f}%,{round(row['Close/Base'])}X,{age:.1f}Y)"
subplot.text(
row['Close Value'] + 100, count, bar_label,
va='center',
fontsize=10
)

# x-axis customization
subplot.set_xlim(0, xaxis_max)
subplot.set_xticks(
list(range(0, xaxis_max + 1, xtick_gap))
)
xtick_labels = [
f'{int(val / 1000)}k' for val in list(range(0, xaxis_max + 1, xtick_gap))
]
subplot.set_xticklabels(xtick_labels, fontsize=12)
subplot.tick_params(
axis='x', which='both',
direction='in', length=6, width=1,
top=True, bottom=True,
labeltop=True, labelbottom=True
)
subplot.grid(
visible=True,
which='major', axis='x',
color='gray',
linestyle='--', linewidth=0.3
)
subplot.set_xlabel(
f'Close Value (Date: {close_date})',
fontsize=15,
labelpad=15
)

# reverse y-axis
subplot.invert_yaxis()

# y-axis customization
subplot.set_ylabel(
'Index Name',
fontsize=20,
labelpad=15
)
subplot.set_ylim(len(df), -1)

# legend
subplot.legend(
title="Index Category",
loc='lower right',
fontsize=12,
title_fontsize=12
)

# figure customization
figure.suptitle(
'NSE Equity Indices Since Launch: Closing Value Bars with CAGR (%), Multiplier (X), and Age (Y)',
fontsize=15,
y=1
)
figure.tight_layout()
figure.savefig(
figure_file,
bbox_inches='tight'
)

# close the figure to prevent duplicate plots from displaying
matplotlib.pyplot.close(figure)

return figure
Loading

0 comments on commit f0850b3

Please sign in to comment.