diff --git a/openbb_terminal/stocks/tradinghours/bursa_model.py b/openbb_terminal/stocks/tradinghours/bursa_model.py index b19f051c4ae..2ddab9bafe4 100644 --- a/openbb_terminal/stocks/tradinghours/bursa_model.py +++ b/openbb_terminal/stocks/tradinghours/bursa_model.py @@ -153,15 +153,15 @@ def all_bursa(): return bursa -def check_if_open(bursa, exchange): +def check_if_open(bursa: pd.DataFrame, exchange: str) -> bool: """Check if market open helper function Parameters __________ - bursa + bursa : pd.DataFrame pd.DataFrame of all exchanges - exchange - bursa pd.DataFrame index value for exchande + exchange : str + bursa pd.DataFrame index value for exchange Returns _______ @@ -178,94 +178,30 @@ def check_if_open(bursa, exchange): exchange_df = exchange_df.iloc[0].transpose() utcmoment_naive = datetime.utcnow() utcmoment = utcmoment_naive.replace(tzinfo=pytz.utc) - localDatetime = utcmoment.astimezone(pytz.timezone(tz)) + local_datetime = utcmoment.astimezone(pytz.timezone(tz)) market_open = datetime.strptime(exchange_df["market_open"], "%H:%M:%S") market_close = datetime.strptime(exchange_df["market_close"], "%H:%M:%S") + after_market_open = local_datetime.time() >= market_open.time() + before_market_close = local_datetime.time() <= market_close.time() try: lunchbreak_start = datetime.strptime( exchange_df["lunchbreak_start"], "%H:%M:%S" ) lunchbreak_end = datetime.strptime(exchange_df["lunchbreak_end"], "%H:%M:%S") - except Exception: - lunchbreak_end = None - lunchbreak_start = None - if localDatetime.weekday() >= 5: + after_lunch_start = local_datetime.time() >= lunchbreak_start.time() + before_lunch_end = local_datetime.time() <= lunchbreak_end.time() + except Exception: + after_lunch_start = False + before_lunch_end = False + + if local_datetime.weekday() >= 5: result = False - elif ( - localDatetime.hour > market_open.hour and localDatetime.hour < market_close.hour - ): - if lunchbreak_start is not None and lunchbreak_end is not None: - if ( - localDatetime.hour > lunchbreak_start.hour - and localDatetime.hour < lunchbreak_end.hour - ): - result = False - elif ( - localDatetime.hour > lunchbreak_start.hour - and localDatetime.hour == lunchbreak_end.hour - and localDatetime.minute < lunchbreak_end.minute - ): - result = False - elif ( - localDatetime.hour == lunchbreak_start.hour - and localDatetime.minute >= lunchbreak_start.minute - ): - result = False - else: - result = True - elif ( - localDatetime.hour > market_open.hour - and localDatetime.hour == market_close.hour - and localDatetime.minute < market_close.minute - ): - if lunchbreak_start is not None and lunchbreak_end is not None: - if ( - localDatetime.hour > lunchbreak_start.hour - and localDatetime.hour < lunchbreak_end.hour - ): - result = False - elif ( - localDatetime.hour > lunchbreak_start.hour - and localDatetime.hour == lunchbreak_end.hour - and localDatetime.minute < lunchbreak_end.minute - ): - result = False - elif ( - localDatetime.hour == lunchbreak_start.hour - and localDatetime.minute >= lunchbreak_start.minute - ): - result = False - else: - result = True - else: - result = True - elif ( - localDatetime.hour == market_open.hour - and localDatetime.minute >= market_open.minute - ): - if lunchbreak_start is not None and lunchbreak_end is not None: - if ( - localDatetime.hour > lunchbreak_start.hour - and localDatetime.hour < lunchbreak_end.hour - ): - result = False - elif ( - localDatetime.hour > lunchbreak_start.hour - and localDatetime.hour == lunchbreak_end.hour - and localDatetime.minute < lunchbreak_end.minute - ): - result = False - elif ( - localDatetime.hour == lunchbreak_start.hour - and localDatetime.minute >= lunchbreak_start.minute - ): - result = False - else: - result = True - else: - result = True else: - result = False + result = ( + after_market_open + and before_market_close + and not (after_lunch_start and before_lunch_end) + ) return result diff --git a/openbb_terminal/stocks/tradinghours/tradinghours_controller.py b/openbb_terminal/stocks/tradinghours/tradinghours_controller.py index adf41752c7f..98813b82725 100644 --- a/openbb_terminal/stocks/tradinghours/tradinghours_controller.py +++ b/openbb_terminal/stocks/tradinghours/tradinghours_controller.py @@ -195,7 +195,7 @@ class TradingHoursController(BaseController): ns_parser = self.parse_known_args_and_warn(parser, other_args) if ns_parser: bursa_view.display_open() - + else: logger.error("No open exchanges right now.") console.print("[red]No open exchanges right now.[/red]\n") diff --git a/tests/openbb_terminal/stocks/tradinghours/__init__.py b/tests/openbb_terminal/stocks/tradinghours/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/openbb_terminal/stocks/tradinghours/csv/test_bursa_model/trading_hours_df.csv b/tests/openbb_terminal/stocks/tradinghours/csv/test_bursa_model/trading_hours_df.csv new file mode 100644 index 00000000000..741d0ae0b7e --- /dev/null +++ b/tests/openbb_terminal/stocks/tradinghours/csv/test_bursa_model/trading_hours_df.csv @@ -0,0 +1,3 @@ +,name,short_name,timezone,market_open,market_close,lunchbreak_start,lunchbreak_end +AAA,Exchange With Lunch Hours,AAA,Europe/London,09:30:00,17:30:00,12:15:00,13:30:00 +BBB,Exchange Without Lunch Hours,BBB,Europe/London,09:30:00,17:30:00,, \ No newline at end of file diff --git a/tests/openbb_terminal/stocks/tradinghours/test_bursa_model.py b/tests/openbb_terminal/stocks/tradinghours/test_bursa_model.py new file mode 100644 index 00000000000..c5fb63f5ba7 --- /dev/null +++ b/tests/openbb_terminal/stocks/tradinghours/test_bursa_model.py @@ -0,0 +1,50 @@ +from datetime import datetime, timedelta + +import pandas as pd +import pytest + +from openbb_terminal.stocks.tradinghours import bursa_model + +TRADING_HOURS_DF = pd.read_csv( + "tests/openbb_terminal/stocks/tradinghours/csv/test_bursa_model/trading_hours_df.csv", + index_col=0, +) + +DAYS_TILL_NEXT_MONDAY = (0 - datetime.utcnow().date().weekday()) % 7 +NEXT_MONDAY = datetime.utcnow() + timedelta(days=DAYS_TILL_NEXT_MONDAY) +DAYS_TILL_NEXT_SUNDAY = (6 - datetime.utcnow().date().weekday()) % 7 +NEXT_SUNDAY = datetime.utcnow() + timedelta(days=DAYS_TILL_NEXT_SUNDAY) + + +@pytest.mark.parametrize( + "current_time, exchange, expected", + [ + (NEXT_MONDAY.replace(hour=8, minute=0, second=0), "AAA", False), + (NEXT_MONDAY.replace(hour=9, minute=0, second=0), "AAA", False), + (NEXT_MONDAY.replace(hour=12, minute=30, second=0), "AAA", False), + (NEXT_MONDAY.replace(hour=13, minute=15, second=0), "AAA", False), + (NEXT_MONDAY.replace(hour=17, minute=45, second=0), "AAA", False), + (NEXT_MONDAY.replace(hour=20, minute=0, second=0), "AAA", False), + (NEXT_MONDAY.replace(hour=9, minute=30, second=0), "AAA", True), + (NEXT_MONDAY.replace(hour=9, minute=45, second=0), "AAA", True), + (NEXT_MONDAY.replace(hour=11, minute=0, second=0), "AAA", True), + (NEXT_MONDAY.replace(hour=12, minute=10, second=0), "AAA", True), + (NEXT_MONDAY.replace(hour=13, minute=45, second=0), "AAA", True), + (NEXT_MONDAY.replace(hour=14, minute=0, second=0), "AAA", True), + (NEXT_MONDAY.replace(hour=17, minute=0, second=0), "AAA", True), + (NEXT_MONDAY.replace(hour=12, minute=30, second=0), "BBB", True), + (NEXT_SUNDAY.replace(hour=14, minute=0, second=0), "AAA", False), + (NEXT_SUNDAY.replace(hour=14, minute=0, second=0), "BBB", False), + ], +) +def test_check_if_open(current_time, exchange, expected, mocker): + path_model = "openbb_terminal.stocks.tradinghours.bursa_model" + + mocked_datetime = mocker.patch(target=f"{path_model}.datetime") + + mocked_datetime.utcnow().replace().astimezone.return_value = current_time + mocked_datetime.strptime = datetime.strptime + + is_open = bursa_model.check_if_open(TRADING_HOURS_DF, exchange) + + assert is_open == expected