diff --git a/pythclient/calendar.py b/pythclient/calendar.py index 99f554f..ec4eb66 100644 --- a/pythclient/calendar.py +++ b/pythclient/calendar.py @@ -22,10 +22,22 @@ datetime.datetime(2022, 9, 4, tzinfo=NY_TZ).date(), datetime.datetime(2023, 11, 23, tzinfo=NY_TZ).date(), datetime.datetime(2023, 12, 25, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 1, 1, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 1, 15, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 2, 19, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 3, 29, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 5, 27, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 6, 19, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 7, 4, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 9, 2, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 11, 28, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 12, 25, tzinfo=NY_TZ).date(), ] NYSE_EARLY_HOLIDAYS = [ datetime.datetime(2023, 7, 3, tzinfo=NY_TZ).date(), datetime.datetime(2023, 11, 24, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 7, 3, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 11, 29, tzinfo=NY_TZ).date(), ] FX_METAL_OPEN_CLOSE_TIME = datetime.time(17, 0, 0, tzinfo=NY_TZ) @@ -35,6 +47,8 @@ FX_METAL_HOLIDAYS = [ datetime.datetime(2023, 1, 1, tzinfo=NY_TZ).date(), datetime.datetime(2023, 12, 25, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 1, 1, tzinfo=NY_TZ).date(), + datetime.datetime(2024, 12, 25, tzinfo=NY_TZ).date(), ] RATES_OPEN = datetime.time(8, 0, 0, tzinfo=NY_TZ) @@ -60,7 +74,7 @@ def is_market_open(asset_type: str, dt: datetime.datetime) -> bool: return False if asset_type in ["fx", "metal"]: - if date in FX_METAL_HOLIDAYS: + if date in FX_METAL_HOLIDAYS and time < FX_METAL_OPEN_CLOSE_TIME: return False # On Friday the market is closed after 5pm if day == 4 and time >= FX_METAL_OPEN_CLOSE_TIME: @@ -71,6 +85,13 @@ def is_market_open(asset_type: str, dt: datetime.datetime) -> bool: # On Sunday the market is closed before 5pm if day == 6 and time < FX_METAL_OPEN_CLOSE_TIME: return False + # On Sunday the market is closed after 5pm if the next day is a holiday + if ( + day == 6 + and time >= FX_METAL_OPEN_CLOSE_TIME + and (date + datetime.timedelta(days=1) in FX_METAL_HOLIDAYS) + ): + return False return True diff --git a/tests/test_calendar.py b/tests/test_calendar.py index d5757ae..11603dd 100644 --- a/tests/test_calendar.py +++ b/tests/test_calendar.py @@ -22,6 +22,8 @@ FX_METAL_OPEN_WED_2023_6_21_23 = datetime.datetime(2023, 6, 21, 23, 0, 0, tzinfo=NY_TZ) FX_METAL_CLOSE_SUN_2023_6_18_16 = datetime.datetime(2023, 6, 18, 16, 0, 0, tzinfo=NY_TZ) FX_METAL_HOLIDAY_SUN_2023_1_1 = datetime.datetime(2023, 1, 1, tzinfo=NY_TZ) +FX_METAL_HOLIDAY_SUN_2023_12_24_17 = datetime.datetime(2023, 12, 24, 17, 0, 0, tzinfo=NY_TZ) +FX_METAL_HOLIDAY_SUN_2023_12_31_17 = datetime.datetime(2023, 12, 31, 17, 0, 0, tzinfo=NY_TZ) # Define constants for rates market RATES_OPEN_WED_2023_6_21_12 = datetime.datetime(2023, 6, 21, 8, 0, 0, tzinfo=NY_TZ) @@ -75,6 +77,12 @@ def test_is_market_open(): assert is_market_open("fx", FX_METAL_HOLIDAY_SUN_2023_1_1) == False assert is_market_open("metal", FX_METAL_HOLIDAY_SUN_2023_1_1) == False + # fx & metal out of market hours on Sunday Dec 24 2023 after 10pm UTC + assert is_market_open("fx", FX_METAL_HOLIDAY_SUN_2023_12_24_17) == False + + # fx & metal out of market hours on Sunday Dec 31 2023 after 10pm UTC + assert is_market_open("fx", FX_METAL_HOLIDAY_SUN_2023_12_31_17) == False + # rates # weekday, within rates market hours assert is_market_open("rates", RATES_OPEN_WED_2023_6_21_12) == True @@ -167,14 +175,24 @@ def test_get_next_market_open(): == format_datetime_to_unix_timestamp(datetime.datetime(2023, 6, 18, 17, 0, 0, tzinfo=NY_TZ)) ) + # fx & metal out of market hours on Sunday Dec 24 2024 after 10pm UTC + assert ( + get_next_market_open("fx", FX_METAL_HOLIDAY_SUN_2023_12_24_17) + == format_datetime_to_unix_timestamp(datetime.datetime(2023, 12, 25, 17, 0, 0, tzinfo=NY_TZ)) + ) + assert ( + get_next_market_open("metal", FX_METAL_HOLIDAY_SUN_2023_12_24_17) + == format_datetime_to_unix_timestamp(datetime.datetime(2023, 12, 25, 17, 0, 0, tzinfo=NY_TZ)) + ) + # fx & metal holiday assert ( get_next_market_open("fx", FX_METAL_HOLIDAY_SUN_2023_1_1) - == format_datetime_to_unix_timestamp(datetime.datetime(2023, 1, 2, 17, 0, 0, tzinfo=NY_TZ)) + == format_datetime_to_unix_timestamp(datetime.datetime(2023, 1, 1, 17, 0, 0, tzinfo=NY_TZ)) ) assert ( get_next_market_open("metal", FX_METAL_HOLIDAY_SUN_2023_1_1) - == format_datetime_to_unix_timestamp(datetime.datetime(2023, 1, 2, 17, 0, 0, tzinfo=NY_TZ)) + == format_datetime_to_unix_timestamp(datetime.datetime(2023, 1, 1, 17, 0, 0, tzinfo=NY_TZ)) ) # rates within market hours