pandas-market-calendars 4.6.1__py3-none-any.whl → 5.0.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.
Files changed (34) hide show
  1. pandas_market_calendars/calendar_utils.py +27 -80
  2. pandas_market_calendars/calendars/asx.py +6 -2
  3. pandas_market_calendars/calendars/bmf.py +4 -8
  4. pandas_market_calendars/calendars/bse.py +6 -2
  5. pandas_market_calendars/calendars/cboe.py +6 -2
  6. pandas_market_calendars/calendars/cme.py +4 -4
  7. pandas_market_calendars/calendars/cme_globex_base.py +2 -2
  8. pandas_market_calendars/calendars/cme_globex_crypto.py +12 -14
  9. pandas_market_calendars/calendars/cme_globex_energy_and_metals.py +4 -4
  10. pandas_market_calendars/calendars/cme_globex_equities.py +2 -2
  11. pandas_market_calendars/calendars/eurex.py +2 -2
  12. pandas_market_calendars/calendars/eurex_fixed_income.py +2 -2
  13. pandas_market_calendars/calendars/hkex.py +7 -5
  14. pandas_market_calendars/calendars/ice.py +2 -2
  15. pandas_market_calendars/calendars/iex.py +7 -3
  16. pandas_market_calendars/calendars/jpx.py +6 -2
  17. pandas_market_calendars/calendars/lse.py +6 -2
  18. pandas_market_calendars/calendars/mirror.py +6 -11
  19. pandas_market_calendars/calendars/nyse.py +41 -42
  20. pandas_market_calendars/calendars/ose.py +7 -5
  21. pandas_market_calendars/calendars/sifma.py +12 -10
  22. pandas_market_calendars/calendars/six.py +6 -2
  23. pandas_market_calendars/calendars/sse.py +6 -2
  24. pandas_market_calendars/calendars/tase.py +6 -2
  25. pandas_market_calendars/calendars/tsx.py +6 -2
  26. pandas_market_calendars/class_registry.py +1 -3
  27. pandas_market_calendars/market_calendar.py +33 -82
  28. {pandas_market_calendars-4.6.1.dist-info → pandas_market_calendars-5.0.0.dist-info}/METADATA +7 -4
  29. pandas_market_calendars-5.0.0.dist-info/RECORD +50 -0
  30. {pandas_market_calendars-4.6.1.dist-info → pandas_market_calendars-5.0.0.dist-info}/WHEEL +1 -1
  31. pandas_market_calendars-4.6.1.dist-info/RECORD +0 -50
  32. {pandas_market_calendars-4.6.1.dist-info → pandas_market_calendars-5.0.0.dist-info/licenses}/LICENSE +0 -0
  33. {pandas_market_calendars-4.6.1.dist-info → pandas_market_calendars-5.0.0.dist-info/licenses}/NOTICE +0 -0
  34. {pandas_market_calendars-4.6.1.dist-info → pandas_market_calendars-5.0.0.dist-info}/top_level.txt +0 -0
@@ -151,27 +151,17 @@ def merge_schedules(schedules, how="outer"):
151
151
  all_cols = [x.columns for x in schedules]
152
152
  all_cols = list(itertools.chain(*all_cols))
153
153
  if ("break_start" in all_cols) or ("break_end" in all_cols):
154
- warnings.warn(
155
- "Merge schedules will drop the break_start and break_end from result."
156
- )
154
+ warnings.warn("Merge schedules will drop the break_start and break_end from result.")
157
155
 
158
156
  result = schedules[0]
159
157
  for schedule in schedules[1:]:
160
158
  result = result.merge(schedule, how=how, right_index=True, left_index=True)
161
159
  if how == "outer":
162
- result["market_open"] = result.apply(
163
- lambda x: min(x.market_open_x, x.market_open_y), axis=1
164
- )
165
- result["market_close"] = result.apply(
166
- lambda x: max(x.market_close_x, x.market_close_y), axis=1
167
- )
160
+ result["market_open"] = result.apply(lambda x: min(x.market_open_x, x.market_open_y), axis=1)
161
+ result["market_close"] = result.apply(lambda x: max(x.market_close_x, x.market_close_y), axis=1)
168
162
  elif how == "inner":
169
- result["market_open"] = result.apply(
170
- lambda x: max(x.market_open_x, x.market_open_y), axis=1
171
- )
172
- result["market_close"] = result.apply(
173
- lambda x: min(x.market_close_x, x.market_close_y), axis=1
174
- )
163
+ result["market_open"] = result.apply(lambda x: max(x.market_open_x, x.market_open_y), axis=1)
164
+ result["market_close"] = result.apply(lambda x: min(x.market_close_x, x.market_close_y), axis=1)
175
165
  else:
176
166
  raise ValueError('how argument must be "inner" or "outer"')
177
167
  result = result[["market_open", "market_close"]]
@@ -211,9 +201,7 @@ SESSIONS = Literal[
211
201
  "closed",
212
202
  "closed_masked",
213
203
  ]
214
- MKT_TIMES = Literal[
215
- "pre", "post", "market_open", "market_close", "break_start", "break_end"
216
- ]
204
+ MKT_TIMES = Literal["pre", "post", "market_open", "market_close", "break_start", "break_end"]
217
205
 
218
206
 
219
207
  # region ---- ---- ---- Date Range Warning Types ---- ---- ----
@@ -279,9 +267,7 @@ class InsufficientScheduleWarning(DateRangeWarning):
279
267
 
280
268
  def filter_date_range_warnings(
281
269
  action: Literal["error", "ignore", "always", "default", "once"],
282
- source: Union[
283
- Iterable[type[DateRangeWarning]], type[DateRangeWarning]
284
- ] = DateRangeWarning,
270
+ source: Union[Iterable[type[DateRangeWarning]], type[DateRangeWarning]] = DateRangeWarning,
285
271
  ):
286
272
  """
287
273
  Adjust the behavior of the date_range() warnings to the desired action.
@@ -471,13 +457,9 @@ def date_range(
471
457
  if frequency <= pd.Timedelta("0s"):
472
458
  raise ValueError("Market Calendar Date_Range Frequency must be Positive.")
473
459
  if frequency > pd.Timedelta("1D"):
474
- raise ValueError(
475
- "Market Calendar Date_Range Frequency Cannot Be longer than '1D'."
476
- )
460
+ raise ValueError("Market Calendar Date_Range Frequency Cannot Be longer than '1D'.")
477
461
 
478
- session_list, mask = _make_session_list(
479
- set(schedule.columns), session, merge_adjacent
480
- )
462
+ session_list, mask = _make_session_list(set(schedule.columns), session, merge_adjacent)
481
463
  if len(session_list) == 0:
482
464
  return pd.DatetimeIndex([], dtype="datetime64[ns, UTC]")
483
465
 
@@ -490,9 +472,7 @@ def date_range(
490
472
  dtype = schedule[session_list[0][0]].dtype # copy dtype info from schedule
491
473
  start, end, periods = _standardize_times(schedule, start, end, periods, tz)
492
474
 
493
- time_series = _calc_time_series(
494
- session_times, frequency, closed, force_close, start, end, periods
495
- )
475
+ time_series = _calc_time_series(session_times, frequency, closed, force_close, start, end, periods)
496
476
  time_series.name = None
497
477
 
498
478
  return pd.DatetimeIndex(time_series, tz=tz, dtype=dtype)
@@ -501,9 +481,7 @@ def date_range(
501
481
  # region ------------------ Date Range LTF Subroutines ------------------
502
482
 
503
483
 
504
- def _make_session_list(
505
- columns: set, sessions: Union[str, Iterable], merge_adjacent: bool
506
- ) -> Tuple[list, bool]:
484
+ def _make_session_list(columns: set, sessions: Union[str, Iterable], merge_adjacent: bool) -> Tuple[list, bool]:
507
485
  "Create a list of (Session Start, Session End) Tuples"
508
486
  session_times = []
509
487
  missing_cols = set()
@@ -571,9 +549,7 @@ def _make_session_list(
571
549
  return session_pairs, "closed_masked" in sessions
572
550
 
573
551
 
574
- def _standardize_times(
575
- schedule, start, end, periods, tz
576
- ) -> Tuple[pd.Timestamp, pd.Timestamp, Union[int, None]]:
552
+ def _standardize_times(schedule, start, end, periods, tz) -> Tuple[pd.Timestamp, pd.Timestamp, Union[int, None]]:
577
553
  "Standardize start and end into a timestamp of the relevant timezone"
578
554
  if all((start, end, periods)):
579
555
  periods = None # Ignore Periods if all 3 params are given.
@@ -617,8 +593,7 @@ def _standardize_times(
617
593
 
618
594
  if start is not None and end is not None and start > end:
619
595
  raise ValueError(
620
- "Date_range() given a start-date that occurs after the given end-date. "
621
- f"{start = }, {end = }"
596
+ "Date_range() given a start-date that occurs after the given end-date. " f"{start = }, {end = }"
622
597
  )
623
598
 
624
599
  return start, end, periods
@@ -633,9 +608,7 @@ def _reconfigure_schedule(schedule, session_list, mask_close) -> pd.DataFrame:
633
608
  if not end.endswith("_wrap"):
634
609
  # Simple Session where 'start' occurs before 'end'
635
610
  sessions.append(
636
- schedule[[start, end]]
637
- .rename(columns={start: "start", end: "end"})
638
- .set_index("start", drop=False)
611
+ schedule[[start, end]].rename(columns={start: "start", end: "end"}).set_index("start", drop=False)
639
612
  )
640
613
  continue
641
614
 
@@ -779,9 +752,7 @@ def _course_trim_to_period_count(num_bars, periods, reverse) -> pd.Series:
779
752
  return sessions_to_keep
780
753
 
781
754
 
782
- def _calc_time_series(
783
- session_times, timestep, closed, force_close, start, end, periods
784
- ) -> pd.Series:
755
+ def _calc_time_series(session_times, timestep, closed, force_close, start, end, periods) -> pd.Series:
785
756
  "Interpolate each session into a datetime series at the desired frequency."
786
757
  # region ---- ---- ---- Trim the Sessions ---- ---- ----
787
758
  # Compare 'start' to the session end times so that if 'start' is in the middle of a session
@@ -798,23 +769,17 @@ def _calc_time_series(
798
769
  # Align the start to a multiple of the timestep after the session's beginning.
799
770
  # This is to make the returned DTIndex consistent across all start/end/period settings.
800
771
  session_start = session_times.loc[session_times.index[0], "start"]
801
- start_aligned = session_start + (
802
- ceil((start - session_start) / timestep) * timestep
803
- )
772
+ start_aligned = session_start + (ceil((start - session_start) / timestep) * timestep)
804
773
  session_times.loc[session_times.index[0], "start"] = start_aligned
805
774
  if end is not None and end < session_times.loc[session_times.index[-1], "end"]:
806
775
  session_start = session_times.loc[session_times.index[0], "start"]
807
- end_aligned = session_start + (
808
- floor((end - session_start) / timestep) * timestep
809
- )
776
+ end_aligned = session_start + (floor((end - session_start) / timestep) * timestep)
810
777
  session_times.loc[session_times.index[-1], "end"] = end_aligned
811
778
 
812
779
  num_bars = _num_bars_ltf(session_times, timestep, closed)
813
780
 
814
781
  if periods is not None:
815
- sessions_to_keep = _course_trim_to_period_count(
816
- num_bars, periods, end is not None
817
- )
782
+ sessions_to_keep = _course_trim_to_period_count(num_bars, periods, end is not None)
818
783
  num_bars = num_bars[sessions_to_keep]
819
784
  session_times = session_times[sessions_to_keep]
820
785
 
@@ -853,9 +818,7 @@ def _calc_time_series(
853
818
 
854
819
  PeriodCode = Literal["D", "W", "M", "Q", "Y"]
855
820
  Day_Anchor = Literal["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"]
856
- Month_Anchor = Literal[
857
- "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
858
- ]
821
+ Month_Anchor = Literal["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]
859
822
 
860
823
  # These needed because the pandas Period Object is stupid and not consistant w/ date_range.
861
824
  # pd.date_range(s,e, freq = 'W-SUN') == [DatetimeIndex of all sundays] (as Expected)
@@ -970,9 +933,7 @@ def _error_check_htf_range(
970
933
  "Standardize and Error Check Start, End, and period params"
971
934
  if periods is not None:
972
935
  if not isinstance(periods, int):
973
- raise ValueError(
974
- f"Date_Range_HTF Must be either an int or None. Given {type(periods)}"
975
- )
936
+ raise ValueError(f"Date_Range_HTF Must be either an int or None. Given {type(periods)}")
976
937
  if periods < 0:
977
938
  raise ValueError("Date_range_HTF Periods must be Positive.")
978
939
 
@@ -989,9 +950,7 @@ def _error_check_htf_range(
989
950
  if all((start, end, periods)):
990
951
  periods = None # Ignore Periods if passed too many params
991
952
  if len([param for param in (start, end, periods) if param is not None]) < 2:
992
- raise ValueError(
993
- "Date_Range_HTF must be given two of the three following params: (start, end, periods)"
994
- )
953
+ raise ValueError("Date_Range_HTF must be given two of the three following params: (start, end, periods)")
995
954
 
996
955
  if start is not None and end is not None and end < start:
997
956
  raise ValueError("Date_Range_HTF() Start-Date must be before the End-Date")
@@ -999,9 +958,7 @@ def _error_check_htf_range(
999
958
  return start, end, periods
1000
959
 
1001
960
 
1002
- def _standardize_htf_freq(
1003
- frequency: Union[str, pd.Timedelta, int, float]
1004
- ) -> Tuple[int, PeriodCode]:
961
+ def _standardize_htf_freq(frequency: Union[str, pd.Timedelta, int, float]) -> Tuple[int, PeriodCode]:
1005
962
  "Standardize the frequency multiplier and Code, throwing errors as needed."
1006
963
  if isinstance(frequency, str):
1007
964
  if len(frequency) == 0:
@@ -1027,9 +984,7 @@ def _standardize_htf_freq(
1027
984
  if frequency < pd.Timedelta("1D"):
1028
985
  raise ValueError("Date_Range_HTF() Frequency must be '1D' or Higher.")
1029
986
  if frequency % pd.Timedelta("1D") != pd.Timedelta(0):
1030
- raise ValueError(
1031
- "Date_Range_HTF() Week and Day frequency must be an integer multiple of Days"
1032
- )
987
+ raise ValueError("Date_Range_HTF() Week and Day frequency must be an integer multiple of Days")
1033
988
 
1034
989
  return frequency.days, "D"
1035
990
 
@@ -1052,9 +1007,7 @@ def _days_per_week(weekmask: Union[Iterable, str]) -> int:
1052
1007
  return len([day for day in weekmask if bool(day)])
1053
1008
 
1054
1009
 
1055
- def _cal_day_range(
1056
- cb_day: "CustomBusinessDay", start, end, periods, mult
1057
- ) -> pd.DatetimeIndex:
1010
+ def _cal_day_range(cb_day: "CustomBusinessDay", start, end, periods, mult) -> pd.DatetimeIndex:
1058
1011
  """
1059
1012
  Returns a Normalized DateTimeIndex of Open Buisness Days.
1060
1013
  Exactly two of the (start, end, periods) arguments must be given.
@@ -1080,9 +1033,7 @@ def _cal_day_range(
1080
1033
  if isinstance(start, pd.Timestamp) and isinstance(end, pd.Timestamp):
1081
1034
  num_days = (end - start) / mult
1082
1035
  # Get a better estimate of the number of open days since date_range calc is slow
1083
- est_open_days = (
1084
- (num_days // 7) * _days_per_week(cb_day.weekmask)
1085
- ) + num_days % pd.Timedelta("1W")
1036
+ est_open_days = ((num_days // 7) * _days_per_week(cb_day.weekmask)) + num_days % pd.Timedelta("1W")
1086
1037
 
1087
1038
  # Should always produce a small overestimate since Holidays aren't accounted for.
1088
1039
  est_open_days = ceil(est_open_days / pd.Timedelta("1D"))
@@ -1149,9 +1100,7 @@ def _cal_WMQY_range(
1149
1100
  roll_func = cb_day.rollforward
1150
1101
  if start is not None:
1151
1102
  normalized_start = start.to_period(grouping_period).start_time
1152
- _dr_start = (
1153
- normalized_start if start <= roll_func(normalized_start) else start
1154
- )
1103
+ _dr_start = normalized_start if start <= roll_func(normalized_start) else start
1155
1104
 
1156
1105
  if end is not None:
1157
1106
  if periods is not None:
@@ -1181,9 +1130,7 @@ def _cal_WMQY_range(
1181
1130
  normalized_end = end.to_period(grouping_period).end_time.normalize()
1182
1131
  _dr_end = normalized_end if end >= roll_func(normalized_end) else end
1183
1132
 
1184
- _range = (
1185
- pd.date_range(_dr_start, _dr_end, periods, freq).to_series().apply(roll_func)
1186
- )
1133
+ _range = pd.date_range(_dr_start, _dr_end, periods, freq).to_series().apply(roll_func)
1187
1134
 
1188
1135
  # Ensure that Rolled Timestamps are in the desired range When given both Start and End
1189
1136
  if start is not None and end is not None:
@@ -1,7 +1,7 @@
1
1
  from datetime import time
2
2
 
3
3
  from pandas.tseries.holiday import AbstractHolidayCalendar, GoodFriday, EasterMonday
4
- from pytz import timezone
4
+ from zoneinfo import ZoneInfo
5
5
 
6
6
  from pandas_market_calendars.holidays.oz import *
7
7
  from pandas_market_calendars.market_calendar import MarketCalendar
@@ -42,9 +42,13 @@ class ASXExchangeCalendar(MarketCalendar):
42
42
  def name(self):
43
43
  return "ASX"
44
44
 
45
+ @property
46
+ def full_name(self):
47
+ return "Australian Securities Exchange"
48
+
45
49
  @property
46
50
  def tz(self):
47
- return timezone("Australia/Sydney")
51
+ return ZoneInfo("Australia/Sydney")
48
52
 
49
53
  @property
50
54
  def regular_holidays(self):
@@ -23,7 +23,7 @@ from pandas.tseries.holiday import (
23
23
  GoodFriday,
24
24
  Holiday,
25
25
  )
26
- from pytz import timezone
26
+ from zoneinfo import ZoneInfo
27
27
 
28
28
  from pandas_market_calendars.market_calendar import FRIDAY, MarketCalendar
29
29
 
@@ -38,9 +38,7 @@ AniversarioSaoPaulo = Holiday(
38
38
  "Aniversario de Sao Paulo", month=1, day=25, end_date="2021-12-31"
39
39
  )
40
40
  # Carnival Monday
41
- CarnavalSegunda = Holiday(
42
- "Carnaval Segunda", month=1, day=1, offset=[Easter(), Day(-48)]
43
- )
41
+ CarnavalSegunda = Holiday("Carnaval Segunda", month=1, day=1, offset=[Easter(), Day(-48)])
44
42
  # Carnival Tuesday
45
43
  CarnavalTerca = Holiday("Carnaval Terca", month=1, day=1, offset=[Easter(), Day(-47)])
46
44
  # Ash Wednesday (short day)
@@ -62,9 +60,7 @@ DiaTrabalho = Holiday(
62
60
  day=1,
63
61
  )
64
62
  # Constitutionalist Revolution
65
- Constitucionalista = Holiday(
66
- "Constitucionalista", month=7, day=9, start_date="1997-01-01", end_date="2019-12-31"
67
- )
63
+ Constitucionalista = Holiday("Constitucionalista", month=7, day=9, start_date="1997-01-01", end_date="2019-12-31")
68
64
  # Independence Day
69
65
  Independencia = Holiday(
70
66
  "Independencia",
@@ -185,7 +181,7 @@ class BMFExchangeCalendar(MarketCalendar):
185
181
 
186
182
  @property
187
183
  def tz(self):
188
- return timezone("America/Sao_Paulo")
184
+ return ZoneInfo("America/Sao_Paulo")
189
185
 
190
186
  @property
191
187
  def regular_holidays(self):
@@ -5,7 +5,7 @@ Bombay Stock Exchnage
5
5
  from datetime import time
6
6
 
7
7
  from pandas import Timestamp
8
- from pytz import timezone
8
+ from zoneinfo import ZoneInfo
9
9
 
10
10
  from pandas_market_calendars.market_calendar import MarketCalendar
11
11
 
@@ -412,9 +412,13 @@ class BSEExchangeCalendar(MarketCalendar):
412
412
  def name(self):
413
413
  return "BSE"
414
414
 
415
+ @property
416
+ def full_name(self):
417
+ return "Bombay Stock Exchange"
418
+
415
419
  @property
416
420
  def tz(self):
417
- return timezone("Asia/Calcutta")
421
+ return ZoneInfo("Asia/Calcutta")
418
422
 
419
423
  @property
420
424
  def adhoc_holidays(self):
@@ -10,7 +10,7 @@ from pandas.tseries.holiday import (
10
10
  USThanksgivingDay,
11
11
  Holiday,
12
12
  )
13
- from pytz import timezone
13
+ from zoneinfo import ZoneInfo
14
14
 
15
15
  from pandas_market_calendars.holidays.us import (
16
16
  Christmas,
@@ -83,9 +83,13 @@ class CFEExchangeCalendar(MarketCalendar):
83
83
  def name(self):
84
84
  return "CFE"
85
85
 
86
+ @property
87
+ def full_name(self):
88
+ return "CBOE Futures Exchange"
89
+
86
90
  @property
87
91
  def tz(self):
88
- return timezone("America/Chicago")
92
+ return ZoneInfo("America/Chicago")
89
93
 
90
94
  @property
91
95
  def regular_holidays(self):
@@ -24,7 +24,7 @@ from pandas.tseries.holiday import (
24
24
  USPresidentsDay,
25
25
  USThanksgivingDay,
26
26
  )
27
- from pytz import timezone
27
+ from zoneinfo import ZoneInfo
28
28
 
29
29
  from pandas_market_calendars.holidays.us import (
30
30
  Christmas,
@@ -71,7 +71,7 @@ class CMEEquityExchangeCalendar(MarketCalendar):
71
71
 
72
72
  @property
73
73
  def tz(self):
74
- return timezone("America/Chicago")
74
+ return ZoneInfo("America/Chicago")
75
75
 
76
76
  @property
77
77
  def regular_holidays(self):
@@ -141,7 +141,7 @@ class CMEAgricultureExchangeCalendar(MarketCalendar):
141
141
 
142
142
  @property
143
143
  def tz(self):
144
- return timezone("America/Chicago")
144
+ return ZoneInfo("America/Chicago")
145
145
 
146
146
  @property
147
147
  def regular_holidays(self):
@@ -357,7 +357,7 @@ class CMEBondExchangeCalendar(MarketCalendar):
357
357
 
358
358
  @property
359
359
  def tz(self):
360
- return timezone("America/Chicago")
360
+ return ZoneInfo("America/Chicago")
361
361
 
362
362
  @property
363
363
  def regular_holidays(self):
@@ -22,7 +22,7 @@ from pandas.tseries.holiday import (
22
22
  USPresidentsDay,
23
23
  USThanksgivingDay,
24
24
  )
25
- from pytz import timezone
25
+ from zoneinfo import ZoneInfo
26
26
 
27
27
  from pandas_market_calendars.holidays.us import (
28
28
  Christmas,
@@ -79,7 +79,7 @@ class CMEGlobexBaseExchangeCalendar(MarketCalendar, ABC):
79
79
 
80
80
  @property
81
81
  def tz(self):
82
- return timezone("America/Chicago")
82
+ return ZoneInfo("America/Chicago")
83
83
 
84
84
  @property
85
85
  def regular_holidays(self):
@@ -1,6 +1,6 @@
1
1
  import datetime as dt
2
2
 
3
- import pytz
3
+ from zoneinfo import ZoneInfo
4
4
  from pandas.tseries.holiday import AbstractHolidayCalendar
5
5
 
6
6
  from pandas_market_calendars.holidays.cme import (
@@ -45,25 +45,23 @@ class CMEGlobexCryptoExchangeCalendar(CMEGlobexBaseExchangeCalendar):
45
45
  # Tuple[Tuple[first date used, time, offset], ...]
46
46
  # -1 offset indicates that the open is on the previous day
47
47
  # None for first date used marks the start, subsequent market times must have an actual timestamp
48
- "market_open": (
49
- (None, dt.time(17, tzinfo=pytz.timezone("America/Chicago")), -1),
50
- ),
48
+ "market_open": ((None, dt.time(17, tzinfo=ZoneInfo("America/Chicago")), -1),),
51
49
  "market_close": (
52
50
  (
53
51
  None,
54
- dt.time(16, tzinfo=pytz.timezone("America/Chicago")),
52
+ dt.time(16, tzinfo=ZoneInfo("America/Chicago")),
55
53
  ),
56
54
  ),
57
55
  "break_start": (
58
56
  (
59
57
  None,
60
- dt.time(16, tzinfo=pytz.timezone("America/Chicago")),
58
+ dt.time(16, tzinfo=ZoneInfo("America/Chicago")),
61
59
  ),
62
60
  ),
63
61
  "break_end": (
64
62
  (
65
63
  None,
66
- dt.time(17, tzinfo=pytz.timezone("America/Chicago")),
64
+ dt.time(17, tzinfo=ZoneInfo("America/Chicago")),
67
65
  ),
68
66
  ),
69
67
  }
@@ -71,7 +69,7 @@ class CMEGlobexCryptoExchangeCalendar(CMEGlobexBaseExchangeCalendar):
71
69
  @property
72
70
  def tz(self):
73
71
  # Central Time
74
- return pytz.timezone("America/Chicago")
72
+ return ZoneInfo("America/Chicago")
75
73
 
76
74
  @property
77
75
  def name(self):
@@ -100,7 +98,7 @@ class CMEGlobexCryptoExchangeCalendar(CMEGlobexBaseExchangeCalendar):
100
98
  # list[Tuple[time, AbstractHolidayCalendar]]
101
99
  return [
102
100
  (
103
- dt.time(8, 15, tzinfo=pytz.timezone("America/Chicago")),
101
+ dt.time(8, 15, tzinfo=ZoneInfo("America/Chicago")),
104
102
  AbstractHolidayCalendar(
105
103
  rules=[
106
104
  GoodFriday2021,
@@ -108,7 +106,7 @@ class CMEGlobexCryptoExchangeCalendar(CMEGlobexBaseExchangeCalendar):
108
106
  ),
109
107
  ),
110
108
  (
111
- dt.time(10, 15, tzinfo=pytz.timezone("America/Chicago")),
109
+ dt.time(10, 15, tzinfo=ZoneInfo("America/Chicago")),
112
110
  AbstractHolidayCalendar(
113
111
  rules=[
114
112
  GoodFridayAfter2022,
@@ -116,7 +114,7 @@ class CMEGlobexCryptoExchangeCalendar(CMEGlobexBaseExchangeCalendar):
116
114
  ),
117
115
  ),
118
116
  (
119
- dt.time(12, tzinfo=pytz.timezone("America/Chicago")),
117
+ dt.time(12, tzinfo=ZoneInfo("America/Chicago")),
120
118
  AbstractHolidayCalendar(
121
119
  rules=[
122
120
  USMartinLutherKingJrPre2022,
@@ -129,7 +127,7 @@ class CMEGlobexCryptoExchangeCalendar(CMEGlobexBaseExchangeCalendar):
129
127
  ),
130
128
  ),
131
129
  (
132
- dt.time(12, 15, tzinfo=pytz.timezone("America/Chicago")),
130
+ dt.time(12, 15, tzinfo=ZoneInfo("America/Chicago")),
133
131
  AbstractHolidayCalendar(
134
132
  rules=[
135
133
  ChristmasEveInOrAfter1993,
@@ -139,12 +137,12 @@ class CMEGlobexCryptoExchangeCalendar(CMEGlobexBaseExchangeCalendar):
139
137
  ),
140
138
  ),
141
139
  (
142
- dt.time(12, 45, tzinfo=pytz.timezone("America/Chicago")),
140
+ dt.time(12, 45, tzinfo=ZoneInfo("America/Chicago")),
143
141
  AbstractHolidayCalendar(rules=[USThanksgivingFridayFrom2021]),
144
142
  ),
145
143
  # TODO: this market already closes at 1600 normally, do we need these holidays?
146
144
  (
147
- dt.time(16, tzinfo=pytz.timezone("America/Chicago")),
145
+ dt.time(16, tzinfo=ZoneInfo("America/Chicago")),
148
146
  AbstractHolidayCalendar(
149
147
  rules=[
150
148
  USMartinLutherKingJrFrom2022,
@@ -18,7 +18,7 @@ from datetime import time
18
18
  from pandas.tseries.holiday import (
19
19
  AbstractHolidayCalendar,
20
20
  ) # , GoodFriday, USLaborDay, USPresidentsDay, USThanksgivingDay
21
- from pytz import timezone
21
+ from zoneinfo import ZoneInfo
22
22
 
23
23
  from pandas_market_calendars.holidays.cme_globex import (
24
24
  USMartinLutherKingJrFrom2022,
@@ -180,7 +180,7 @@ class CMEGlobexEnergyAndMetalsExchangeCalendar(CMEGlobexBaseExchangeCalendar):
180
180
  def special_closes(self):
181
181
  return [
182
182
  (
183
- time(12, tzinfo=timezone("America/Chicago")),
183
+ time(12, tzinfo=ZoneInfo("America/Chicago")),
184
184
  AbstractHolidayCalendar(
185
185
  rules=[
186
186
  USMartinLutherKingJrPre2022,
@@ -193,7 +193,7 @@ class CMEGlobexEnergyAndMetalsExchangeCalendar(CMEGlobexBaseExchangeCalendar):
193
193
  ),
194
194
  ),
195
195
  (
196
- time(12, 45, tzinfo=timezone("America/Chicago")),
196
+ time(12, 45, tzinfo=ZoneInfo("America/Chicago")),
197
197
  AbstractHolidayCalendar(
198
198
  rules=[
199
199
  FridayAfterThanksgiving,
@@ -201,7 +201,7 @@ class CMEGlobexEnergyAndMetalsExchangeCalendar(CMEGlobexBaseExchangeCalendar):
201
201
  ),
202
202
  ),
203
203
  (
204
- time(13, 30, tzinfo=timezone("America/Chicago")),
204
+ time(13, 30, tzinfo=ZoneInfo("America/Chicago")),
205
205
  AbstractHolidayCalendar(
206
206
  rules=[
207
207
  USMartinLutherKingJrFrom2022,
@@ -1,7 +1,7 @@
1
1
  from datetime import time
2
2
 
3
3
  from pandas.tseries.holiday import AbstractHolidayCalendar
4
- from pytz import timezone
4
+ from zoneinfo import ZoneInfo
5
5
 
6
6
  from pandas_market_calendars.holidays.cme import (
7
7
  USMartinLutherKingJrAfter1998Before2015,
@@ -45,7 +45,7 @@ class CMEGlobexEquitiesExchangeCalendar(CMEGlobexBaseExchangeCalendar):
45
45
 
46
46
  @property
47
47
  def tz(self):
48
- return timezone("America/Chicago")
48
+ return ZoneInfo("America/Chicago")
49
49
 
50
50
  @property
51
51
  def name(self):
@@ -11,7 +11,7 @@ from pandas.tseries.holiday import (
11
11
  Holiday,
12
12
  previous_friday,
13
13
  )
14
- from pytz import timezone
14
+ from zoneinfo import ZoneInfo
15
15
 
16
16
  from pandas_market_calendars.market_calendar import (
17
17
  FRIDAY,
@@ -99,7 +99,7 @@ class EUREXExchangeCalendar(MarketCalendar):
99
99
 
100
100
  @property
101
101
  def tz(self):
102
- return timezone("Europe/Berlin")
102
+ return ZoneInfo("Europe/Berlin")
103
103
 
104
104
  @property
105
105
  def regular_holidays(self):
@@ -6,7 +6,7 @@ from pandas.tseries.holiday import (
6
6
  GoodFriday,
7
7
  Holiday,
8
8
  )
9
- from pytz import timezone
9
+ from zoneinfo import ZoneInfo
10
10
 
11
11
  from pandas_market_calendars.market_calendar import (
12
12
  FRIDAY,
@@ -80,7 +80,7 @@ class EUREXFixedIncomeCalendar(MarketCalendar):
80
80
 
81
81
  @property
82
82
  def tz(self):
83
- return timezone("Europe/Berlin")
83
+ return ZoneInfo("Europe/Berlin")
84
84
 
85
85
  @property
86
86
  def regular_holidays(self):
@@ -10,7 +10,7 @@ from pandas.tseries.holiday import (
10
10
  sunday_to_monday,
11
11
  )
12
12
  from pandas.tseries.offsets import LastWeekOfMonth, WeekOfMonth
13
- from pytz import timezone
13
+ from zoneinfo import ZoneInfo
14
14
 
15
15
  from pandas_market_calendars.holidays.cn import (
16
16
  bsd_mapping,
@@ -198,9 +198,7 @@ MidAutumnFestivalDay = Holiday(
198
198
  name="Mid-autumn Festival", # 中秋节翌日
199
199
  month=9,
200
200
  day=7,
201
- observance=partial(
202
- process_date, mapping=maf_mapping, delta=1, func=sunday_to_monday
203
- ),
201
+ observance=partial(process_date, mapping=maf_mapping, delta=1, func=sunday_to_monday),
204
202
  start_date=Timestamp("2011-01-01"),
205
203
  )
206
204
 
@@ -381,9 +379,13 @@ class HKEXExchangeCalendar(MarketCalendar):
381
379
  def name(self):
382
380
  return "HKEX"
383
381
 
382
+ @property
383
+ def full_name(self):
384
+ return "Hong Kong Stock Exchange"
385
+
384
386
  @property
385
387
  def tz(self):
386
- return timezone("Asia/Shanghai")
388
+ return ZoneInfo("Asia/Shanghai")
387
389
 
388
390
  @property
389
391
  def regular_holidays(self):
@@ -9,7 +9,7 @@ from pandas.tseries.holiday import (
9
9
  USPresidentsDay,
10
10
  USThanksgivingDay,
11
11
  )
12
- from pytz import timezone
12
+ from zoneinfo import ZoneInfo
13
13
 
14
14
  from pandas_market_calendars.holidays.us import (
15
15
  Christmas,
@@ -44,7 +44,7 @@ class ICEExchangeCalendar(MarketCalendar):
44
44
 
45
45
  @property
46
46
  def tz(self):
47
- return timezone("US/Eastern")
47
+ return ZoneInfo("US/Eastern")
48
48
 
49
49
  @property
50
50
  def special_closes(self):