diff --git a/BharatFinTrack/__init__.py b/BharatFinTrack/__init__.py index 29c5764..5c2f6c4 100644 --- a/BharatFinTrack/__init__.py +++ b/BharatFinTrack/__init__.py @@ -10,4 +10,4 @@ ] -__version__ = '0.1.3' +__version__ = '0.1.4' diff --git a/BharatFinTrack/nse_tri.py b/BharatFinTrack/nse_tri.py index b9fbab7..2fed2d1 100644 --- a/BharatFinTrack/nse_tri.py +++ b/BharatFinTrack/nse_tri.py @@ -3,6 +3,7 @@ import dateutil.relativedelta import pandas import matplotlib +import warnings from .nse_product import NSEProduct from .core import Core @@ -110,8 +111,7 @@ def download_historical_daily_data( Returns ------- DataFrame - A DataFrame with two columns: 'Date' and 'Close', representing the daily - closing values for the index between the specified dates. + A DataFrame containing the daily closing values for the index between the specified dates. ''' # check index name @@ -168,14 +168,70 @@ def download_historical_daily_data( return df - def download_equity_indices_updated_value( + def update_historical_daily_data( self, + index: str, excel_file: str, http_headers: typing.Optional[dict[str, str]] = None ) -> pandas.DataFrame: ''' - Returns updated TRI values for all NSE indices. + Updates historical daily closing values from the last date in the input Excel file + to the present and saves the aggregated data to the same file. + + Parameters + ---------- + index : str + Name of the index. + + excel_file : str + Path to the Excel file containing existing historical data. + + http_headers : dict, optional + HTTP headers for the web request. If not provided, defaults to + :attr:`BharatFinTrack.core.Core.default_http_headers`. + + Returns + ------- + DataFrame + A DataFrame with updated closing values from the last recorded date to the present. + ''' + + # read the input Excel file + df = pandas.read_excel(excel_file) + df['Date'] = df['Date'].apply( + lambda x: x.date() + ) + + # addition of downloaded DataFrame + add_df = self.download_historical_daily_data( + index=index, + start_date=df.iloc[-1, 0].strftime('%d-%b-%Y'), + end_date=datetime.date.today().strftime('%d-%b-%Y'), + http_headers=http_headers + ) + + # updating the DataFrame + update_df = pandas.concat([df, add_df]) if isinstance(add_df, pandas.DataFrame) else df + update_df = update_df.drop_duplicates().reset_index(drop=True) + + # saving the DataFrame + with pandas.ExcelWriter(excel_file, engine='xlsxwriter') as excel_writer: + update_df.to_excel(excel_writer, index=False) + worksheet = excel_writer.sheets['Sheet1'] + worksheet.set_column(0, 1, 12) + + return add_df + + def download_daily_summary_equity_closing( + self, + excel_file: str, + http_headers: typing.Optional[dict[str, str]] = None, + test_mode: bool = False + ) -> pandas.DataFrame: + + ''' + Returns updated TRI closing values for all NSE indices. Parameters ---------- @@ -186,14 +242,20 @@ def download_equity_indices_updated_value( 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. + A DataFrame containing updated TRI closing values for all NSE indices. ''' # 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.reset_index() base_df = base_df.drop(columns=['ID', 'API TRI']) base_df['Base Date'] = base_df['Base Date'].apply(lambda x: x.date()) @@ -239,6 +301,55 @@ def download_equity_indices_updated_value( 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, diff --git a/tests/test_bharatfintrack.py b/tests/test_bharatfintrack.py index 483fa8e..fb40233 100644 --- a/tests/test_bharatfintrack.py +++ b/tests/test_bharatfintrack.py @@ -191,26 +191,6 @@ def test_download_historical_daily_data( ) assert exc_info.value.args[0] == message['error_excel'] - # pass test for saving the output DataFrame to an Excel file - with tempfile.TemporaryDirectory() as tmp_dir: - excel_file = os.path.join(tmp_dir, 'equity.xlsx') - nse_tri.download_historical_daily_data( - index='NIFTY 50', - start_date='23-Sep-2024', - end_date='27-Sep-2024', - excel_file=excel_file - ) - df = pandas.read_excel(excel_file) - assert float(df.iloc[-1, -1]) == 38861.64 - - # pass test for valid start and end dates - df = nse_tri.download_historical_daily_data( - index='NIFTY SMALLCAP 100', - start_date='27-Sep-2024', - end_date='27-Sep-2024' - ) - assert float(df.iloc[-1, -1]) == 24686.28 - # pass test for start date being None df = nse_tri.download_historical_daily_data( index='NIFTY INDIA DEFENCE', @@ -232,8 +212,8 @@ def test_download_historical_daily_data( @pytest.mark.parametrize( 'index, expected_value', [ - ('NIFTY MIDCAP150 MOMENTUM 50', 82438.16), - ('NIFTY 50 FUTURES TR', 28187.74), + ('NIFTY 50', 38861.64), + ('NIFTY MIDCAP150 MOMENTUM 50', 82438.16) ] ) def test_index_download_historical_daily_data( @@ -302,6 +282,7 @@ def test_equity_index_price_download_updated_value( assert exc_info.value.args[0] == message['error_excel'] +@pytest.mark.filterwarnings('ignore::DeprecationWarning') def test_equity_index_tri_download_updated_value( nse_tri, message @@ -311,10 +292,12 @@ def test_equity_index_tri_download_updated_value( excel_file = os.path.join(tmp_dir, 'equity.xlsx') # pass test for downloading updated TRI values of NSE equity indices nse_tri.download_equity_indices_updated_value( - excel_file=excel_file + excel_file=excel_file, + test_mode=True ) df = pandas.read_excel(excel_file) assert df.shape[1] == 6 + assert df.shape[0] <= 4 # error test for invalid Excel file input with pytest.raises(Exception) as exc_info: nse_tri.download_equity_indices_updated_value( @@ -358,7 +341,7 @@ def test_equity_index_tri_download_updated_value( output_excel=output_excel ) df = pandas.read_excel(output_excel, index_col=[0, 1]) - assert len(df.index.get_level_values('Category').unique()) <= 5 + assert len(df.index.get_level_values('Category').unique()) <= 4 # error test for invalid Excel file input with pytest.raises(Exception) as exc_info: nse_tri.category_sort_equity_cagr_from_launch( @@ -366,3 +349,29 @@ def test_equity_index_tri_download_updated_value( output_excel='output.xl' ) assert exc_info.value.args[0] == message['error_excel'] + + +def test_update_historical_daily_data( + nse_tri +): + + with tempfile.TemporaryDirectory() as tmp_dir: + excel_file = os.path.join(tmp_dir, 'equity.xlsx') + today = datetime.date.today() + day1_ago = today - datetime.timedelta(days=30) + day2_ago = today - datetime.timedelta(days=15) + # pass test for downloading daily TRI values of NSE a equity index + nse_tri.download_historical_daily_data( + index='NIFTY INDIA DEFENCE', + start_date=day1_ago.strftime('%d-%b-%Y'), + end_date=day2_ago.strftime('%d-%b-%Y'), + excel_file=excel_file + ) + len_df1 = len(pandas.read_excel(excel_file)) + # pass test for updating daily TRI values for the NSE equity index + nse_tri.update_historical_daily_data( + index='NIFTY INDIA DEFENCE', + excel_file=excel_file + ) + len_df2 = len(pandas.read_excel(excel_file)) + assert len_df2 > len_df1