pandas-market-calendars 4.3.2__py3-none-any.whl → 4.3.3__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 (46) hide show
  1. pandas_market_calendars/__init__.py +38 -38
  2. pandas_market_calendars/calendar_registry.py +53 -52
  3. pandas_market_calendars/calendar_utils.py +261 -261
  4. pandas_market_calendars/calendars/asx.py +66 -66
  5. pandas_market_calendars/calendars/bmf.py +206 -206
  6. pandas_market_calendars/calendars/bse.py +407 -407
  7. pandas_market_calendars/calendars/cboe.py +145 -145
  8. pandas_market_calendars/calendars/cme.py +402 -402
  9. pandas_market_calendars/calendars/cme_globex_agriculture.py +126 -127
  10. pandas_market_calendars/calendars/cme_globex_base.py +119 -119
  11. pandas_market_calendars/calendars/cme_globex_crypto.py +160 -147
  12. pandas_market_calendars/calendars/cme_globex_energy_and_metals.py +216 -216
  13. pandas_market_calendars/calendars/cme_globex_equities.py +123 -121
  14. pandas_market_calendars/calendars/cme_globex_fixed_income.py +136 -134
  15. pandas_market_calendars/calendars/cme_globex_fx.py +101 -92
  16. pandas_market_calendars/calendars/eurex.py +139 -139
  17. pandas_market_calendars/calendars/eurex_fixed_income.py +98 -0
  18. pandas_market_calendars/calendars/hkex.py +426 -426
  19. pandas_market_calendars/calendars/ice.py +81 -81
  20. pandas_market_calendars/calendars/iex.py +112 -111
  21. pandas_market_calendars/calendars/jpx.py +109 -109
  22. pandas_market_calendars/calendars/lse.py +114 -114
  23. pandas_market_calendars/calendars/mirror.py +130 -129
  24. pandas_market_calendars/calendars/nyse.py +1324 -1324
  25. pandas_market_calendars/calendars/ose.py +116 -116
  26. pandas_market_calendars/calendars/sifma.py +350 -335
  27. pandas_market_calendars/calendars/six.py +132 -132
  28. pandas_market_calendars/calendars/sse.py +311 -311
  29. pandas_market_calendars/calendars/tase.py +197 -195
  30. pandas_market_calendars/calendars/tsx.py +181 -181
  31. pandas_market_calendars/holidays/cme.py +385 -372
  32. pandas_market_calendars/holidays/cme_globex.py +214 -223
  33. pandas_market_calendars/holidays/cn.py +1455 -1455
  34. pandas_market_calendars/holidays/jp.py +398 -394
  35. pandas_market_calendars/holidays/nyse.py +1531 -1539
  36. pandas_market_calendars/holidays/oz.py +63 -65
  37. pandas_market_calendars/holidays/sifma.py +338 -350
  38. pandas_market_calendars/holidays/us.py +376 -377
  39. pandas_market_calendars/market_calendar.py +895 -895
  40. {pandas_market_calendars-4.3.2.dist-info → pandas_market_calendars-4.3.3.dist-info}/METADATA +3 -3
  41. pandas_market_calendars-4.3.3.dist-info/RECORD +50 -0
  42. pandas_market_calendars-4.3.2.dist-info/RECORD +0 -49
  43. {pandas_market_calendars-4.3.2.dist-info → pandas_market_calendars-4.3.3.dist-info}/LICENSE +0 -0
  44. {pandas_market_calendars-4.3.2.dist-info → pandas_market_calendars-4.3.3.dist-info}/NOTICE +0 -0
  45. {pandas_market_calendars-4.3.2.dist-info → pandas_market_calendars-4.3.3.dist-info}/WHEEL +0 -0
  46. {pandas_market_calendars-4.3.2.dist-info → pandas_market_calendars-4.3.3.dist-info}/top_level.txt +0 -0
@@ -1,261 +1,261 @@
1
- """
2
- Utilities to use with market_calendars
3
- """
4
- import itertools
5
- import warnings
6
-
7
- import pandas as pd
8
- import numpy as np
9
-
10
-
11
- def merge_schedules(schedules, how="outer"):
12
- """
13
- Given a list of schedules will return a merged schedule. The merge method (how) will either return the superset
14
- of any datetime when any schedule is open (outer) or only the datetime where all markets are open (inner)
15
-
16
- CAVEATS:
17
- * This does not work for schedules with breaks, the break information will be lost.
18
- * Only "market_open" and "market_close" are considered, other market times are not yet supported.
19
-
20
- :param schedules: list of schedules
21
- :param how: outer or inner
22
- :return: schedule DataFrame
23
- """
24
- all_cols = [x.columns for x in schedules]
25
- all_cols = list(itertools.chain(*all_cols))
26
- if ("break_start" in all_cols) or ("break_end" in all_cols):
27
- warnings.warn(
28
- "Merge schedules will drop the break_start and break_end from result."
29
- )
30
-
31
- result = schedules[0]
32
- for schedule in schedules[1:]:
33
- result = result.merge(schedule, how=how, right_index=True, left_index=True)
34
- if how == "outer":
35
- result["market_open"] = result.apply(
36
- lambda x: min(x.market_open_x, x.market_open_y), axis=1
37
- )
38
- result["market_close"] = result.apply(
39
- lambda x: max(x.market_close_x, x.market_close_y), axis=1
40
- )
41
- elif how == "inner":
42
- result["market_open"] = result.apply(
43
- lambda x: max(x.market_open_x, x.market_open_y), axis=1
44
- )
45
- result["market_close"] = result.apply(
46
- lambda x: min(x.market_close_x, x.market_close_y), axis=1
47
- )
48
- else:
49
- raise ValueError('how argument must be "inner" or "outer"')
50
- result = result[["market_open", "market_close"]]
51
- return result
52
-
53
-
54
- def convert_freq(index, frequency):
55
- """
56
- Converts a DateTimeIndex to a new lower frequency
57
-
58
- :param index: DateTimeIndex
59
- :param frequency: frequency string
60
- :return: DateTimeIndex
61
- """
62
- return pd.DataFrame(index=index).asfreq(frequency).index
63
-
64
-
65
- class _date_range:
66
- """
67
- This is a callable class that should be used by calling the already initiated instance: `date_range`.
68
- Given a schedule, it will return a DatetimeIndex with all of the valid datetimes at the frequency given.
69
-
70
- The schedule columns should all have the same time zone.
71
-
72
- The calculations will be made for each trading session. If the passed schedule-DataFrame doesn't have
73
- breaks, there is one trading session per day going from market_open to market_close, otherwise there are two,
74
- the first one going from market_open to break_start and the second one from break_end to market_close.
75
-
76
- *Any trading session where start == end is considered a 'no-trading session' and will always be dropped*
77
-
78
- CAVEATS:
79
- * Only "market_open", "market_close" (and, optionally, "breaak_start" and "break_end")
80
- are considered, other market times are not yet supported by this class.
81
-
82
- * If the difference between start and end of a trading session is smaller than an interval of the
83
- frequency, and closed= "right" and force_close = False, the whole session will disappear.
84
- This will also raise a warning.
85
-
86
-
87
- Signature:
88
- .__call__(self, schedule, frequency, closed='right', force_close=True, **kwargs)
89
-
90
- :param schedule: schedule of a calendar, which may or may not include break_start and break_end columns
91
- :param frequency: frequency string that is used by pd.Timedelta to calculate the timestamps
92
- this must be "1D" or higher frequency
93
- :param closed: the way the intervals are labeled
94
- 'right': use the end of the interval
95
- 'left': use the start of the interval
96
- None: (or 'both') use the end of the interval but include the start of the first interval (the open)
97
- :param force_close: how the last value of a trading session is handled
98
- True: guarantee that the close of the trading session is the last value
99
- False: guarantee that there is no value greater than the close of the trading session
100
- None: leave the last value as it is calculated based on the closed parameter
101
- :param kwargs: unused. Solely for compatibility.
102
-
103
-
104
- """
105
-
106
- def __init__(self, schedule=None, frequency=None, closed="right", force_close=True):
107
- if not closed in ("left", "right", "both", None):
108
- raise ValueError("closed must be 'left', 'right', 'both' or None.")
109
- elif not force_close in (True, False, None):
110
- raise ValueError("force_close must be True, False or None.")
111
-
112
- self.closed = closed
113
- self.force_close = force_close
114
- self.has_breaks = False
115
- if frequency is None:
116
- self.frequency = None
117
- else:
118
- self.frequency = pd.Timedelta(frequency)
119
- if self.frequency > pd.Timedelta("1D"):
120
- raise ValueError("Frequency must be 1D or higher frequency.")
121
-
122
- elif schedule.market_close.lt(schedule.market_open).any():
123
- raise ValueError(
124
- "Schedule contains rows where market_close < market_open,"
125
- " please correct the schedule"
126
- )
127
-
128
- if "break_start" in schedule:
129
- if not all(
130
- [
131
- schedule.market_open.le(schedule.break_start).all(),
132
- schedule.break_start.le(schedule.break_end).all(),
133
- schedule.break_end.le(schedule.market_close).all(),
134
- ]
135
- ):
136
- raise ValueError(
137
- "Not all rows match the condition: "
138
- "market_open <= break_start <= break_end <= market_close, "
139
- "please correct the schedule"
140
- )
141
- self.has_breaks = True
142
-
143
- def _check_overlap(self, schedule):
144
- """checks if calculated end times would overlap with the next start times.
145
- Only an issue when force_close is None and closed != left.
146
-
147
- :param schedule: pd.DataFrame with first column: 'start' and second column: 'end'
148
- :raises ValueError:"""
149
- if self.force_close is None and self.closed != "left":
150
- num_bars = self._calc_num_bars(schedule)
151
- end_times = schedule.start + num_bars * self.frequency
152
-
153
- if end_times.gt(schedule.start.shift(-1)).any():
154
- raise ValueError(
155
- f"The chosen frequency will lead to overlaps in the calculated index. "
156
- f"Either choose a higher frequency or avoid setting force_close to None "
157
- f"when setting closed to 'right', 'both' or None."
158
- )
159
-
160
- def _check_disappearing_session(self, schedule):
161
- """checks if requested frequency and schedule would lead to lost trading sessions.
162
- Only necessary when force_close = False and closed = "right".
163
-
164
- :param schedule: pd.DataFrame with first column: 'start' and second column: 'end'
165
- :raises UserWarning:"""
166
- if self.force_close is False and self.closed == "right":
167
- if (schedule.end - schedule.start).lt(self.frequency).any():
168
- warnings.warn(
169
- "An interval of the chosen frequency is larger than some of the trading sessions, "
170
- "while closed== 'right' and force_close is False. This will make those trading sessions "
171
- "disappear. Use a higher frequency or change the values of closed/force_close, to "
172
- "keep this from happening."
173
- )
174
-
175
- def _calc_num_bars(self, schedule):
176
- """calculate the number of timestamps needed for each trading session.
177
-
178
- :param schedule: pd.DataFrame with first column: 'start' and second column: 'end'
179
- :return: pd.Series of float64"""
180
- return np.ceil((schedule.end - schedule.start) / self.frequency)
181
-
182
- def _calc_time_series(self, schedule):
183
- """Method used by date_range to calculate the trading index.
184
-
185
- :param schedule: pd.DataFrame with first column: 'start' and second column: 'end'
186
- :return: pd.Series of datetime64[ns, UTC]"""
187
- num_bars = self._calc_num_bars(schedule)
188
-
189
- # ---> calculate the desired timeseries:
190
- if self.closed == "left":
191
- opens = schedule.start.repeat(num_bars) # keep as is
192
- time_series = (
193
- opens.groupby(opens.index).cumcount()
194
- ) * self.frequency + opens
195
- elif self.closed == "right":
196
- opens = schedule.start.repeat(num_bars) # dont add row but shift up
197
- time_series = (
198
- opens.groupby(opens.index).cumcount() + 1
199
- ) * self.frequency + opens
200
- else:
201
- num_bars += 1
202
- opens = schedule.start.repeat(num_bars) # add row but dont shift up
203
- time_series = (
204
- opens.groupby(opens.index).cumcount()
205
- ) * self.frequency + opens
206
-
207
- if not self.force_close is None:
208
- time_series = time_series[time_series.le(schedule.end.repeat(num_bars))]
209
- if self.force_close:
210
- time_series = pd.concat([time_series, schedule.end]).sort_values()
211
-
212
- return time_series
213
-
214
- def __call__(self, schedule, frequency, closed="right", force_close=True, **kwargs):
215
- """
216
- See class docstring for more information.
217
-
218
- :param schedule: schedule of a calendar, which may or may not include break_start and break_end columns
219
- :param frequency: frequency string that is used by pd.Timedelta to calculate the timestamps
220
- this must be "1D" or higher frequency
221
- :param closed: the way the intervals are labeled
222
- 'right': use the end of the interval
223
- 'left': use the start of the interval
224
- None: (or 'both') use the end of the interval but include the start of the first interval
225
- :param force_close: how the last value of a trading session is handled
226
- True: guarantee that the close of the trading session is the last value
227
- False: guarantee that there is no value greater than the close of the trading session
228
- None: leave the last value as it is calculated based on the closed parameter
229
- :param kwargs: unused. Solely for compatibility.
230
- :return: pd.DatetimeIndex of datetime64[ns, UTC]
231
- """
232
- self.__init__(schedule, frequency, closed, force_close)
233
- if self.has_breaks:
234
- # rearrange the schedule, to make every row one session
235
- before = schedule[["market_open", "break_start"]].set_index(
236
- schedule["market_open"]
237
- )
238
- after = schedule[["break_end", "market_close"]].set_index(
239
- schedule["break_end"]
240
- )
241
- before.columns = after.columns = ["start", "end"]
242
- schedule = pd.concat([before, after]).sort_index()
243
-
244
- else:
245
- schedule = schedule.rename(
246
- columns={"market_open": "start", "market_close": "end"}
247
- )
248
-
249
- schedule = schedule[
250
- schedule.start.ne(schedule.end)
251
- ] # drop the 'no-trading sessions'
252
- self._check_overlap(schedule)
253
- self._check_disappearing_session(schedule)
254
-
255
- time_series = self._calc_time_series(schedule)
256
-
257
- time_series.name = None
258
- return pd.DatetimeIndex(time_series.drop_duplicates())
259
-
260
-
261
- date_range = _date_range()
1
+ """
2
+ Utilities to use with market_calendars
3
+ """
4
+ import itertools
5
+ import warnings
6
+
7
+ import numpy as np
8
+ import pandas as pd
9
+
10
+
11
+ def merge_schedules(schedules, how="outer"):
12
+ """
13
+ Given a list of schedules will return a merged schedule. The merge method (how) will either return the superset
14
+ of any datetime when any schedule is open (outer) or only the datetime where all markets are open (inner)
15
+
16
+ CAVEATS:
17
+ * This does not work for schedules with breaks, the break information will be lost.
18
+ * Only "market_open" and "market_close" are considered, other market times are not yet supported.
19
+
20
+ :param schedules: list of schedules
21
+ :param how: outer or inner
22
+ :return: schedule DataFrame
23
+ """
24
+ all_cols = [x.columns for x in schedules]
25
+ all_cols = list(itertools.chain(*all_cols))
26
+ if ("break_start" in all_cols) or ("break_end" in all_cols):
27
+ warnings.warn(
28
+ "Merge schedules will drop the break_start and break_end from result."
29
+ )
30
+
31
+ result = schedules[0]
32
+ for schedule in schedules[1:]:
33
+ result = result.merge(schedule, how=how, right_index=True, left_index=True)
34
+ if how == "outer":
35
+ result["market_open"] = result.apply(
36
+ lambda x: min(x.market_open_x, x.market_open_y), axis=1
37
+ )
38
+ result["market_close"] = result.apply(
39
+ lambda x: max(x.market_close_x, x.market_close_y), axis=1
40
+ )
41
+ elif how == "inner":
42
+ result["market_open"] = result.apply(
43
+ lambda x: max(x.market_open_x, x.market_open_y), axis=1
44
+ )
45
+ result["market_close"] = result.apply(
46
+ lambda x: min(x.market_close_x, x.market_close_y), axis=1
47
+ )
48
+ else:
49
+ raise ValueError('how argument must be "inner" or "outer"')
50
+ result = result[["market_open", "market_close"]]
51
+ return result
52
+
53
+
54
+ def convert_freq(index, frequency):
55
+ """
56
+ Converts a DateTimeIndex to a new lower frequency
57
+
58
+ :param index: DateTimeIndex
59
+ :param frequency: frequency string
60
+ :return: DateTimeIndex
61
+ """
62
+ return pd.DataFrame(index=index).asfreq(frequency).index
63
+
64
+
65
+ class _date_range:
66
+ """
67
+ This is a callable class that should be used by calling the already initiated instance: `date_range`.
68
+ Given a schedule, it will return a DatetimeIndex with all of the valid datetimes at the frequency given.
69
+
70
+ The schedule columns should all have the same time zone.
71
+
72
+ The calculations will be made for each trading session. If the passed schedule-DataFrame doesn't have
73
+ breaks, there is one trading session per day going from market_open to market_close, otherwise there are two,
74
+ the first one going from market_open to break_start and the second one from break_end to market_close.
75
+
76
+ *Any trading session where start == end is considered a 'no-trading session' and will always be dropped*
77
+
78
+ CAVEATS:
79
+ * Only "market_open", "market_close" (and, optionally, "breaak_start" and "break_end")
80
+ are considered, other market times are not yet supported by this class.
81
+
82
+ * If the difference between start and end of a trading session is smaller than an interval of the
83
+ frequency, and closed= "right" and force_close = False, the whole session will disappear.
84
+ This will also raise a warning.
85
+
86
+
87
+ Signature:
88
+ .__call__(self, schedule, frequency, closed='right', force_close=True, **kwargs)
89
+
90
+ :param schedule: schedule of a calendar, which may or may not include break_start and break_end columns
91
+ :param frequency: frequency string that is used by pd.Timedelta to calculate the timestamps
92
+ this must be "1D" or higher frequency
93
+ :param closed: the way the intervals are labeled
94
+ 'right': use the end of the interval
95
+ 'left': use the start of the interval
96
+ None: (or 'both') use the end of the interval but include the start of the first interval (the open)
97
+ :param force_close: how the last value of a trading session is handled
98
+ True: guarantee that the close of the trading session is the last value
99
+ False: guarantee that there is no value greater than the close of the trading session
100
+ None: leave the last value as it is calculated based on the closed parameter
101
+ :param kwargs: unused. Solely for compatibility.
102
+
103
+
104
+ """
105
+
106
+ def __init__(self, schedule=None, frequency=None, closed="right", force_close=True):
107
+ if closed not in ("left", "right", "both", None):
108
+ raise ValueError("closed must be 'left', 'right', 'both' or None.")
109
+ elif force_close not in (True, False, None):
110
+ raise ValueError("force_close must be True, False or None.")
111
+
112
+ self.closed = closed
113
+ self.force_close = force_close
114
+ self.has_breaks = False
115
+ if frequency is None:
116
+ self.frequency = None
117
+ else:
118
+ self.frequency = pd.Timedelta(frequency)
119
+ if self.frequency > pd.Timedelta("1D"):
120
+ raise ValueError("Frequency must be 1D or higher frequency.")
121
+
122
+ elif schedule.market_close.lt(schedule.market_open).any():
123
+ raise ValueError(
124
+ "Schedule contains rows where market_close < market_open,"
125
+ " please correct the schedule"
126
+ )
127
+
128
+ if "break_start" in schedule:
129
+ if not all(
130
+ [
131
+ schedule.market_open.le(schedule.break_start).all(),
132
+ schedule.break_start.le(schedule.break_end).all(),
133
+ schedule.break_end.le(schedule.market_close).all(),
134
+ ]
135
+ ):
136
+ raise ValueError(
137
+ "Not all rows match the condition: "
138
+ "market_open <= break_start <= break_end <= market_close, "
139
+ "please correct the schedule"
140
+ )
141
+ self.has_breaks = True
142
+
143
+ def _check_overlap(self, schedule):
144
+ """checks if calculated end times would overlap with the next start times.
145
+ Only an issue when force_close is None and closed != left.
146
+
147
+ :param schedule: pd.DataFrame with first column: 'start' and second column: 'end'
148
+ :raises ValueError:"""
149
+ if self.force_close is None and self.closed != "left":
150
+ num_bars = self._calc_num_bars(schedule)
151
+ end_times = schedule.start + num_bars * self.frequency
152
+
153
+ if end_times.gt(schedule.start.shift(-1)).any():
154
+ raise ValueError(
155
+ "The chosen frequency will lead to overlaps in the calculated index. "
156
+ "Either choose a higher frequency or avoid setting force_close to None "
157
+ "when setting closed to 'right', 'both' or None."
158
+ )
159
+
160
+ def _check_disappearing_session(self, schedule):
161
+ """checks if requested frequency and schedule would lead to lost trading sessions.
162
+ Only necessary when force_close = False and closed = "right".
163
+
164
+ :param schedule: pd.DataFrame with first column: 'start' and second column: 'end'
165
+ :raises UserWarning:"""
166
+ if self.force_close is False and self.closed == "right":
167
+ if (schedule.end - schedule.start).lt(self.frequency).any():
168
+ warnings.warn(
169
+ "An interval of the chosen frequency is larger than some of the trading sessions, "
170
+ "while closed== 'right' and force_close is False. This will make those trading sessions "
171
+ "disappear. Use a higher frequency or change the values of closed/force_close, to "
172
+ "keep this from happening."
173
+ )
174
+
175
+ def _calc_num_bars(self, schedule):
176
+ """calculate the number of timestamps needed for each trading session.
177
+
178
+ :param schedule: pd.DataFrame with first column: 'start' and second column: 'end'
179
+ :return: pd.Series of float64"""
180
+ return np.ceil((schedule.end - schedule.start) / self.frequency)
181
+
182
+ def _calc_time_series(self, schedule):
183
+ """Method used by date_range to calculate the trading index.
184
+
185
+ :param schedule: pd.DataFrame with first column: 'start' and second column: 'end'
186
+ :return: pd.Series of datetime64[ns, UTC]"""
187
+ num_bars = self._calc_num_bars(schedule)
188
+
189
+ # ---> calculate the desired timeseries:
190
+ if self.closed == "left":
191
+ opens = schedule.start.repeat(num_bars) # keep as is
192
+ time_series = (
193
+ opens.groupby(opens.index).cumcount()
194
+ ) * self.frequency + opens
195
+ elif self.closed == "right":
196
+ opens = schedule.start.repeat(num_bars) # dont add row but shift up
197
+ time_series = (
198
+ opens.groupby(opens.index).cumcount() + 1
199
+ ) * self.frequency + opens
200
+ else:
201
+ num_bars += 1
202
+ opens = schedule.start.repeat(num_bars) # add row but dont shift up
203
+ time_series = (
204
+ opens.groupby(opens.index).cumcount()
205
+ ) * self.frequency + opens
206
+
207
+ if self.force_close is not None:
208
+ time_series = time_series[time_series.le(schedule.end.repeat(num_bars))]
209
+ if self.force_close:
210
+ time_series = pd.concat([time_series, schedule.end]).sort_values()
211
+
212
+ return time_series
213
+
214
+ def __call__(self, schedule, frequency, closed="right", force_close=True, **kwargs):
215
+ """
216
+ See class docstring for more information.
217
+
218
+ :param schedule: schedule of a calendar, which may or may not include break_start and break_end columns
219
+ :param frequency: frequency string that is used by pd.Timedelta to calculate the timestamps
220
+ this must be "1D" or higher frequency
221
+ :param closed: the way the intervals are labeled
222
+ 'right': use the end of the interval
223
+ 'left': use the start of the interval
224
+ None: (or 'both') use the end of the interval but include the start of the first interval
225
+ :param force_close: how the last value of a trading session is handled
226
+ True: guarantee that the close of the trading session is the last value
227
+ False: guarantee that there is no value greater than the close of the trading session
228
+ None: leave the last value as it is calculated based on the closed parameter
229
+ :param kwargs: unused. Solely for compatibility.
230
+ :return: pd.DatetimeIndex of datetime64[ns, UTC]
231
+ """
232
+ self.__init__(schedule, frequency, closed, force_close)
233
+ if self.has_breaks:
234
+ # rearrange the schedule, to make every row one session
235
+ before = schedule[["market_open", "break_start"]].set_index(
236
+ schedule["market_open"]
237
+ )
238
+ after = schedule[["break_end", "market_close"]].set_index(
239
+ schedule["break_end"]
240
+ )
241
+ before.columns = after.columns = ["start", "end"]
242
+ schedule = pd.concat([before, after]).sort_index()
243
+
244
+ else:
245
+ schedule = schedule.rename(
246
+ columns={"market_open": "start", "market_close": "end"}
247
+ )
248
+
249
+ schedule = schedule[
250
+ schedule.start.ne(schedule.end)
251
+ ] # drop the 'no-trading sessions'
252
+ self._check_overlap(schedule)
253
+ self._check_disappearing_session(schedule)
254
+
255
+ time_series = self._calc_time_series(schedule)
256
+
257
+ time_series.name = None
258
+ return pd.DatetimeIndex(time_series.drop_duplicates())
259
+
260
+
261
+ date_range = _date_range()
@@ -1,66 +1,66 @@
1
- from datetime import time
2
-
3
- from pandas.tseries.holiday import AbstractHolidayCalendar, GoodFriday, EasterMonday
4
- from pytz import timezone
5
-
6
- from pandas_market_calendars.holidays.oz import *
7
- from pandas_market_calendars.market_calendar import MarketCalendar
8
-
9
- AbstractHolidayCalendar.start_date = "2011-01-01"
10
-
11
-
12
- class ASXExchangeCalendar(MarketCalendar):
13
- """
14
- Open Time: 10:00 AM, Australia/Sydney
15
- Close Time: 4:10 PM, Australia/Sydney
16
-
17
-
18
- Regularly-Observed Holidays:
19
- - New Year's Day (observed on Monday when Jan 1 is a Saturday or Sunday)
20
- - Australia Day (observed on Monday when Jan 26 is a Saturday or Sunday)
21
- - Good Friday (two days before Easter Sunday)
22
- - Easter Monday (the Monday after Easter Sunday)
23
- - ANZAC Day (April 25)
24
- - Queen's Birthday (second Monday in June)
25
- - Christmas Day (December 25, Saturday/Sunday to Monday)
26
- - Boxing Day (December 26, Saturday to Monday, Sunday to Tuesday)
27
-
28
-
29
- Regularly-Observed Early Closes:
30
- - Last Business Day before Christmas Day
31
- - Last Business Day of the Year
32
-
33
- """
34
-
35
- aliases = ["ASX"]
36
- regular_market_times = {
37
- "market_open": ((None, time(10)),),
38
- "market_close": ((None, time(16, 10)),),
39
- }
40
-
41
- @property
42
- def name(self):
43
- return "ASX"
44
-
45
- @property
46
- def tz(self):
47
- return timezone("Australia/Sydney")
48
-
49
- @property
50
- def regular_holidays(self):
51
- return AbstractHolidayCalendar(
52
- rules=[
53
- OZNewYearsDay,
54
- AustraliaDay,
55
- AnzacDay,
56
- QueensBirthday,
57
- Christmas,
58
- BoxingDay,
59
- GoodFriday,
60
- EasterMonday,
61
- ]
62
- )
63
-
64
- @property
65
- def adhoc_holidays(self):
66
- return UniqueCloses
1
+ from datetime import time
2
+
3
+ from pandas.tseries.holiday import AbstractHolidayCalendar, GoodFriday, EasterMonday
4
+ from pytz import timezone
5
+
6
+ from pandas_market_calendars.holidays.oz import *
7
+ from pandas_market_calendars.market_calendar import MarketCalendar
8
+
9
+ AbstractHolidayCalendar.start_date = "2011-01-01"
10
+
11
+
12
+ class ASXExchangeCalendar(MarketCalendar):
13
+ """
14
+ Open Time: 10:00 AM, Australia/Sydney
15
+ Close Time: 4:10 PM, Australia/Sydney
16
+
17
+
18
+ Regularly-Observed Holidays:
19
+ - New Year's Day (observed on Monday when Jan 1 is a Saturday or Sunday)
20
+ - Australia Day (observed on Monday when Jan 26 is a Saturday or Sunday)
21
+ - Good Friday (two days before Easter Sunday)
22
+ - Easter Monday (the Monday after Easter Sunday)
23
+ - ANZAC Day (April 25)
24
+ - Queen's Birthday (second Monday in June)
25
+ - Christmas Day (December 25, Saturday/Sunday to Monday)
26
+ - Boxing Day (December 26, Saturday to Monday, Sunday to Tuesday)
27
+
28
+
29
+ Regularly-Observed Early Closes:
30
+ - Last Business Day before Christmas Day
31
+ - Last Business Day of the Year
32
+
33
+ """
34
+
35
+ aliases = ["ASX"]
36
+ regular_market_times = {
37
+ "market_open": ((None, time(10)),),
38
+ "market_close": ((None, time(16, 10)),),
39
+ }
40
+
41
+ @property
42
+ def name(self):
43
+ return "ASX"
44
+
45
+ @property
46
+ def tz(self):
47
+ return timezone("Australia/Sydney")
48
+
49
+ @property
50
+ def regular_holidays(self):
51
+ return AbstractHolidayCalendar(
52
+ rules=[
53
+ OZNewYearsDay,
54
+ AustraliaDay,
55
+ AnzacDay,
56
+ QueensBirthday,
57
+ Christmas,
58
+ BoxingDay,
59
+ GoodFriday,
60
+ EasterMonday,
61
+ ]
62
+ )
63
+
64
+ @property
65
+ def adhoc_holidays(self):
66
+ return UniqueCloses