pandas-market-calendars 4.3.2__py3-none-any.whl → 4.3.3__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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