pandas-market-calendars 5.0.0__py3-none-any.whl → 5.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -106,11 +106,15 @@ def mark_session(
106
106
  f"Schedule ends at: {schedule.iloc[-1, -1]}"
107
107
  )
108
108
 
109
+ lte_end = schedule.index <= end.normalize().tz_localize(None)
110
+ gte_start = schedule.index >= start.normalize().tz_localize(None)
111
+
112
+ # Shift both by 1 to keep an extra row on either end if available. Needed in some edge cases.
113
+ gte_start = np.append(gte_start, True)[1:] # Shifts gte_start by one to the left.
114
+ lte_end = np.insert(lte_end, 0, True)[:-1] # Shifts lte_end by one to the right.
115
+
109
116
  # Trim the schedule to match the timeframe covered by the given timeseries
110
- schedule = schedule[
111
- (schedule.index >= start.normalize().tz_localize(None))
112
- & (schedule.index <= end.normalize().tz_localize(None))
113
- ]
117
+ schedule = schedule[gte_start & lte_end]
114
118
 
115
119
  backfilled_map = DEFAULT_LABEL_MAP | label_map
116
120
  mapped_labels = [backfilled_map[label] for label in session_labels]
@@ -1,5 +1,7 @@
1
1
  from datetime import time
2
+ import functools
2
3
 
4
+ import pandas as pd
3
5
  from pandas.tseries.holiday import AbstractHolidayCalendar
4
6
  from zoneinfo import ZoneInfo
5
7
  from itertools import chain
@@ -26,11 +28,13 @@ from pandas_market_calendars.holidays.sifma import (
26
28
  USNewYearsEve2pmEarlyClose,
27
29
  MartinLutherKingJr,
28
30
  USPresidentsDay,
31
+ # --- Good Friday Rules --- #
32
+ is_first_friday,
29
33
  GoodFridayThru2020,
30
34
  DayBeforeGoodFriday2pmEarlyCloseThru2020,
31
- GoodFridayAdHoc,
32
- GoodFriday2pmEarlyCloseAdHoc,
33
- DayBeforeGoodFriday2pmEarlyCloseAdHoc,
35
+ GoodFridayPotentialPost2020, # Potential dates, filtered later
36
+ DayBeforeGoodFridayPotentialPost2020, # Potential dates, filtered later
37
+ # --- End Good Friday Rules --- #
34
38
  DayBeforeUSMemorialDay2pmEarlyClose,
35
39
  USMemorialDay,
36
40
  USJuneteenthAfter2022,
@@ -39,7 +43,6 @@ from pandas_market_calendars.holidays.sifma import (
39
43
  ThursdayBeforeUSIndependenceDay2pmEarlyClose,
40
44
  USLaborDay,
41
45
  USColumbusDay,
42
- USVeteransDay2022,
43
46
  USVeteransDay,
44
47
  USThanksgivingDay,
45
48
  DayAfterThanksgiving2pmEarlyClose,
@@ -118,6 +121,32 @@ class SIFMAUSExchangeCalendar(MarketCalendar):
118
121
  def tz(self):
119
122
  return ZoneInfo("America/New_York")
120
123
 
124
+ # Helper method to calculate and cache dynamic dates
125
+ @functools.lru_cache()
126
+ def _get_dynamic_gf_rules(self):
127
+ # Calculate rules for a wide fixed range to avoid arbitrary cutoffs
128
+ # while preventing infinite generation. 1970-2100 is a reasonable range.
129
+ calc_start = pd.Timestamp("1970-01-01")
130
+ calc_end = pd.Timestamp("2100-12-31")
131
+
132
+ # Filter potential dates based on the start_date of the underlying Holiday rules
133
+ gf_rule_start = GoodFridayPotentialPost2020.start_date
134
+ thurs_rule_start = DayBeforeGoodFridayPotentialPost2020.start_date
135
+
136
+ # Ensure calculation range respects the rule start dates
137
+ effective_gf_start = max(calc_start, gf_rule_start) if gf_rule_start else calc_start
138
+ effective_thurs_start = max(calc_start, thurs_rule_start) if thurs_rule_start else calc_start
139
+
140
+ potential_gf_dates = GoodFridayPotentialPost2020.dates(effective_gf_start, calc_end)
141
+ gf_full_holidays = [d for d in potential_gf_dates if not is_first_friday(d)]
142
+ gf_12pm_early_closes = [d for d in potential_gf_dates if is_first_friday(d)]
143
+
144
+ potential_thurs_dates = DayBeforeGoodFridayPotentialPost2020.dates(effective_thurs_start, calc_end)
145
+ thurs_before_gf_2pm_early_closes = [
146
+ thurs for thurs in potential_thurs_dates if not is_first_friday(thurs + pd.Timedelta(days=1))
147
+ ]
148
+ return gf_full_holidays, gf_12pm_early_closes, thurs_before_gf_2pm_early_closes
149
+
121
150
  @property
122
151
  def regular_holidays(self):
123
152
  return AbstractHolidayCalendar(
@@ -131,7 +160,6 @@ class SIFMAUSExchangeCalendar(MarketCalendar):
131
160
  USIndependenceDay,
132
161
  USLaborDay,
133
162
  USColumbusDay,
134
- USVeteransDay2022,
135
163
  USVeteransDay,
136
164
  USThanksgivingDay,
137
165
  Christmas,
@@ -140,11 +168,8 @@ class SIFMAUSExchangeCalendar(MarketCalendar):
140
168
 
141
169
  @property
142
170
  def adhoc_holidays(self):
143
- return list(
144
- chain(
145
- GoodFridayAdHoc,
146
- )
147
- )
171
+ gf_full_holidays, _, _ = self._get_dynamic_gf_rules()
172
+ return gf_full_holidays
148
173
 
149
174
  @property
150
175
  def special_closes(self):
@@ -168,11 +193,15 @@ class SIFMAUSExchangeCalendar(MarketCalendar):
168
193
 
169
194
  @property
170
195
  def special_closes_adhoc(self):
196
+ _, gf_12pm_early_closes, thurs_before_gf_2pm_early_closes = self._get_dynamic_gf_rules()
171
197
  return [
172
198
  (
173
- time(14, tzinfo=ZoneInfo("America/New_York")),
174
- GoodFriday2pmEarlyCloseAdHoc
175
- + DayBeforeGoodFriday2pmEarlyCloseAdHoc, # list
199
+ time(12), # SIFMA rule specifies 12:00 PM ET
200
+ gf_12pm_early_closes,
201
+ ),
202
+ (
203
+ time(14), # SIFMA rule specifies 2:00 PM ET
204
+ thurs_before_gf_2pm_early_closes,
176
205
  ),
177
206
  ]
178
207
 
@@ -227,7 +256,6 @@ class SIFMAUKExchangeCalendar(MarketCalendar):
227
256
  UKSummerBank,
228
257
  USLaborDay,
229
258
  USColumbusDay,
230
- USVeteransDay2022,
231
259
  USVeteransDay,
232
260
  USThanksgivingDay,
233
261
  UKChristmas,
@@ -331,7 +359,6 @@ class SIFMAJPExchangeCalendar(MarketCalendar):
331
359
  JapanSportsDay2020,
332
360
  JapanHealthAndSportsDay2000To2019,
333
361
  JapanCultureDay,
334
- USVeteransDay2022,
335
362
  USVeteransDay,
336
363
  JapanLaborThanksgivingDay,
337
364
  USThanksgivingDay,
@@ -89,27 +89,31 @@ USPresidentsDay = Holiday(
89
89
  ############################################################
90
90
  # Good Friday
91
91
  ############################################################
92
+
93
+
94
+ def is_first_friday(dt):
95
+ """Check if date is the first Friday of the month"""
96
+ # The first Friday of any month must occur on or before the 7th.
97
+ # This check is sufficient regardless of whether Good Friday is in March or April.
98
+ return dt.weekday() == FRIDAY and dt.day <= 7
99
+
100
+
92
101
  GoodFridayThru2020 = Holiday(
93
- "Good Friday 1908+",
102
+ "Good Friday Thru 2020",
94
103
  end_date=Timestamp("2020-12-31"),
95
104
  month=1,
96
105
  day=1,
97
106
  offset=[Easter(), Day(-2)],
98
107
  )
99
108
 
100
- # 2021 is early close.
101
- # 2022 is a full holiday.
102
- # 2023 is early close.
103
- # 2024 is a full holiday
104
- GoodFridayAdHoc = [
105
- Timestamp("2022-04-15", tz="UTC"),
106
- Timestamp("2024-03-29", tz="UTC"),
107
- ]
108
-
109
- GoodFriday2pmEarlyCloseAdHoc = [
110
- Timestamp("2021-04-02", tz="UTC"),
111
- Timestamp("2023-04-07", tz="UTC"),
112
- ]
109
+ # Generate potential Good Friday dates post 2020 (will be filtered in calendar class)
110
+ GoodFridayPotentialPost2020 = Holiday(
111
+ "Good Friday Potential Post 2020",
112
+ start_date=Timestamp("2021-01-01"),
113
+ month=1,
114
+ day=1,
115
+ offset=[Easter(), Day(-2)],
116
+ )
113
117
 
114
118
  DayBeforeGoodFriday2pmEarlyCloseThru2020 = Holiday(
115
119
  "Day Before Good Friday Thru 2020",
@@ -119,10 +123,14 @@ DayBeforeGoodFriday2pmEarlyCloseThru2020 = Holiday(
119
123
  offset=[Easter(), Day(-3)],
120
124
  )
121
125
 
122
- DayBeforeGoodFriday2pmEarlyCloseAdHoc = [
123
- Timestamp("2022-04-14", tz="UTC"),
124
- Timestamp("2024-03-28", tz="UTC"),
125
- ]
126
+ # Generate potential Thursday before Good Friday dates post 2020 (will be filtered in calendar class)
127
+ DayBeforeGoodFridayPotentialPost2020 = Holiday(
128
+ "Day Before Good Friday Potential Post 2020",
129
+ start_date=Timestamp("2021-01-01"),
130
+ month=1,
131
+ day=1,
132
+ offset=[Easter(), Day(-3)],
133
+ )
126
134
 
127
135
  ##################################################
128
136
  # US Memorial Day (Decoration Day) May 30
@@ -204,20 +212,14 @@ USColumbusDay = Holiday(
204
212
  # When falls on Saturday, no holiday is observed.
205
213
  # When falls on Sunday, the Monday following is a holiday.
206
214
  ##########################################################
207
- USVeteransDay2022 = Holiday(
208
- "Veterans Day Prior to 2023",
209
- month=11,
210
- day=11,
211
- end_date=Timestamp("2022-12-31"),
212
- days_of_week=(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY),
213
- observance=sunday_to_monday,
214
- )
215
-
216
215
  USVeteransDay = Holiday(
217
216
  "Veterans Day",
218
217
  month=11,
219
218
  day=11,
220
- start_date=Timestamp("2023-12-31"),
219
+ # SIFMA guidance for observing only Mon-Fri or Sunday->Monday
220
+ # appears consistent for many years. This rule doesn't specify
221
+ # a start_date, letting it apply further back if needed by other logic,
222
+ # while effectively covering 2023+ due to the days_of_week filter.
221
223
  days_of_week=(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY),
222
224
  observance=sunday_to_monday,
223
225
  )
@@ -225,9 +227,7 @@ USVeteransDay = Holiday(
225
227
  ################################################
226
228
  # US Thanksgiving Nov 30
227
229
  ################################################
228
- USThanksgivingDay = Holiday(
229
- "Thanksgiving", month=11, day=1, offset=DateOffset(weekday=TH(4))
230
- )
230
+ USThanksgivingDay = Holiday("Thanksgiving", month=11, day=1, offset=DateOffset(weekday=TH(4)))
231
231
 
232
232
  DayAfterThanksgiving2pmEarlyClose = Holiday(
233
233
  "Black Friday",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pandas_market_calendars
3
- Version: 5.0.0
3
+ Version: 5.1.0
4
4
  Summary: Market and exchange trading calendars for pandas
5
5
  Author-email: Ryan Sheftel <rsheftel@alumni.upenn.edu>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  pandas_market_calendars/__init__.py,sha256=9nFwO1i8mOeM9V75vRmbHCz4pcjSjfXHl8CBvrM-_2s,1357
2
2
  pandas_market_calendars/calendar_registry.py,sha256=9ecKkERkztiwVaOXVsWfUcEvaT5_SwwpD5VaUAJhR1Y,2495
3
- pandas_market_calendars/calendar_utils.py,sha256=tWPtsLW4f9-rqMxQR5J30e16ZaKJ6vf02735PnSfthA,51856
3
+ pandas_market_calendars/calendar_utils.py,sha256=bTW3q4l-PvqJaOmXsfh3LCqRn47TZXKlXNvQSFMgLwE,52151
4
4
  pandas_market_calendars/class_registry.py,sha256=-L3nL7lTSc8B7ieMmA-2ifakJn6pzaLT1bUzSdrTlsg,3838
5
5
  pandas_market_calendars/market_calendar.py,sha256=1VSeiz4ZWk54ARiyxJClHjQ_C0NkdsDQClm4SjSVorM,40409
6
6
  pandas_market_calendars/calendars/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -26,7 +26,7 @@ pandas_market_calendars/calendars/lse.py,sha256=G9LMdGJcWPaZQRbaihVGtYbD92b9I6E0
26
26
  pandas_market_calendars/calendars/mirror.py,sha256=UVMUV6RMuT9h3U46eNFYllSF8fGFwi6U1L9z_EroiD0,4422
27
27
  pandas_market_calendars/calendars/nyse.py,sha256=IdldsuESaZ47Vzm7RyK2ZvpiVMuoQMAH_zR48weLk8U,66206
28
28
  pandas_market_calendars/calendars/ose.py,sha256=BVgMWrmZRaaPXddyXlgtxHz8GcRMLKdhAshOHc3dnUU,3013
29
- pandas_market_calendars/calendars/sifma.py,sha256=JS1bZs-2T329w9OhGgJPzxG_SmNAs82jaDrAoezyTYU,10053
29
+ pandas_market_calendars/calendars/sifma.py,sha256=o50Gr01x6cl_CtvY2FvvFTCLG9WJcUsVO8AQdOiZijs,11745
30
30
  pandas_market_calendars/calendars/six.py,sha256=zVlaVvNxMx2oRhc054B_A3YrsyD1dtKnUtEGkkx34Xk,2690
31
31
  pandas_market_calendars/calendars/sse.py,sha256=HL5o5WOQr7EZVXW35ujhqdCAgobHyQOEkfQzz7SR6t0,10992
32
32
  pandas_market_calendars/calendars/tase.py,sha256=3zvGAl_fvwVis522zTs3-9QT2UKA1LlHocA-B-UYqmM,8756
@@ -39,12 +39,12 @@ pandas_market_calendars/holidays/jp.py,sha256=rqobVw837Uxb-4D1Zq_PyBLoeyhImYW7DB
39
39
  pandas_market_calendars/holidays/jpx_equinox.py,sha256=KWbJqWsnkdyzG3fD2gJTXRLQOF3YTWSn9O6sYRL9Dnk,8070
40
40
  pandas_market_calendars/holidays/nyse.py,sha256=jwcz3Xp7NNL0rnwrQG8vuuBuXg7YTSBcg733nmFw-uM,39831
41
41
  pandas_market_calendars/holidays/oz.py,sha256=P77pWe7ZQj4o-731w6fW_Vzmo41PRxh94QpclI3ZyFM,1042
42
- pandas_market_calendars/holidays/sifma.py,sha256=gELES9-NeV3QNGE4JpsVfmcs1-jtYQrLxjnG4B-4RmM,8754
42
+ pandas_market_calendars/holidays/sifma.py,sha256=PsGYHMHD5fH02o7UUuDB4yadUWawUXRUHH7UDO5GZvc,9183
43
43
  pandas_market_calendars/holidays/uk.py,sha256=dt5TNONlDMXPw8wjyyPBYNnLO5Yz6Mht8VrPUrNqy-M,4719
44
44
  pandas_market_calendars/holidays/us.py,sha256=OBBMMKTRzghD-b9CmPRe5zBh7zQYjWl4-9SogT6ZnBo,11515
45
- pandas_market_calendars-5.0.0.dist-info/licenses/LICENSE,sha256=qW51_A-I7YutlB-s8VSKeOP-aL83T-Lb8LqqU1x1ilw,1065
46
- pandas_market_calendars-5.0.0.dist-info/licenses/NOTICE,sha256=mmH7c9aF5FsELh1OHXloXw1TajLD_mWDKO4dsVf43_E,11693
47
- pandas_market_calendars-5.0.0.dist-info/METADATA,sha256=63lMywzh2v3ev1v0ubNeTtRCKD4I1UnOV998FvMFf14,9641
48
- pandas_market_calendars-5.0.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
49
- pandas_market_calendars-5.0.0.dist-info/top_level.txt,sha256=_4cUEFr07SuEAzZMT-5p0lJGXxO9imVbEK9_5oqcopQ,24
50
- pandas_market_calendars-5.0.0.dist-info/RECORD,,
45
+ pandas_market_calendars-5.1.0.dist-info/licenses/LICENSE,sha256=qW51_A-I7YutlB-s8VSKeOP-aL83T-Lb8LqqU1x1ilw,1065
46
+ pandas_market_calendars-5.1.0.dist-info/licenses/NOTICE,sha256=mmH7c9aF5FsELh1OHXloXw1TajLD_mWDKO4dsVf43_E,11693
47
+ pandas_market_calendars-5.1.0.dist-info/METADATA,sha256=b9voNNgwPUyYYTXbUDmFrQmUyCOG3pkBfEgtFB49x7k,9641
48
+ pandas_market_calendars-5.1.0.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
49
+ pandas_market_calendars-5.1.0.dist-info/top_level.txt,sha256=_4cUEFr07SuEAzZMT-5p0lJGXxO9imVbEK9_5oqcopQ,24
50
+ pandas_market_calendars-5.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (79.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5