Skip to content

Commit

Permalink
version 0.1.9
Browse files Browse the repository at this point in the history
  • Loading branch information
debpal committed Nov 15, 2024
1 parent 992daca commit d5fe14d
Show file tree
Hide file tree
Showing 15 changed files with 275 additions and 30 deletions.
2 changes: 1 addition & 1 deletion BharatFinTrack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
]


__version__ = '0.1.8'
__version__ = '0.1.9'
Binary file modified BharatFinTrack/data/equity_indices.xlsx
Binary file not shown.
147 changes: 143 additions & 4 deletions BharatFinTrack/nse_tri.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ def download_historical_daily_data(
index : str
Name of the index.
excel_file : str, optional
Path to an Excel file to save the DataFrame.
start_date : str, optional
Start date in the format 'DD-MMM-YYYY'.
Defaults to the index's base date if None is provided.
Expand All @@ -109,9 +112,6 @@ def download_historical_daily_data(
HTTP headers for the web request. If not provided, defaults to
:attr:`BharatFinTrack.core.Core.default_http_headers`.
excel_file : str, optional
Path to an Excel file to save the DataFrame.
Returns
-------
DataFrame
Expand Down Expand Up @@ -238,7 +238,7 @@ def download_daily_summary_equity_closing(
Parameters
----------
excel_file : str, optional
excel_file : str
Path to an Excel file to save the DataFrame.
http_headers : dict, optional
Expand Down Expand Up @@ -884,3 +884,142 @@ def sip_summary_from_given_date(
summary['XIRR (%)'] = f'{xirr_p:.1f}'

return summary

def sip_growth_comparison_across_indices(
self,
indices: list[str],
folder_path: str,
excel_file: str,
) -> pandas.DataFrame:

'''
Generates a DataFrame that compares SIP investment growth on the
first date of each month across multiple indices over the years.
The output DataFrame is saved to an Excel file, where the cells with
the highest growth among indices for each year are highlighted in green-yellow,
and those with the lowest growth are highlighted in sandy brown.
Parameters
----------
indices : list
A list of index names to compare in the SIP growth.
folder_path : str
Path to the directory containing Excel files with historical data for each index. Each Excel file must be
named as '{index}.xlsx' corresponding to the index names provided in the `indices` list. These files should
be obtained from :meth:`BharatFinTrack.NSETRI.download_historical_daily_data` or
:meth:`BharatFinTrack.NSETRI.update_historical_daily_data`.
excel_file : str
Path to an Excel file to save the output DataFrame.
Returns
-------
DataFrame
A DataFrame comparing SIP investment growth on the
first date of each month across multiple indices over the years.
'''

# check the Excel file extension first
excel_ext = Core()._excel_file_extension(excel_file)
if excel_ext == '.xlsx':
pass
else:
raise Exception(f'Input file extension "{excel_ext}" does not match the required ".xlsx".')

# monthly investment amount
monthly_invest = 1000

# SIP dataframe of index
dataframes = []
with tempfile.TemporaryDirectory() as tmp_dir:
for index in indices:
index_excel = os.path.join(folder_path, f'{index}.xlsx')
df = NSETRI().yearwise_sip_analysis(
input_excel=index_excel,
monthly_invest=monthly_invest,
output_excel=os.path.join(tmp_dir, 'output.xlsx')
)
dataframes.append(df)

# check equal close date for all DataFrames
close_date = dataframes[0]['Close Date'].iloc[0]
equal_closedate = all(map(lambda df: df['Close Date'].iloc[0] == close_date, dataframes))
if equal_closedate is True:
pass
else:
raise Exception('Last date must be equal across all indices in the Excel files.')

# filtered dataframes
common_year = min(
map(lambda df: int(df['Year'].max()), dataframes)
)
dataframes = [
df[df['Year'] <= common_year] for df in dataframes
]
dataframes = [
df.drop(columns=['Invest', 'Value', 'XIRR (%)']) for df in dataframes
]
dataframes = [
df.rename(columns={'Multiple (X)': f'{index} (X)'}) for df, index in zip(dataframes, indices)
]

# mergeing the DataFrames
merged_df = dataframes[0]
common_cols = list(merged_df.columns)[:-1]
for df in dataframes[1:]:
merged_df = pandas.merge(merged_df, df, on=common_cols, how='inner')
for col in merged_df.columns:
if col.endswith('(X)'):
merged_df[col] = merged_df[col].round(5)
else:
pass

# saving DataFrame
with pandas.ExcelWriter(excel_file, engine='xlsxwriter') as excel_writer:
merged_df.to_excel(excel_writer, index=False)
workbook = excel_writer.book
worksheet = excel_writer.sheets['Sheet1']
worksheet.set_column(
0, len(common_cols) - 1, 15
)
worksheet.set_column(
len(common_cols), merged_df.shape[1] - 1, 20,
workbook.add_format({'num_format': '#,##0.0'})
)
# header formatting
header_format = workbook.add_format(
{
'bold': True,
'text_wrap': True,
'align': 'center',
'valign': 'vcenter'
}
)
for col_num, col_df in enumerate(merged_df.columns):
worksheet.write(0, col_num, col_df, header_format)
# formatting for maximum and minimum value in each row
skip_cols = len(common_cols)
for row in range(merged_df.shape[0]):
# minimum value
worksheet.conditional_format(
row + 1, skip_cols, row + 1, merged_df.shape[1] - 1,
{
'type': 'cell',
'criteria': 'equal to',
'value': merged_df.iloc[row, skip_cols:].min(),
'format': workbook.add_format({'bg_color': '#F4A460'})
}
)
# maximim value
worksheet.conditional_format(
row + 1, skip_cols, row + 1, merged_df.shape[1] - 1,
{
'type': 'cell',
'criteria': 'equal to',
'value': merged_df.iloc[row, skip_cols:].max(),
'format': workbook.add_format({'bg_color': '#ADFF2F'})
}
)

return merged_df
39 changes: 24 additions & 15 deletions BharatFinTrack/visual.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ def plot_top_cagr_indices(
Path of the input Excel file containing the data.
close_type : str
Type of closing value for indices, either PRICE or TRI.
Type of closing value for indices, either 'PRICE' or 'TRI'.
figure_file : str
File Path to save the output figue.
Expand Down Expand Up @@ -614,12 +614,12 @@ def plot_yearwise_sip_returns(
fontsize=12
)
subplot.set_xlabel(
xlabel='Start Date',
xlabel='SIP Start Date',
fontsize=15
)

# y-axis customization
yaxis_max = (int((df['Value'].max() / monthly_invest + 50) / ytick_gap) + 1) * ytick_gap
yaxis_max = (round((df['Value'].max() / monthly_invest + 50) / ytick_gap) + 1) * ytick_gap
subplot.set_ylim(0, yaxis_max)
yticks = range(0, yaxis_max + 1, ytick_gap)
subplot.set_yticks(
Expand Down Expand Up @@ -656,7 +656,7 @@ def plot_yearwise_sip_returns(

# figure customization
figure_title = (
f'{index.upper()}: Invest and Return with Multiples (X) and XIRR (%) of Monthly SIP {monthly_invest} Rupees Over Years'
f'{index.upper()}\n\nReturn with Multiples (X) and XIRR (%) for SIP 1000 Rupees on First Date of Each Month Over Years'
)
figure.suptitle(
t=figure_title,
Expand All @@ -678,7 +678,7 @@ def plot_sip_index_vs_gsec(
index: str,
excel_file: str,
figure_file: str,
bank_return: float = 7.5,
gsec_return: float = 8,
ytick_gap: int = 500
) -> matplotlib.figure.Figure:

Expand All @@ -698,8 +698,8 @@ def plot_sip_index_vs_gsec(
figure_file : str
File Path to save the output figue.
bank_return : float, optional
Expected annual return rate of bank fixed deposit in percentage. Default is 7.5.
gsec_return : float, optional
Expected annual return rate of government bond in percentage. Default is 8.
ytick_gap : int, optional
Gap between two y-axis ticks. Default is 500.
Expand Down Expand Up @@ -738,12 +738,12 @@ def plot_sip_index_vs_gsec(
bank_df = Core().sip_growth(
invest=monthly_invest,
frequency='monthly',
annual_return=bank_return,
annual_return=gsec_return,
years=sip_years
)

# figure
fig_width = len(df) if len(df) > 10 else 10
fig_width = len(df) * 1.2 if len(df) >= 9 else 10
figure = matplotlib.pyplot.figure(
figsize=(fig_width, 10)
)
Expand All @@ -765,7 +765,7 @@ def plot_sip_index_vs_gsec(
x=xticks,
height=bank_df['Value'] / monthly_invest,
width=bar_width,
label='Bank',
label=f'Government ({gsec_return:.1f}%)',
color='cyan'
)
subplot.bar(
Expand All @@ -775,6 +775,15 @@ def plot_sip_index_vs_gsec(
label='Index',
color='lightgreen'
)
for xt in xticks:
multiple = df['Multiple (X)'][xt]
xirr = df['XIRR (%)'][xt]
subplot.annotate(
f'{multiple:.1f}X,{xirr:.0f}%',
xy=(xticks[xt] + bar_width, df['Value'][xt] / monthly_invest),
ha='center', va='bottom',
fontsize=12
)

# x-axis customization
subplot.set_xticks(
Expand All @@ -796,7 +805,7 @@ def plot_sip_index_vs_gsec(
)

# y-axis customization
yaxis_max = (int((df['Value'].max() / monthly_invest + 50) / ytick_gap) + 1) * ytick_gap
yaxis_max = (round((df['Value'].max() / monthly_invest + 50) / ytick_gap) + 1) * ytick_gap
subplot.set_ylim(0, yaxis_max)
yticks = range(0, yaxis_max + 1, ytick_gap)
subplot.set_yticks(
Expand Down Expand Up @@ -833,7 +842,7 @@ def plot_sip_index_vs_gsec(

# figure customization
figure_title = (
f'{index.upper()}: Comparison Return Between Index and Government Bond of Monthly SIP {monthly_invest} Rupees Over Years'
f'{index.upper()} Return with Multiples (X) and XIRR (%)\n\nComparison Return Between Index and Government Bond for SIP 1000 Rupees on First Date of Each Month Over Years'
)
figure.suptitle(
t=figure_title,
Expand Down Expand Up @@ -863,7 +872,7 @@ def plot_sip_growth_comparison_across_indices(
Parameters
----------
indices : str
indices : list
A list of index names to compare in the SIP growth plot.
folder_path : str
Expand Down Expand Up @@ -957,7 +966,7 @@ def plot_sip_growth_comparison_across_indices(
fontsize=12
)
subplot.set_xlabel(
xlabel='Start Date',
xlabel='SIP Start Date',
fontsize=15
)

Expand Down Expand Up @@ -1000,7 +1009,7 @@ def plot_sip_growth_comparison_across_indices(

# figure customization
figure_title = (
'Growth of Monthly SIP Investment Over Years'
'Growth of Monthly SIP Investment on First Date of each Month Over Years'
)
figure.suptitle(
t=figure_title,
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@

* Computes the year-wise SIP return for a fixed monthly contribution to a specified NSE equity `TRI` index.
* Calculates the closing summary of an SIP with a fixed monthly contribution to a specified NSE equity `TRI` index, starting from a given date.
* Compares the growth of a monthly SIP investment across multiple NSE equity `TRI` indices over the years.
* Estimates annual SIP performance, including investment amount, closing balance, and cumulative growth over a specified number of years and expected annual return, with options for yearly, quarterly, monthly, or weekly contributions.


## Visualization

* Displays bar graphs of NSE equity indices’ closing values with descending CAGR (%) since inception, both overall and by index category.
* Shows bar graphs of top-performing NSE equity indices by CAGR (%) since launch, with options to view a specified number of top indices, either overall or within each category.
* Compares the growth of a monthly SIP investment across multiple NSE equity `TRI` indices over the years.
* Depicts a bar graph of year-wise investments and returns for a monthly SIP of 1,000 Rupees in a specified NSE equity `TRI` index since its inception.
* Provides a return comparison between a specified index and government bonds for a monthly SIP of 1,000 Rupees over the years.
* Illustrates a line plot comparing the growth of a monthly SIP investment across multiple NSE equity `TRI` indices over the years.


# Example Insights
Expand All @@ -45,7 +46,8 @@ In this graph, the `NIFTY MIDCAP150 MOMENTUM 50` stands out as one of the best-p

![Year-wise SIP analysis of NIFTY_MIDCAP150_MOMENTUM_50](https://github.com/debpal/BharatFinTrack/raw/master/docs/_static/sip_yearwise_NIFTY_MIDCAP150_MOMENTUM_50.png)

Additionally, the following plot compares the growth of a monthly SIP investment across `TRI` indices, including `NIFTY 50` and several other top-performing NSE equity indices over the years.
Additionally, the following plot compares the growth multiples (X) of a monthly SIP investment across `TRI` indices, including popular indices such as `NIFTY 50` and `NIFTY 500`, as well as several other top-performing NSE equity indices over the years.


![Year-wise SIP growth comparison across multiple indices](https://github.com/debpal/BharatFinTrack/raw/master/docs/_static/sip_invest_growth_across_indices.png)

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/sip_invest_growth_across_indices.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/sip_yearwise_NIFTY_MIDCAP150_MOMENTUM_50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/tri_top_cagr.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/tri_top_cagr_by_category.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@
Release Notes
===============

Version 0.1.9
---------------

* **Release date:** 15-Nov-2024

* **Feature Additions:**

* Added support for newly launched NSE equity indices.
* Enhanced functionality for SIP comparison across indices in the :class:`BharatFinTrack.NSETRI` class.


* **Development Status:** Upgraded from Beta to Production/Stable.



Version 0.1.8
---------------

Expand Down
26 changes: 26 additions & 0 deletions docs/functionality.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,32 @@ Computes the year-wise SIP return for a fixed monthly contribution to a specifie
monthly_invest=1000,
output_excel=r"C:\Users\Username\Folder\SIP_Yearwise_NIFTY_50.xlsx"
)
SIP Comparison Across Indices
-------------------------------

Comparing the growth multiples (X) of a monthly SIP investment across `TRI` indices, including popular indices such as NIFTY 50 and NIFTY 500, as well as several other top-performing NSE equity indices over the years. The data required for SIP calculations must be sourced from the Excel files generated in the :ref:`Total Return Index (TRI) <f_download_tri>` section. Ensure that all Excel files are stored in the designated input folder, with each file named as `{index}.xlsx` to correspond to the index names provided in the list of indices. The output DataFrame is saved to an Excel file, where the cells with the highest growth among indices for each year are highlighted in green-yellow, and those with the lowest growth are highlighted in sandy brown.


.. code-block:: python
index_list = [
'NIFTY 50',
'NIFTY 500',
'NIFTY ALPHA 50',
'NIFTY MIDCAP150 MOMENTUM 50',
'NIFTY500 MOMENTUM 50',
'NIFTY MIDSMALLCAP400 MOMENTUM QUALITY 100',
'NIFTY SMALLCAP250 MOMENTUM QUALITY 100'
]
nse_tri.sip_growth_comparison_across_indices(
indices=index_list
folder_path=r"C:\Users\Username\Folder",
excel_file=r"C:\Users\Username\Folder\sip_invest_growth_across_indices.xlsx"
)
SIP Calculator
Expand Down
Loading

0 comments on commit d5fe14d

Please sign in to comment.