pandas-market-calendars 5.0.0__tar.gz → 5.1.0__tar.gz
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.
- {pandas_market_calendars-5.0.0/pandas_market_calendars.egg-info → pandas_market_calendars-5.1.0}/PKG-INFO +1 -1
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendar_utils.py +8 -4
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/sifma.py +42 -15
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/holidays/sifma.py +31 -31
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0/pandas_market_calendars.egg-info}/PKG-INFO +1 -1
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pyproject.toml +1 -1
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_sifma_calendars.py +126 -19
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_utils.py +27 -4
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/LICENSE +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/NOTICE +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/README.rst +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/__init__.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendar_registry.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/__init__.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/asx.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/bmf.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/bse.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/cboe.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/cme.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/cme_globex_agriculture.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/cme_globex_base.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/cme_globex_crypto.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/cme_globex_energy_and_metals.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/cme_globex_equities.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/cme_globex_fixed_income.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/cme_globex_fx.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/eurex.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/eurex_fixed_income.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/hkex.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/ice.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/iex.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/jpx.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/lse.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/mirror.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/nyse.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/ose.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/six.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/sse.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/tase.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/calendars/tsx.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/class_registry.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/holidays/__init__.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/holidays/cme.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/holidays/cme_globex.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/holidays/cn.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/holidays/jp.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/holidays/jpx_equinox.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/holidays/nyse.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/holidays/oz.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/holidays/uk.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/holidays/us.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/market_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars.egg-info/SOURCES.txt +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars.egg-info/dependency_links.txt +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars.egg-info/requires.txt +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars.egg-info/top_level.txt +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/setup.cfg +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_24_7_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_XNYS_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_asx_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_bmf_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_bse_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_cboe_calendars.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_class_registry.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_cme_agriculture_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_cme_bond_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_cme_equity_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_date_range.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_eurex_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_eurex_fixed_income_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_exchange_calendar_cme_globex_crypto.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_exchange_calendar_cme_globex_energy_and_metals.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_exchange_calendar_cme_globex_equities.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_exchange_calendar_cme_globex_fixed_income.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_exchange_calendar_cme_globex_fx.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_exchange_calendar_cme_globex_grains.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_hkex_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_ice_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_iex_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_jpx_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_lse_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_market_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_nyse_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_nyse_calendar_early_years.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_ose_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_six_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_sse_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_tsx_calendar.py +0 -0
- {pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_xtae_calendar.py +0 -0
@@ -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
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
144
|
-
|
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(
|
174
|
-
|
175
|
-
|
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
|
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
|
-
#
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
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",
|
{pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_sifma_calendars.py
RENAMED
@@ -93,6 +93,40 @@ def test_us_weekmask():
|
|
93
93
|
assert sifma_us.weekmask == "Mon Tue Wed Thu Fri"
|
94
94
|
|
95
95
|
|
96
|
+
def test_us_2025():
|
97
|
+
start = "2025-01-01"
|
98
|
+
end = "2025-12-31"
|
99
|
+
holidays = [
|
100
|
+
pd.Timestamp("2025-01-01", tz="UTC"), # New Year's Day
|
101
|
+
pd.Timestamp("2025-01-20", tz="UTC"), # MLK
|
102
|
+
pd.Timestamp("2025-02-17", tz="UTC"), # Presidents Day
|
103
|
+
pd.Timestamp("2025-04-18", tz="UTC"), # Good Friday (NOT first Friday)
|
104
|
+
pd.Timestamp("2025-05-26", tz="UTC"), # Memorial Day
|
105
|
+
pd.Timestamp("2025-06-19", tz="UTC"), # Juneteenth
|
106
|
+
pd.Timestamp("2025-07-04", tz="UTC"), # Independence Day
|
107
|
+
pd.Timestamp("2025-09-01", tz="UTC"), # Labor Day
|
108
|
+
pd.Timestamp("2025-10-13", tz="UTC"), # Columbus Day
|
109
|
+
pd.Timestamp("2025-11-11", tz="UTC"), # Veterans Day
|
110
|
+
pd.Timestamp("2025-11-27", tz="UTC"), # Thanksgiving
|
111
|
+
pd.Timestamp("2025-12-25", tz="UTC"), # Christmas
|
112
|
+
]
|
113
|
+
_test_holidays(sifma_us, holidays, start, end)
|
114
|
+
_test_no_special_opens(sifma_us, start, end)
|
115
|
+
|
116
|
+
# early closes we expect:
|
117
|
+
early_closes = [
|
118
|
+
pd.Timestamp(
|
119
|
+
"2025-04-17 2:00PM", tz="America/New_York"
|
120
|
+
), # Day before Good Friday (2pm because GF is full holiday)
|
121
|
+
pd.Timestamp("2025-05-23 2:00PM", tz="America/New_York"), # Day before Memorial Day
|
122
|
+
pd.Timestamp("2025-07-03 2:00PM", tz="America/New_York"), # Day before Independence Day
|
123
|
+
pd.Timestamp("2025-11-28 2:00PM", tz="America/New_York"), # Day after Thanksgiving
|
124
|
+
pd.Timestamp("2025-12-24 2:00PM", tz="America/New_York"), # Day before Christmas
|
125
|
+
pd.Timestamp("2025-12-31 2:00PM", tz="America/New_York"), # New Year's Eve
|
126
|
+
]
|
127
|
+
_test_has_early_closes(sifma_us, early_closes, start, end)
|
128
|
+
|
129
|
+
|
96
130
|
def test_us_2024():
|
97
131
|
start = "2024-01-01"
|
98
132
|
end = "2024-12-31"
|
@@ -100,7 +134,7 @@ def test_us_2024():
|
|
100
134
|
pd.Timestamp("2024-01-01", tz="UTC"), # New Year's Day
|
101
135
|
pd.Timestamp("2024-01-15", tz="UTC"), # MLK
|
102
136
|
pd.Timestamp("2024-02-19", tz="UTC"), # Presidents Day
|
103
|
-
pd.Timestamp("2024-03-29", tz="UTC"), # Good Friday
|
137
|
+
pd.Timestamp("2024-03-29", tz="UTC"), # Good Friday (NOT first Friday)
|
104
138
|
pd.Timestamp("2024-05-27", tz="UTC"), # Memorial Day
|
105
139
|
pd.Timestamp("2024-06-19", tz="UTC"), # Juneteenth
|
106
140
|
pd.Timestamp("2024-07-04", tz="UTC"), # Independence Day
|
@@ -115,19 +149,13 @@ def test_us_2024():
|
|
115
149
|
|
116
150
|
# early closes we expect:
|
117
151
|
early_closes = [
|
118
|
-
pd.Timestamp("2024-03-28 2:00PM", tz="America/New_York"), # Good Friday
|
119
|
-
pd.Timestamp(
|
120
|
-
"2024-05-24 2:00PM", tz="America/New_York"
|
121
|
-
), # Day before Memorial Day
|
122
|
-
pd.Timestamp(
|
123
|
-
"2024-07-03 2:00PM", tz="America/New_York"
|
124
|
-
), # Day before Independence Day
|
125
|
-
pd.Timestamp(
|
126
|
-
"2024-11-29 2:00PM", tz="America/New_York"
|
127
|
-
), # Day after Thanksgiving
|
128
152
|
pd.Timestamp(
|
129
|
-
"2024-
|
130
|
-
), # Day before
|
153
|
+
"2024-03-28 2:00PM", tz="America/New_York"
|
154
|
+
), # Day before Good Friday (2pm because GF is full holiday)
|
155
|
+
pd.Timestamp("2024-05-24 2:00PM", tz="America/New_York"), # Day before Memorial Day
|
156
|
+
pd.Timestamp("2024-07-03 2:00PM", tz="America/New_York"), # Day before Independence Day
|
157
|
+
pd.Timestamp("2024-11-29 2:00PM", tz="America/New_York"), # Day after Thanksgiving
|
158
|
+
pd.Timestamp("2024-12-24 2:00PM", tz="America/New_York"), # Day before Christmas
|
131
159
|
pd.Timestamp("2024-12-31 2:00PM", tz="America/New_York"), # New Year's Eve
|
132
160
|
]
|
133
161
|
_test_has_early_closes(sifma_us, early_closes, start, end)
|
@@ -136,10 +164,12 @@ def test_us_2024():
|
|
136
164
|
def test_us_2023():
|
137
165
|
start = "2023-01-01"
|
138
166
|
end = "2023-12-31"
|
167
|
+
# Note: Good Friday 2023-04-07 IS the first Friday -> 12pm early close
|
139
168
|
holidays = [
|
140
169
|
pd.Timestamp("2023-01-02", tz="UTC"), # New Year's Day
|
141
170
|
pd.Timestamp("2023-01-16", tz="UTC"), # MLK
|
142
171
|
pd.Timestamp("2023-02-20", tz="UTC"), # Presidents Day
|
172
|
+
# Good Friday is NOT a full holiday
|
143
173
|
pd.Timestamp("2023-05-29", tz="UTC"), # Memorial Day
|
144
174
|
pd.Timestamp("2023-06-19", tz="UTC"), # Juneteenth
|
145
175
|
pd.Timestamp("2023-07-04", tz="UTC"), # Independence Day
|
@@ -153,7 +183,8 @@ def test_us_2023():
|
|
153
183
|
|
154
184
|
# early closes we expect:
|
155
185
|
early_closes = [
|
156
|
-
pd.Timestamp("2023-04-07
|
186
|
+
pd.Timestamp("2023-04-07 12:00PM", tz="America/New_York"), # Good Friday (12pm because it's the first Friday)
|
187
|
+
# No early close the day before Good Friday
|
157
188
|
pd.Timestamp("2023-05-26 2:00PM", tz="America/New_York"), # Day before Memorial Day
|
158
189
|
pd.Timestamp("2023-07-03 2:00PM", tz="America/New_York"), # Day before Independence Day
|
159
190
|
pd.Timestamp("2023-11-24 2:00PM", tz="America/New_York"), # Day after Thanksgiving
|
@@ -166,10 +197,11 @@ def test_us_2023():
|
|
166
197
|
def test_us_2022():
|
167
198
|
start = "2022-01-01"
|
168
199
|
end = "2022-12-31"
|
200
|
+
# Note: Good Friday 2022-04-15 is NOT the first Friday -> full holiday
|
169
201
|
holidays = [
|
170
202
|
pd.Timestamp("2022-01-17", tz="UTC"), # MLK
|
171
203
|
pd.Timestamp("2022-02-21", tz="UTC"), # Presidents Day
|
172
|
-
pd.Timestamp("2022-04-15", tz="UTC"), # Good Friday
|
204
|
+
pd.Timestamp("2022-04-15", tz="UTC"), # Good Friday (Full Holiday)
|
173
205
|
pd.Timestamp("2022-05-30", tz="UTC"), # Memorial Day
|
174
206
|
pd.Timestamp("2022-06-20", tz="UTC"), # Juneteenth
|
175
207
|
pd.Timestamp("2022-07-04", tz="UTC"), # Independence Day
|
@@ -184,7 +216,9 @@ def test_us_2022():
|
|
184
216
|
|
185
217
|
# early closes we expect:
|
186
218
|
early_closes = [
|
187
|
-
pd.Timestamp(
|
219
|
+
pd.Timestamp(
|
220
|
+
"2022-04-14 2:00PM", tz="America/New_York"
|
221
|
+
), # Day before Good Friday (2pm because GF is full holiday)
|
188
222
|
pd.Timestamp("2022-05-27 2:00PM", tz="America/New_York"), # Day before Memorial Day
|
189
223
|
pd.Timestamp("2022-07-01 2:00PM", tz="America/New_York"), # Day before Independence Day
|
190
224
|
pd.Timestamp("2022-11-25 2:00PM", tz="America/New_York"), # Day after Thanksgiving
|
@@ -197,24 +231,28 @@ def test_us_2022():
|
|
197
231
|
def test_us_2021():
|
198
232
|
start = "2021-01-01"
|
199
233
|
end = "2021-12-31"
|
234
|
+
# Note: Good Friday 2021-04-02 IS the first Friday -> 12pm early close
|
200
235
|
holidays = [
|
201
236
|
pd.Timestamp("2021-01-01", tz="UTC"), # New Year's Day
|
202
237
|
pd.Timestamp("2021-01-18", tz="UTC"), # MLK
|
203
238
|
pd.Timestamp("2021-02-15", tz="UTC"), # Presidents Day
|
239
|
+
# Good Friday is NOT a full holiday
|
204
240
|
pd.Timestamp("2021-05-31", tz="UTC"), # Memorial Day
|
205
|
-
|
241
|
+
# Juneteenth not observed by SIFMA in 2021
|
242
|
+
pd.Timestamp("2021-07-05", tz="UTC"), # Independence Day observed
|
206
243
|
pd.Timestamp("2021-09-06", tz="UTC"), # Labor Day
|
207
244
|
pd.Timestamp("2021-10-11", tz="UTC"), # Columbus Day
|
208
245
|
pd.Timestamp("2021-11-11", tz="UTC"), # Veterans Day
|
209
246
|
pd.Timestamp("2021-11-25", tz="UTC"), # Thanksgiving
|
210
|
-
pd.Timestamp("2021-12-24", tz="UTC"), # Christmas
|
247
|
+
pd.Timestamp("2021-12-24", tz="UTC"), # Christmas observed
|
211
248
|
]
|
212
249
|
_test_holidays(sifma_us, holidays, start, end)
|
213
250
|
_test_no_special_opens(sifma_us, start, end)
|
214
251
|
|
215
252
|
# early closes we expect:
|
216
253
|
early_closes = [
|
217
|
-
pd.Timestamp("2021-04-02
|
254
|
+
pd.Timestamp("2021-04-02 12:00PM", tz="America/New_York"), # Good Friday (12pm because it's the first Friday)
|
255
|
+
# No early close the day before Good Friday
|
218
256
|
pd.Timestamp("2021-05-28 2:00PM", tz="America/New_York"), # Day before Memorial Day
|
219
257
|
pd.Timestamp("2021-07-02 2:00PM", tz="America/New_York"), # Day before Independence Day
|
220
258
|
pd.Timestamp("2021-11-26 2:00PM", tz="America/New_York"), # Day after Thanksgiving
|
@@ -286,6 +324,75 @@ def test_us_2019():
|
|
286
324
|
_test_has_early_closes(sifma_us, early_closes, start, end)
|
287
325
|
|
288
326
|
|
327
|
+
def test_us_2026():
|
328
|
+
start = "2026-01-01"
|
329
|
+
end = "2026-12-31"
|
330
|
+
# Note: Good Friday 2026-04-03 IS the first Friday -> 12pm early close
|
331
|
+
holidays = [
|
332
|
+
pd.Timestamp("2026-01-01", tz="UTC"), # New Year's Day
|
333
|
+
pd.Timestamp("2026-01-19", tz="UTC"), # MLK
|
334
|
+
pd.Timestamp("2026-02-16", tz="UTC"), # Presidents Day
|
335
|
+
# Good Friday is NOT a full holiday
|
336
|
+
pd.Timestamp("2026-05-25", tz="UTC"), # Memorial Day
|
337
|
+
pd.Timestamp("2026-06-19", tz="UTC"), # Juneteenth
|
338
|
+
pd.Timestamp("2026-07-03", tz="UTC"), # Independence Day observed
|
339
|
+
pd.Timestamp("2026-09-07", tz="UTC"), # Labor Day
|
340
|
+
pd.Timestamp("2026-10-12", tz="UTC"), # Columbus Day
|
341
|
+
pd.Timestamp("2026-11-11", tz="UTC"), # Veterans Day
|
342
|
+
pd.Timestamp("2026-11-26", tz="UTC"), # Thanksgiving
|
343
|
+
pd.Timestamp("2026-12-25", tz="UTC"), # Christmas
|
344
|
+
]
|
345
|
+
_test_holidays(sifma_us, holidays, start, end)
|
346
|
+
_test_no_special_opens(sifma_us, start, end)
|
347
|
+
|
348
|
+
# early closes we expect:
|
349
|
+
early_closes = [
|
350
|
+
pd.Timestamp("2026-04-03 12:00PM", tz="America/New_York"), # Good Friday (12pm because it's the first Friday)
|
351
|
+
# No early close the day before Good Friday
|
352
|
+
pd.Timestamp("2026-05-22 2:00PM", tz="America/New_York"), # Day before Memorial Day
|
353
|
+
pd.Timestamp("2026-07-02 2:00PM", tz="America/New_York"), # Day before Independence Day
|
354
|
+
pd.Timestamp("2026-11-27 2:00PM", tz="America/New_York"), # Day after Thanksgiving
|
355
|
+
pd.Timestamp("2026-12-24 2:00PM", tz="America/New_York"), # Day before Christmas
|
356
|
+
pd.Timestamp("2026-12-31 2:00PM", tz="America/New_York"), # New Year's Eve
|
357
|
+
]
|
358
|
+
_test_has_early_closes(sifma_us, early_closes, start, end)
|
359
|
+
|
360
|
+
|
361
|
+
def test_us_2027():
|
362
|
+
start = "2027-01-01"
|
363
|
+
end = "2027-12-31"
|
364
|
+
# Note: Good Friday 2027-03-26 is NOT the first Friday -> full holiday
|
365
|
+
holidays = [
|
366
|
+
pd.Timestamp("2027-01-01", tz="UTC"), # New Year's Day
|
367
|
+
pd.Timestamp("2027-01-18", tz="UTC"), # MLK
|
368
|
+
pd.Timestamp("2027-02-15", tz="UTC"), # Presidents Day
|
369
|
+
pd.Timestamp("2027-03-26", tz="UTC"), # Good Friday (Full Holiday)
|
370
|
+
pd.Timestamp("2027-05-31", tz="UTC"), # Memorial Day
|
371
|
+
pd.Timestamp("2027-06-18", tz="UTC"), # Juneteenth observed
|
372
|
+
pd.Timestamp("2027-07-05", tz="UTC"), # Independence Day observed
|
373
|
+
pd.Timestamp("2027-09-06", tz="UTC"), # Labor Day
|
374
|
+
pd.Timestamp("2027-10-11", tz="UTC"), # Columbus Day
|
375
|
+
pd.Timestamp("2027-11-11", tz="UTC"), # Veterans Day
|
376
|
+
pd.Timestamp("2027-11-25", tz="UTC"), # Thanksgiving
|
377
|
+
pd.Timestamp("2027-12-24", tz="UTC"), # Christmas observed
|
378
|
+
]
|
379
|
+
_test_holidays(sifma_us, holidays, start, end)
|
380
|
+
_test_no_special_opens(sifma_us, start, end)
|
381
|
+
|
382
|
+
# early closes we expect:
|
383
|
+
early_closes = [
|
384
|
+
pd.Timestamp(
|
385
|
+
"2027-03-25 2:00PM", tz="America/New_York"
|
386
|
+
), # Day before Good Friday (2pm because GF is full holiday)
|
387
|
+
pd.Timestamp("2027-05-28 2:00PM", tz="America/New_York"), # Day before Memorial Day
|
388
|
+
pd.Timestamp("2027-07-02 2:00PM", tz="America/New_York"), # Day before Independence Day
|
389
|
+
pd.Timestamp("2027-11-26 2:00PM", tz="America/New_York"), # Day after Thanksgiving
|
390
|
+
pd.Timestamp("2027-12-23 2:00PM", tz="America/New_York"), # Day before Christmas
|
391
|
+
pd.Timestamp("2027-12-31 2:00PM", tz="America/New_York"), # New Year's Eve
|
392
|
+
]
|
393
|
+
_test_has_early_closes(sifma_us, early_closes, start, end)
|
394
|
+
|
395
|
+
|
289
396
|
#########################################################################
|
290
397
|
# UK TESTS
|
291
398
|
#########################################################################
|
@@ -56,9 +56,7 @@ def test_merge_schedules():
|
|
56
56
|
],
|
57
57
|
},
|
58
58
|
columns=["market_open", "market_close"],
|
59
|
-
index=pd.DatetimeIndex(
|
60
|
-
["2016-07-01", "2016-07-04", "2016-07-05", "2016-07-06"]
|
61
|
-
),
|
59
|
+
index=pd.DatetimeIndex(["2016-07-01", "2016-07-04", "2016-07-05", "2016-07-06"]),
|
62
60
|
)
|
63
61
|
actual = mcal.merge_schedules([sch1, sch2], how="outer")
|
64
62
|
assert_frame_equal(actual, expected)
|
@@ -230,7 +228,7 @@ def test_mark_session():
|
|
230
228
|
],
|
231
229
|
dtype="datetime64[ns, UTC]",
|
232
230
|
),
|
233
|
-
dtype=pd.CategoricalDtype(categories=["closed", "rth"], ordered=False),
|
231
|
+
dtype=pd.CategoricalDtype(categories=["break", "closed", "rth"], ordered=False),
|
234
232
|
),
|
235
233
|
mcal.mark_session(
|
236
234
|
sched,
|
@@ -264,3 +262,28 @@ def test_mark_session():
|
|
264
262
|
closed="left",
|
265
263
|
),
|
266
264
|
)
|
265
|
+
|
266
|
+
|
267
|
+
def test_mark_session_edge_case():
|
268
|
+
# Edge case test where mark_session needs an additional schedule row because the first
|
269
|
+
# timestamp of a given date range lands in the post market session of the day prior
|
270
|
+
NYSE = mcal.get_calendar("NYSE")
|
271
|
+
sched = NYSE.schedule("2015-12-25", "2016-01-05", market_times="all", tz="UTC")
|
272
|
+
dt = pd.date_range("2015-12-31T23:00", "2016-01-01T02:00", freq="30min", tz="UTC")
|
273
|
+
|
274
|
+
assert_series_equal(
|
275
|
+
pd.Series(
|
276
|
+
[
|
277
|
+
"post",
|
278
|
+
"post",
|
279
|
+
"post",
|
280
|
+
"post",
|
281
|
+
"closed",
|
282
|
+
"closed",
|
283
|
+
"closed",
|
284
|
+
],
|
285
|
+
index=dt,
|
286
|
+
dtype=pd.CategoricalDtype(["closed", "post", "pre", "rth"], ordered=False),
|
287
|
+
),
|
288
|
+
mcal.mark_session(sched, dt, closed="left"),
|
289
|
+
)
|
File without changes
|
File without changes
|
File without changes
|
{pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/pandas_market_calendars/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_cboe_calendars.py
RENAMED
File without changes
|
{pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_class_registry.py
RENAMED
File without changes
|
File without changes
|
{pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_cme_bond_calendar.py
RENAMED
File without changes
|
{pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_cme_equity_calendar.py
RENAMED
File without changes
|
File without changes
|
{pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_eurex_calendar.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pandas_market_calendars-5.0.0 → pandas_market_calendars-5.1.0}/tests/test_market_calendar.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|