pandas-market-calendars 4.6.1__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.
- pandas_market_calendars/calendar_utils.py +35 -84
- pandas_market_calendars/calendars/asx.py +6 -2
- pandas_market_calendars/calendars/bmf.py +4 -8
- pandas_market_calendars/calendars/bse.py +6 -2
- pandas_market_calendars/calendars/cboe.py +6 -2
- pandas_market_calendars/calendars/cme.py +4 -4
- pandas_market_calendars/calendars/cme_globex_base.py +2 -2
- pandas_market_calendars/calendars/cme_globex_crypto.py +12 -14
- pandas_market_calendars/calendars/cme_globex_energy_and_metals.py +4 -4
- pandas_market_calendars/calendars/cme_globex_equities.py +2 -2
- pandas_market_calendars/calendars/eurex.py +2 -2
- pandas_market_calendars/calendars/eurex_fixed_income.py +2 -2
- pandas_market_calendars/calendars/hkex.py +7 -5
- pandas_market_calendars/calendars/ice.py +2 -2
- pandas_market_calendars/calendars/iex.py +7 -3
- pandas_market_calendars/calendars/jpx.py +6 -2
- pandas_market_calendars/calendars/lse.py +6 -2
- pandas_market_calendars/calendars/mirror.py +6 -11
- pandas_market_calendars/calendars/nyse.py +41 -42
- pandas_market_calendars/calendars/ose.py +7 -5
- pandas_market_calendars/calendars/sifma.py +51 -22
- pandas_market_calendars/calendars/six.py +6 -2
- pandas_market_calendars/calendars/sse.py +6 -2
- pandas_market_calendars/calendars/tase.py +6 -2
- pandas_market_calendars/calendars/tsx.py +6 -2
- pandas_market_calendars/class_registry.py +1 -3
- pandas_market_calendars/holidays/sifma.py +31 -31
- pandas_market_calendars/market_calendar.py +33 -82
- {pandas_market_calendars-4.6.1.dist-info → pandas_market_calendars-5.1.0.dist-info}/METADATA +7 -4
- pandas_market_calendars-5.1.0.dist-info/RECORD +50 -0
- {pandas_market_calendars-4.6.1.dist-info → pandas_market_calendars-5.1.0.dist-info}/WHEEL +1 -1
- pandas_market_calendars-4.6.1.dist-info/RECORD +0 -50
- {pandas_market_calendars-4.6.1.dist-info → pandas_market_calendars-5.1.0.dist-info/licenses}/LICENSE +0 -0
- {pandas_market_calendars-4.6.1.dist-info → pandas_market_calendars-5.1.0.dist-info/licenses}/NOTICE +0 -0
- {pandas_market_calendars-4.6.1.dist-info → pandas_market_calendars-5.1.0.dist-info}/top_level.txt +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]
|
@@ -151,27 +155,17 @@ def merge_schedules(schedules, how="outer"):
|
|
151
155
|
all_cols = [x.columns for x in schedules]
|
152
156
|
all_cols = list(itertools.chain(*all_cols))
|
153
157
|
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
|
-
)
|
158
|
+
warnings.warn("Merge schedules will drop the break_start and break_end from result.")
|
157
159
|
|
158
160
|
result = schedules[0]
|
159
161
|
for schedule in schedules[1:]:
|
160
162
|
result = result.merge(schedule, how=how, right_index=True, left_index=True)
|
161
163
|
if how == "outer":
|
162
|
-
result["market_open"] = result.apply(
|
163
|
-
|
164
|
-
)
|
165
|
-
result["market_close"] = result.apply(
|
166
|
-
lambda x: max(x.market_close_x, x.market_close_y), axis=1
|
167
|
-
)
|
164
|
+
result["market_open"] = result.apply(lambda x: min(x.market_open_x, x.market_open_y), axis=1)
|
165
|
+
result["market_close"] = result.apply(lambda x: max(x.market_close_x, x.market_close_y), axis=1)
|
168
166
|
elif how == "inner":
|
169
|
-
result["market_open"] = result.apply(
|
170
|
-
|
171
|
-
)
|
172
|
-
result["market_close"] = result.apply(
|
173
|
-
lambda x: min(x.market_close_x, x.market_close_y), axis=1
|
174
|
-
)
|
167
|
+
result["market_open"] = result.apply(lambda x: max(x.market_open_x, x.market_open_y), axis=1)
|
168
|
+
result["market_close"] = result.apply(lambda x: min(x.market_close_x, x.market_close_y), axis=1)
|
175
169
|
else:
|
176
170
|
raise ValueError('how argument must be "inner" or "outer"')
|
177
171
|
result = result[["market_open", "market_close"]]
|
@@ -211,9 +205,7 @@ SESSIONS = Literal[
|
|
211
205
|
"closed",
|
212
206
|
"closed_masked",
|
213
207
|
]
|
214
|
-
MKT_TIMES = Literal[
|
215
|
-
"pre", "post", "market_open", "market_close", "break_start", "break_end"
|
216
|
-
]
|
208
|
+
MKT_TIMES = Literal["pre", "post", "market_open", "market_close", "break_start", "break_end"]
|
217
209
|
|
218
210
|
|
219
211
|
# region ---- ---- ---- Date Range Warning Types ---- ---- ----
|
@@ -279,9 +271,7 @@ class InsufficientScheduleWarning(DateRangeWarning):
|
|
279
271
|
|
280
272
|
def filter_date_range_warnings(
|
281
273
|
action: Literal["error", "ignore", "always", "default", "once"],
|
282
|
-
source: Union[
|
283
|
-
Iterable[type[DateRangeWarning]], type[DateRangeWarning]
|
284
|
-
] = DateRangeWarning,
|
274
|
+
source: Union[Iterable[type[DateRangeWarning]], type[DateRangeWarning]] = DateRangeWarning,
|
285
275
|
):
|
286
276
|
"""
|
287
277
|
Adjust the behavior of the date_range() warnings to the desired action.
|
@@ -471,13 +461,9 @@ def date_range(
|
|
471
461
|
if frequency <= pd.Timedelta("0s"):
|
472
462
|
raise ValueError("Market Calendar Date_Range Frequency must be Positive.")
|
473
463
|
if frequency > pd.Timedelta("1D"):
|
474
|
-
raise ValueError(
|
475
|
-
"Market Calendar Date_Range Frequency Cannot Be longer than '1D'."
|
476
|
-
)
|
464
|
+
raise ValueError("Market Calendar Date_Range Frequency Cannot Be longer than '1D'.")
|
477
465
|
|
478
|
-
session_list, mask = _make_session_list(
|
479
|
-
set(schedule.columns), session, merge_adjacent
|
480
|
-
)
|
466
|
+
session_list, mask = _make_session_list(set(schedule.columns), session, merge_adjacent)
|
481
467
|
if len(session_list) == 0:
|
482
468
|
return pd.DatetimeIndex([], dtype="datetime64[ns, UTC]")
|
483
469
|
|
@@ -490,9 +476,7 @@ def date_range(
|
|
490
476
|
dtype = schedule[session_list[0][0]].dtype # copy dtype info from schedule
|
491
477
|
start, end, periods = _standardize_times(schedule, start, end, periods, tz)
|
492
478
|
|
493
|
-
time_series = _calc_time_series(
|
494
|
-
session_times, frequency, closed, force_close, start, end, periods
|
495
|
-
)
|
479
|
+
time_series = _calc_time_series(session_times, frequency, closed, force_close, start, end, periods)
|
496
480
|
time_series.name = None
|
497
481
|
|
498
482
|
return pd.DatetimeIndex(time_series, tz=tz, dtype=dtype)
|
@@ -501,9 +485,7 @@ def date_range(
|
|
501
485
|
# region ------------------ Date Range LTF Subroutines ------------------
|
502
486
|
|
503
487
|
|
504
|
-
def _make_session_list(
|
505
|
-
columns: set, sessions: Union[str, Iterable], merge_adjacent: bool
|
506
|
-
) -> Tuple[list, bool]:
|
488
|
+
def _make_session_list(columns: set, sessions: Union[str, Iterable], merge_adjacent: bool) -> Tuple[list, bool]:
|
507
489
|
"Create a list of (Session Start, Session End) Tuples"
|
508
490
|
session_times = []
|
509
491
|
missing_cols = set()
|
@@ -571,9 +553,7 @@ def _make_session_list(
|
|
571
553
|
return session_pairs, "closed_masked" in sessions
|
572
554
|
|
573
555
|
|
574
|
-
def _standardize_times(
|
575
|
-
schedule, start, end, periods, tz
|
576
|
-
) -> Tuple[pd.Timestamp, pd.Timestamp, Union[int, None]]:
|
556
|
+
def _standardize_times(schedule, start, end, periods, tz) -> Tuple[pd.Timestamp, pd.Timestamp, Union[int, None]]:
|
577
557
|
"Standardize start and end into a timestamp of the relevant timezone"
|
578
558
|
if all((start, end, periods)):
|
579
559
|
periods = None # Ignore Periods if all 3 params are given.
|
@@ -617,8 +597,7 @@ def _standardize_times(
|
|
617
597
|
|
618
598
|
if start is not None and end is not None and start > end:
|
619
599
|
raise ValueError(
|
620
|
-
"Date_range() given a start-date that occurs after the given end-date. "
|
621
|
-
f"{start = }, {end = }"
|
600
|
+
"Date_range() given a start-date that occurs after the given end-date. " f"{start = }, {end = }"
|
622
601
|
)
|
623
602
|
|
624
603
|
return start, end, periods
|
@@ -633,9 +612,7 @@ def _reconfigure_schedule(schedule, session_list, mask_close) -> pd.DataFrame:
|
|
633
612
|
if not end.endswith("_wrap"):
|
634
613
|
# Simple Session where 'start' occurs before 'end'
|
635
614
|
sessions.append(
|
636
|
-
schedule[[start, end]]
|
637
|
-
.rename(columns={start: "start", end: "end"})
|
638
|
-
.set_index("start", drop=False)
|
615
|
+
schedule[[start, end]].rename(columns={start: "start", end: "end"}).set_index("start", drop=False)
|
639
616
|
)
|
640
617
|
continue
|
641
618
|
|
@@ -779,9 +756,7 @@ def _course_trim_to_period_count(num_bars, periods, reverse) -> pd.Series:
|
|
779
756
|
return sessions_to_keep
|
780
757
|
|
781
758
|
|
782
|
-
def _calc_time_series(
|
783
|
-
session_times, timestep, closed, force_close, start, end, periods
|
784
|
-
) -> pd.Series:
|
759
|
+
def _calc_time_series(session_times, timestep, closed, force_close, start, end, periods) -> pd.Series:
|
785
760
|
"Interpolate each session into a datetime series at the desired frequency."
|
786
761
|
# region ---- ---- ---- Trim the Sessions ---- ---- ----
|
787
762
|
# Compare 'start' to the session end times so that if 'start' is in the middle of a session
|
@@ -798,23 +773,17 @@ def _calc_time_series(
|
|
798
773
|
# Align the start to a multiple of the timestep after the session's beginning.
|
799
774
|
# This is to make the returned DTIndex consistent across all start/end/period settings.
|
800
775
|
session_start = session_times.loc[session_times.index[0], "start"]
|
801
|
-
start_aligned = session_start + (
|
802
|
-
ceil((start - session_start) / timestep) * timestep
|
803
|
-
)
|
776
|
+
start_aligned = session_start + (ceil((start - session_start) / timestep) * timestep)
|
804
777
|
session_times.loc[session_times.index[0], "start"] = start_aligned
|
805
778
|
if end is not None and end < session_times.loc[session_times.index[-1], "end"]:
|
806
779
|
session_start = session_times.loc[session_times.index[0], "start"]
|
807
|
-
end_aligned = session_start + (
|
808
|
-
floor((end - session_start) / timestep) * timestep
|
809
|
-
)
|
780
|
+
end_aligned = session_start + (floor((end - session_start) / timestep) * timestep)
|
810
781
|
session_times.loc[session_times.index[-1], "end"] = end_aligned
|
811
782
|
|
812
783
|
num_bars = _num_bars_ltf(session_times, timestep, closed)
|
813
784
|
|
814
785
|
if periods is not None:
|
815
|
-
sessions_to_keep = _course_trim_to_period_count(
|
816
|
-
num_bars, periods, end is not None
|
817
|
-
)
|
786
|
+
sessions_to_keep = _course_trim_to_period_count(num_bars, periods, end is not None)
|
818
787
|
num_bars = num_bars[sessions_to_keep]
|
819
788
|
session_times = session_times[sessions_to_keep]
|
820
789
|
|
@@ -853,9 +822,7 @@ def _calc_time_series(
|
|
853
822
|
|
854
823
|
PeriodCode = Literal["D", "W", "M", "Q", "Y"]
|
855
824
|
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
|
-
]
|
825
|
+
Month_Anchor = Literal["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]
|
859
826
|
|
860
827
|
# These needed because the pandas Period Object is stupid and not consistant w/ date_range.
|
861
828
|
# pd.date_range(s,e, freq = 'W-SUN') == [DatetimeIndex of all sundays] (as Expected)
|
@@ -970,9 +937,7 @@ def _error_check_htf_range(
|
|
970
937
|
"Standardize and Error Check Start, End, and period params"
|
971
938
|
if periods is not None:
|
972
939
|
if not isinstance(periods, int):
|
973
|
-
raise ValueError(
|
974
|
-
f"Date_Range_HTF Must be either an int or None. Given {type(periods)}"
|
975
|
-
)
|
940
|
+
raise ValueError(f"Date_Range_HTF Must be either an int or None. Given {type(periods)}")
|
976
941
|
if periods < 0:
|
977
942
|
raise ValueError("Date_range_HTF Periods must be Positive.")
|
978
943
|
|
@@ -989,9 +954,7 @@ def _error_check_htf_range(
|
|
989
954
|
if all((start, end, periods)):
|
990
955
|
periods = None # Ignore Periods if passed too many params
|
991
956
|
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
|
-
)
|
957
|
+
raise ValueError("Date_Range_HTF must be given two of the three following params: (start, end, periods)")
|
995
958
|
|
996
959
|
if start is not None and end is not None and end < start:
|
997
960
|
raise ValueError("Date_Range_HTF() Start-Date must be before the End-Date")
|
@@ -999,9 +962,7 @@ def _error_check_htf_range(
|
|
999
962
|
return start, end, periods
|
1000
963
|
|
1001
964
|
|
1002
|
-
def _standardize_htf_freq(
|
1003
|
-
frequency: Union[str, pd.Timedelta, int, float]
|
1004
|
-
) -> Tuple[int, PeriodCode]:
|
965
|
+
def _standardize_htf_freq(frequency: Union[str, pd.Timedelta, int, float]) -> Tuple[int, PeriodCode]:
|
1005
966
|
"Standardize the frequency multiplier and Code, throwing errors as needed."
|
1006
967
|
if isinstance(frequency, str):
|
1007
968
|
if len(frequency) == 0:
|
@@ -1027,9 +988,7 @@ def _standardize_htf_freq(
|
|
1027
988
|
if frequency < pd.Timedelta("1D"):
|
1028
989
|
raise ValueError("Date_Range_HTF() Frequency must be '1D' or Higher.")
|
1029
990
|
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
|
-
)
|
991
|
+
raise ValueError("Date_Range_HTF() Week and Day frequency must be an integer multiple of Days")
|
1033
992
|
|
1034
993
|
return frequency.days, "D"
|
1035
994
|
|
@@ -1052,9 +1011,7 @@ def _days_per_week(weekmask: Union[Iterable, str]) -> int:
|
|
1052
1011
|
return len([day for day in weekmask if bool(day)])
|
1053
1012
|
|
1054
1013
|
|
1055
|
-
def _cal_day_range(
|
1056
|
-
cb_day: "CustomBusinessDay", start, end, periods, mult
|
1057
|
-
) -> pd.DatetimeIndex:
|
1014
|
+
def _cal_day_range(cb_day: "CustomBusinessDay", start, end, periods, mult) -> pd.DatetimeIndex:
|
1058
1015
|
"""
|
1059
1016
|
Returns a Normalized DateTimeIndex of Open Buisness Days.
|
1060
1017
|
Exactly two of the (start, end, periods) arguments must be given.
|
@@ -1080,9 +1037,7 @@ def _cal_day_range(
|
|
1080
1037
|
if isinstance(start, pd.Timestamp) and isinstance(end, pd.Timestamp):
|
1081
1038
|
num_days = (end - start) / mult
|
1082
1039
|
# 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")
|
1040
|
+
est_open_days = ((num_days // 7) * _days_per_week(cb_day.weekmask)) + num_days % pd.Timedelta("1W")
|
1086
1041
|
|
1087
1042
|
# Should always produce a small overestimate since Holidays aren't accounted for.
|
1088
1043
|
est_open_days = ceil(est_open_days / pd.Timedelta("1D"))
|
@@ -1149,9 +1104,7 @@ def _cal_WMQY_range(
|
|
1149
1104
|
roll_func = cb_day.rollforward
|
1150
1105
|
if start is not None:
|
1151
1106
|
normalized_start = start.to_period(grouping_period).start_time
|
1152
|
-
_dr_start = (
|
1153
|
-
normalized_start if start <= roll_func(normalized_start) else start
|
1154
|
-
)
|
1107
|
+
_dr_start = normalized_start if start <= roll_func(normalized_start) else start
|
1155
1108
|
|
1156
1109
|
if end is not None:
|
1157
1110
|
if periods is not None:
|
@@ -1181,9 +1134,7 @@ def _cal_WMQY_range(
|
|
1181
1134
|
normalized_end = end.to_period(grouping_period).end_time.normalize()
|
1182
1135
|
_dr_end = normalized_end if end >= roll_func(normalized_end) else end
|
1183
1136
|
|
1184
|
-
_range = (
|
1185
|
-
pd.date_range(_dr_start, _dr_end, periods, freq).to_series().apply(roll_func)
|
1186
|
-
)
|
1137
|
+
_range = pd.date_range(_dr_start, _dr_end, periods, freq).to_series().apply(roll_func)
|
1187
1138
|
|
1188
1139
|
# Ensure that Rolled Timestamps are in the desired range When given both Start and End
|
1189
1140
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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=
|
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=
|
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=
|
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
|
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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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
|
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=
|
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=
|
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=
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
388
|
+
return ZoneInfo("Asia/Shanghai")
|
387
389
|
|
388
390
|
@property
|
389
391
|
def regular_holidays(self):
|