pandas-market-calendars 4.4.0__py3-none-any.whl → 4.6.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/__init__.py +2 -1
- pandas_market_calendars/calendar_registry.py +5 -1
- pandas_market_calendars/calendar_utils.py +1102 -163
- pandas_market_calendars/calendars/cme.py +3 -0
- pandas_market_calendars/calendars/cme_globex_agriculture.py +46 -0
- pandas_market_calendars/calendars/eurex.py +0 -8
- pandas_market_calendars/calendars/hkex.py +3 -0
- pandas_market_calendars/calendars/iex.py +43 -4
- pandas_market_calendars/calendars/jpx.py +6 -2
- pandas_market_calendars/calendars/mirror.py +19 -0
- pandas_market_calendars/calendars/nyse.py +154 -12
- pandas_market_calendars/calendars/sse.py +1 -1
- pandas_market_calendars/calendars/tase.py +24 -1
- pandas_market_calendars/holidays/cn.py +21 -0
- pandas_market_calendars/holidays/jpx_equinox.py +1 -0
- pandas_market_calendars/holidays/nyse.py +5 -0
- pandas_market_calendars/market_calendar.py +185 -23
- {pandas_market_calendars-4.4.0.dist-info → pandas_market_calendars-4.6.0.dist-info}/METADATA +13 -9
- {pandas_market_calendars-4.4.0.dist-info → pandas_market_calendars-4.6.0.dist-info}/RECORD +23 -23
- {pandas_market_calendars-4.4.0.dist-info → pandas_market_calendars-4.6.0.dist-info}/WHEEL +1 -1
- {pandas_market_calendars-4.4.0.dist-info → pandas_market_calendars-4.6.0.dist-info}/LICENSE +0 -0
- {pandas_market_calendars-4.4.0.dist-info → pandas_market_calendars-4.6.0.dist-info}/NOTICE +0 -0
- {pandas_market_calendars-4.4.0.dist-info → pandas_market_calendars-4.6.0.dist-info}/top_level.txt +0 -0
@@ -31,6 +31,7 @@ from pandas_market_calendars.holidays.us import (
|
|
31
31
|
ChristmasEveBefore1993,
|
32
32
|
ChristmasEveInOrAfter1993,
|
33
33
|
USBlackFridayInOrAfter1993,
|
34
|
+
USJuneteenthAfter2022,
|
34
35
|
USIndependenceDay,
|
35
36
|
USMartinLutherKingJrAfter1998,
|
36
37
|
USMemorialDay,
|
@@ -98,6 +99,7 @@ class CMEEquityExchangeCalendar(MarketCalendar):
|
|
98
99
|
USPresidentsDay,
|
99
100
|
USMemorialDay,
|
100
101
|
USLaborDay,
|
102
|
+
USJuneteenthAfter2022,
|
101
103
|
USIndependenceDay,
|
102
104
|
USThanksgivingDay,
|
103
105
|
USBlackFridayInOrAfter1993,
|
@@ -158,6 +160,7 @@ class CMEAgricultureExchangeCalendar(MarketCalendar):
|
|
158
160
|
USPresidentsDay,
|
159
161
|
GoodFriday,
|
160
162
|
USMemorialDay,
|
163
|
+
USJuneteenthAfter2022,
|
161
164
|
USIndependenceDay,
|
162
165
|
USLaborDay,
|
163
166
|
USThanksgivingDay,
|
@@ -124,3 +124,49 @@ class CMEGlobexLivestockExchangeCalendar(CMEGlobexAgricultureExchangeCalendar):
|
|
124
124
|
),
|
125
125
|
)
|
126
126
|
]
|
127
|
+
|
128
|
+
|
129
|
+
class CMEGlobexGrainsAndOilseedsExchangeCalendar(CMEGlobexAgricultureExchangeCalendar):
|
130
|
+
"""
|
131
|
+
Exchange calendar for CME for Grains & Oilseeds
|
132
|
+
|
133
|
+
https://www.cmegroup.com/trading/agricultural/grain-and-oilseed.html
|
134
|
+
|
135
|
+
GLOBEX Trading Times
|
136
|
+
https://www.cmegroup.com/markets/agriculture/oilseeds/soybean.contractSpecs.html
|
137
|
+
https://www.cmegroup.com/markets/agriculture/grains/corn.contractSpecs.html
|
138
|
+
https://www.cmegroup.com/markets/agriculture/grains/wheat.contractSpecs.html
|
139
|
+
Sunday - Friday: 7:00 p.m. - 7:45 a.m. CT and Monday - Friday: 8:30 a.m. - 1:20 p.m. CT
|
140
|
+
"""
|
141
|
+
|
142
|
+
aliases = [
|
143
|
+
"CMEGlobex_Grains",
|
144
|
+
"CMEGlobex_Oilseeds",
|
145
|
+
]
|
146
|
+
|
147
|
+
regular_market_times = {
|
148
|
+
"market_open": ((None, time(19), -1),), # offset by -1 day
|
149
|
+
"market_close": ((None, time(13, 20)),),
|
150
|
+
"break_start": ((None, time(7, 45)),),
|
151
|
+
"break_end": ((None, time(8, 30)),),
|
152
|
+
}
|
153
|
+
|
154
|
+
@property
|
155
|
+
def name(self):
|
156
|
+
return "CMEGlobex_GrainsAndOilseeds"
|
157
|
+
|
158
|
+
@property
|
159
|
+
def regular_holidays(self):
|
160
|
+
return AbstractHolidayCalendar(
|
161
|
+
rules=[
|
162
|
+
USNewYearsDay,
|
163
|
+
USMartinLutherKingJrAfter1998,
|
164
|
+
USPresidentsDay,
|
165
|
+
GoodFriday,
|
166
|
+
USMemorialDay,
|
167
|
+
USIndependenceDay,
|
168
|
+
USLaborDay,
|
169
|
+
USThanksgivingDay,
|
170
|
+
Christmas,
|
171
|
+
]
|
172
|
+
)
|
@@ -43,13 +43,6 @@ MayBank = Holiday(
|
|
43
43
|
day=1,
|
44
44
|
days_of_week=(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY),
|
45
45
|
)
|
46
|
-
# German National Holiday (Tag der Deutschen Einheit)
|
47
|
-
GermanNationalDay = Holiday(
|
48
|
-
"Tag der Deutschen Einheit",
|
49
|
-
month=10,
|
50
|
-
day=3,
|
51
|
-
days_of_week=(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY),
|
52
|
-
)
|
53
46
|
# Christmas Eve
|
54
47
|
ChristmasEve = Holiday(
|
55
48
|
"Christmas Eve",
|
@@ -116,7 +109,6 @@ class EUREXExchangeCalendar(MarketCalendar):
|
|
116
109
|
GoodFriday,
|
117
110
|
EasterMonday,
|
118
111
|
MayBank,
|
119
|
-
GermanNationalDay,
|
120
112
|
Christmas,
|
121
113
|
WeekendChristmas,
|
122
114
|
BoxingDay,
|
@@ -354,6 +354,9 @@ HKClosedDay = [
|
|
354
354
|
Timestamp("2016-10-21", tz="UTC"), # 台风海马1622
|
355
355
|
# Timestamp(2017-06-12', tz='UTC'), # 台风苗柏1702,期货夜盘17:35休市
|
356
356
|
Timestamp("2017-08-23", tz="UTC"), # 台风天鸽1713
|
357
|
+
Timestamp("2023-07-17", tz="UTC"), # Typhoon closure
|
358
|
+
Timestamp("2023-09-01", tz="UTC"), # Typhoon closure
|
359
|
+
Timestamp("2023-09-08", tz="UTC"), # Typhoon closure
|
357
360
|
]
|
358
361
|
|
359
362
|
|
@@ -1,9 +1,13 @@
|
|
1
1
|
from datetime import time
|
2
2
|
from itertools import chain
|
3
3
|
|
4
|
+
from pandas import Timestamp, DatetimeIndex, Timedelta
|
4
5
|
from pandas.tseries.holiday import AbstractHolidayCalendar
|
5
6
|
from pytz import timezone
|
6
7
|
|
8
|
+
from typing import Literal, Union
|
9
|
+
from pandas_market_calendars import calendar_utils as u
|
10
|
+
|
7
11
|
from pandas_market_calendars.holidays.nyse import (
|
8
12
|
USPresidentsDay,
|
9
13
|
GoodFriday,
|
@@ -106,7 +110,42 @@ class IEXExchangeCalendar(NYSEExchangeCalendar):
|
|
106
110
|
return []
|
107
111
|
|
108
112
|
def valid_days(self, start_date, end_date, tz="UTC"):
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
+
start_date = Timestamp(start_date)
|
114
|
+
if start_date.tz is not None:
|
115
|
+
# Ensure valid Comparison to "2013-08-25" is possible
|
116
|
+
start_date.tz_convert(self.tz).tz_localize(None)
|
117
|
+
|
118
|
+
# Limit Start_date to the Exchange's Open
|
119
|
+
start_date = max(start_date, Timestamp("2013-08-25"))
|
120
|
+
return super().valid_days(start_date, end_date, tz=tz)
|
121
|
+
|
122
|
+
def date_range_htf(
|
123
|
+
self,
|
124
|
+
frequency: Union[str, Timedelta, int, float],
|
125
|
+
start: Union[str, Timestamp, int, float, None] = None,
|
126
|
+
end: Union[str, Timestamp, int, float, None] = None,
|
127
|
+
periods: Union[int, None] = None,
|
128
|
+
closed: Union[Literal["left", "right"], None] = "right",
|
129
|
+
*,
|
130
|
+
day_anchor: u.Day_Anchor = "SUN",
|
131
|
+
month_anchor: u.Month_Anchor = "JAN",
|
132
|
+
) -> DatetimeIndex:
|
133
|
+
|
134
|
+
start, end, periods = u._error_check_htf_range(start, end, periods)
|
135
|
+
|
136
|
+
# Cap Beginning and end dates to the opening date of IEX
|
137
|
+
if start is not None:
|
138
|
+
start = max(start, Timestamp("2013-08-25"))
|
139
|
+
if end is not None:
|
140
|
+
end = max(end, Timestamp("2013-08-25"))
|
141
|
+
|
142
|
+
return u.date_range_htf(
|
143
|
+
self.holidays(),
|
144
|
+
frequency,
|
145
|
+
start,
|
146
|
+
end,
|
147
|
+
periods,
|
148
|
+
closed,
|
149
|
+
day_anchor=day_anchor,
|
150
|
+
month_anchor=month_anchor,
|
151
|
+
)
|
@@ -21,13 +21,17 @@ class JPXExchangeCalendar(MarketCalendar):
|
|
21
21
|
|
22
22
|
Open Time: 9:31 AM, Asia/Tokyo
|
23
23
|
LUNCH BREAK :facepalm: : 11:30 AM - 12:30 PM Asia/Tokyo
|
24
|
-
Close Time:
|
24
|
+
Close Time: 3:30 PM, Asia/Tokyo
|
25
|
+
|
26
|
+
Market close of Japan changed from 3:00 PM to 3:30 PM on November 5, 2024
|
27
|
+
Reference:
|
28
|
+
https://www.jpx.co.jp/english/equities/trading/domestic/tvdivq0000006blj-att/tradinghours_eg.pdf
|
25
29
|
"""
|
26
30
|
|
27
31
|
aliases = ["JPX", "XJPX"]
|
28
32
|
regular_market_times = {
|
29
33
|
"market_open": ((None, time(9)),),
|
30
|
-
"market_close": ((None, time(15)),),
|
34
|
+
"market_close": ((None, time(15)), ("2024-11-05", time(15, 30))),
|
31
35
|
"break_start": ((None, time(11, 30)),),
|
32
36
|
"break_end": ((None, time(12, 30)),),
|
33
37
|
}
|
@@ -8,6 +8,8 @@ import exchange_calendars
|
|
8
8
|
|
9
9
|
from pandas_market_calendars.market_calendar import MarketCalendar
|
10
10
|
|
11
|
+
DAYMASKS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
|
12
|
+
|
11
13
|
|
12
14
|
class TradingCalendar(MarketCalendar):
|
13
15
|
"""
|
@@ -97,6 +99,23 @@ class TradingCalendar(MarketCalendar):
|
|
97
99
|
def special_closes_adhoc(self):
|
98
100
|
return self._ec.special_closes_adhoc
|
99
101
|
|
102
|
+
@property
|
103
|
+
def weekmask(self):
|
104
|
+
if hasattr(self._ec, "weekmask"):
|
105
|
+
if "1" in self._ec.weekmask or "0" in self._ec.weekmask:
|
106
|
+
# Convert 1s & 0s to Day Abbreviations
|
107
|
+
return " ".join(
|
108
|
+
[
|
109
|
+
DAYMASKS[i]
|
110
|
+
for i, val in enumerate(self._ec.weekmask)
|
111
|
+
if val == "1"
|
112
|
+
]
|
113
|
+
)
|
114
|
+
else:
|
115
|
+
return self._ec.weekmask
|
116
|
+
else:
|
117
|
+
return "Mon Tue Wed Thu Fri"
|
118
|
+
|
100
119
|
|
101
120
|
calendars = exchange_calendars.calendar_utils._default_calendar_factories # noqa
|
102
121
|
|
@@ -18,8 +18,12 @@ from itertools import chain
|
|
18
18
|
|
19
19
|
import pandas as pd
|
20
20
|
from pandas.tseries.holiday import AbstractHolidayCalendar
|
21
|
+
from pandas.tseries.offsets import CustomBusinessDay
|
21
22
|
from pytz import timezone
|
22
23
|
|
24
|
+
from typing import Literal, Union
|
25
|
+
from pandas_market_calendars import calendar_utils as u
|
26
|
+
|
23
27
|
from pandas_market_calendars.holidays.nyse import (
|
24
28
|
# Always Celebrated Holidays
|
25
29
|
USNewYearsDayNYSEpost1952,
|
@@ -297,6 +301,8 @@ from pandas_market_calendars.holidays.nyse import (
|
|
297
301
|
HurricaneSandyClosings2012,
|
298
302
|
# 2018
|
299
303
|
GeorgeHWBushDeath2018,
|
304
|
+
# 2025
|
305
|
+
JimmyCarterDeath2025,
|
300
306
|
)
|
301
307
|
from pandas_market_calendars.market_calendar import MarketCalendar
|
302
308
|
|
@@ -828,7 +834,28 @@ class NYSEExchangeCalendar(MarketCalendar):
|
|
828
834
|
|
829
835
|
@property
|
830
836
|
def weekmask(self):
|
831
|
-
return "Mon Tue Wed Thu Fri
|
837
|
+
return "Mon Tue Wed Thu Fri"
|
838
|
+
|
839
|
+
@property
|
840
|
+
def weekmask_pre_1952(self):
|
841
|
+
return "Mon Tue Wed Thu Fri Sat"
|
842
|
+
|
843
|
+
def holidays_pre_1952(self):
|
844
|
+
"""
|
845
|
+
NYSE Market open on Saturdays pre 5/24/1952.
|
846
|
+
CustomBusinessDay object that can be used inplace of holidays() for dates prior to crossover
|
847
|
+
|
848
|
+
:return: CustomBusinessDay object of holidays
|
849
|
+
"""
|
850
|
+
if hasattr(self, "_holidays_hist"):
|
851
|
+
return self._holidays_hist
|
852
|
+
|
853
|
+
self._holidays_hist = CustomBusinessDay(
|
854
|
+
holidays=self.adhoc_holidays,
|
855
|
+
calendar=self.regular_holidays,
|
856
|
+
weekmask=self.weekmask_pre_1952,
|
857
|
+
)
|
858
|
+
return self._holidays_hist
|
832
859
|
|
833
860
|
@property
|
834
861
|
def regular_holidays(self):
|
@@ -961,10 +988,10 @@ class NYSEExchangeCalendar(MarketCalendar):
|
|
961
988
|
September11Closings2001,
|
962
989
|
HurricaneSandyClosings2012,
|
963
990
|
GeorgeHWBushDeath2018,
|
991
|
+
JimmyCarterDeath2025,
|
964
992
|
)
|
965
993
|
)
|
966
994
|
|
967
|
-
#
|
968
995
|
@property
|
969
996
|
def special_closes(self):
|
970
997
|
return [
|
@@ -1085,7 +1112,6 @@ class NYSEExchangeCalendar(MarketCalendar):
|
|
1085
1112
|
),
|
1086
1113
|
]
|
1087
1114
|
|
1088
|
-
#
|
1089
1115
|
@property
|
1090
1116
|
def special_closes_adhoc(self):
|
1091
1117
|
def _union_many(indexes):
|
@@ -1140,7 +1166,6 @@ class NYSEExchangeCalendar(MarketCalendar):
|
|
1140
1166
|
),
|
1141
1167
|
]
|
1142
1168
|
|
1143
|
-
#
|
1144
1169
|
@property
|
1145
1170
|
def special_opens(self):
|
1146
1171
|
return [
|
@@ -1254,7 +1279,6 @@ class NYSEExchangeCalendar(MarketCalendar):
|
|
1254
1279
|
),
|
1255
1280
|
]
|
1256
1281
|
|
1257
|
-
#
|
1258
1282
|
@property
|
1259
1283
|
def special_opens_adhoc(self):
|
1260
1284
|
return [
|
@@ -1272,7 +1296,7 @@ class NYSEExchangeCalendar(MarketCalendar):
|
|
1272
1296
|
),
|
1273
1297
|
]
|
1274
1298
|
|
1275
|
-
# Override market_calendar.py
|
1299
|
+
# Override market_calendar.py to split calc between pre & post 1952 Saturday Close
|
1276
1300
|
def valid_days(self, start_date, end_date, tz="UTC"):
|
1277
1301
|
"""
|
1278
1302
|
Get a DatetimeIndex of valid open business days.
|
@@ -1282,7 +1306,8 @@ class NYSEExchangeCalendar(MarketCalendar):
|
|
1282
1306
|
:param tz: time zone in either string or pytz.timezone
|
1283
1307
|
:return: DatetimeIndex of valid business days
|
1284
1308
|
"""
|
1285
|
-
|
1309
|
+
start_date = pd.Timestamp(start_date, tz=tz)
|
1310
|
+
end_date = pd.Timestamp(end_date, tz=tz)
|
1286
1311
|
|
1287
1312
|
# Starting Monday Sept. 29, 1952, no more saturday trading days
|
1288
1313
|
if tz is None:
|
@@ -1290,12 +1315,32 @@ class NYSEExchangeCalendar(MarketCalendar):
|
|
1290
1315
|
else:
|
1291
1316
|
saturday_end = self._saturday_end
|
1292
1317
|
|
1293
|
-
|
1294
|
-
if
|
1295
|
-
|
1296
|
-
trading_days = trading_days[~above_and_saturday]
|
1318
|
+
# Don't care about Saturdays. Call super.
|
1319
|
+
if start_date > saturday_end:
|
1320
|
+
return super().valid_days(start_date, end_date, tz=tz)
|
1297
1321
|
|
1298
|
-
|
1322
|
+
# Full Date Range is pre 1952. Augment the Super call
|
1323
|
+
if end_date <= saturday_end:
|
1324
|
+
return pd.date_range(
|
1325
|
+
start_date,
|
1326
|
+
end_date,
|
1327
|
+
freq=self.holidays_pre_1952(),
|
1328
|
+
normalize=True,
|
1329
|
+
tz=tz,
|
1330
|
+
)
|
1331
|
+
|
1332
|
+
# Range is split across 1952. Concatenate Two different Date_Range calls
|
1333
|
+
days_pre = pd.date_range(
|
1334
|
+
start_date,
|
1335
|
+
saturday_end,
|
1336
|
+
freq=self.holidays_pre_1952(),
|
1337
|
+
normalize=True,
|
1338
|
+
tz=tz,
|
1339
|
+
)
|
1340
|
+
days_post = pd.date_range(
|
1341
|
+
saturday_end, end_date, freq=self.holidays(), normalize=True, tz=tz
|
1342
|
+
)
|
1343
|
+
return days_pre.union(days_post)
|
1299
1344
|
|
1300
1345
|
def days_at_time(self, days, market_time, day_offset=0):
|
1301
1346
|
days = super().days_at_time(days, market_time, day_offset=day_offset)
|
@@ -1309,6 +1354,103 @@ class NYSEExchangeCalendar(MarketCalendar):
|
|
1309
1354
|
days = days.dt.tz_convert("UTC")
|
1310
1355
|
return days
|
1311
1356
|
|
1357
|
+
def date_range_htf(
|
1358
|
+
self,
|
1359
|
+
frequency: Union[str, pd.Timedelta, int, float],
|
1360
|
+
start: Union[str, pd.Timestamp, int, float, None] = None,
|
1361
|
+
end: Union[str, pd.Timestamp, int, float, None] = None,
|
1362
|
+
periods: Union[int, None] = None,
|
1363
|
+
closed: Union[Literal["left", "right"], None] = "right",
|
1364
|
+
*,
|
1365
|
+
day_anchor: u.Day_Anchor = "SUN",
|
1366
|
+
month_anchor: u.Month_Anchor = "JAN",
|
1367
|
+
) -> pd.DatetimeIndex:
|
1368
|
+
# __doc__ = MarketCalendar.date_range_htf.__doc__
|
1369
|
+
|
1370
|
+
start, end, periods = u._error_check_htf_range(start, end, periods)
|
1371
|
+
|
1372
|
+
args = {
|
1373
|
+
"frequency": frequency,
|
1374
|
+
"start": start,
|
1375
|
+
"end": end,
|
1376
|
+
"periods": periods,
|
1377
|
+
"closed": closed,
|
1378
|
+
"day_anchor": day_anchor,
|
1379
|
+
"month_anchor": month_anchor,
|
1380
|
+
}
|
1381
|
+
|
1382
|
+
saturday_end = self._saturday_end.tz_localize(None)
|
1383
|
+
|
1384
|
+
# All Dates post 1952 This is the most common use case so return it first
|
1385
|
+
if start is not None and start > saturday_end:
|
1386
|
+
return u.date_range_htf(self.holidays(), **args)
|
1387
|
+
|
1388
|
+
# ---- Start-Date to End-Date w/ pre-1952 ----
|
1389
|
+
if start is not None and end is not None:
|
1390
|
+
if end <= saturday_end:
|
1391
|
+
# All pre 1952 Dates
|
1392
|
+
return u.date_range_htf(self.holidays_pre_1952(), **args)
|
1393
|
+
else:
|
1394
|
+
# Split Range Across 1952
|
1395
|
+
pre = u.date_range_htf( # Only Generate to the last saturday
|
1396
|
+
self.holidays_pre_1952(), **(args | {"end": saturday_end})
|
1397
|
+
)
|
1398
|
+
post = u.date_range_htf( # start generating from the last date of 'pre'
|
1399
|
+
self.holidays(), **(args | {"start": pre[-1]})
|
1400
|
+
)
|
1401
|
+
return pd.DatetimeIndex(pre.union(post), dtype="datetime64[ns]")
|
1402
|
+
|
1403
|
+
# ---- Periods from Start-Date w/ pre-1952 ----
|
1404
|
+
elif start is not None and periods is not None:
|
1405
|
+
# Start prior to 1952 & Number of periods given
|
1406
|
+
rtn_dt = u.date_range_htf(self.holidays_pre_1952(), **args)
|
1407
|
+
if rtn_dt[-1] <= saturday_end:
|
1408
|
+
return rtn_dt # never passed 1952, good to return
|
1409
|
+
|
1410
|
+
# Date Range Split.
|
1411
|
+
pre = rtn_dt[rtn_dt <= saturday_end]
|
1412
|
+
post = u.date_range_htf(
|
1413
|
+
self.holidays(),
|
1414
|
+
**(args | {"start": pre[-1], "periods": periods - len(pre) + 1}),
|
1415
|
+
)
|
1416
|
+
return pd.DatetimeIndex(pre.union(post)[:periods], dtype="datetime64[ns]")
|
1417
|
+
|
1418
|
+
# ---- Periods from End-Date ----
|
1419
|
+
elif end is not None and periods is not None:
|
1420
|
+
if end <= saturday_end:
|
1421
|
+
# All Dates pre-1952, Good to return the normal call
|
1422
|
+
return u.date_range_htf(self.holidays_pre_1952(), **args)
|
1423
|
+
else:
|
1424
|
+
rtn_dt = u.date_range_htf(self.holidays(), **args)
|
1425
|
+
|
1426
|
+
if rtn_dt[0] > saturday_end:
|
1427
|
+
return rtn_dt # never passed 1952, good to return
|
1428
|
+
|
1429
|
+
# Date Range Split
|
1430
|
+
post = rtn_dt[rtn_dt > saturday_end]
|
1431
|
+
_, period_code = u._standardize_htf_freq(frequency)
|
1432
|
+
altered_args = {
|
1433
|
+
# This nonsense is to realign the schedules as best as possible. This
|
1434
|
+
# essentially creates the 'pre-1952' equivalent date to the last generated 'post-1952'
|
1435
|
+
# date. Start the Range from there, then pre[0:-1] trims off that extra date where we
|
1436
|
+
# started from
|
1437
|
+
"end": post[0].to_period(period_code).end_time.normalize(),
|
1438
|
+
"periods": periods - len(post) + 2,
|
1439
|
+
}
|
1440
|
+
pre = u.date_range_htf(
|
1441
|
+
self.holidays_pre_1952(),
|
1442
|
+
**(args | altered_args),
|
1443
|
+
)
|
1444
|
+
|
1445
|
+
return pd.DatetimeIndex(
|
1446
|
+
pre[:-1].union(post)[-periods:], dtype="datetime64[ns]"
|
1447
|
+
)
|
1448
|
+
else:
|
1449
|
+
_, _ = u._standardize_htf_freq(frequency)
|
1450
|
+
raise ValueError(
|
1451
|
+
"This should never be raised, the above call should error first"
|
1452
|
+
)
|
1453
|
+
|
1312
1454
|
def early_closes(self, schedule):
|
1313
1455
|
"""
|
1314
1456
|
Get a DataFrame of the dates that are an early close.
|
@@ -42,7 +42,7 @@ class SSEExchangeCalendar(MarketCalendar):
|
|
42
42
|
# Since all past holidays are adhoc, start_year should always be a year in the future.
|
43
43
|
# For example: Holiday arrangements for 2022 are now included,
|
44
44
|
# then our guesswork starts from the next year so start_year = 2023
|
45
|
-
start_year =
|
45
|
+
start_year = 2026
|
46
46
|
|
47
47
|
return AbstractHolidayCalendar(
|
48
48
|
rules=[
|
@@ -1,9 +1,11 @@
|
|
1
1
|
from datetime import time
|
2
2
|
|
3
|
-
from
|
3
|
+
from typing import Literal, Union
|
4
|
+
from pandas import Timestamp, Timedelta, DatetimeIndex
|
4
5
|
from pytz import timezone
|
5
6
|
|
6
7
|
from pandas_market_calendars.market_calendar import MarketCalendar
|
8
|
+
from pandas_market_calendars.calendar_utils import Day_Anchor, Month_Anchor
|
7
9
|
|
8
10
|
TASEClosedDay = [
|
9
11
|
# 2019
|
@@ -195,3 +197,24 @@ class TASEExchangeCalendar(MarketCalendar):
|
|
195
197
|
@property
|
196
198
|
def weekmask(self):
|
197
199
|
return "Sun Mon Tue Wed Thu"
|
200
|
+
|
201
|
+
def date_range_htf(
|
202
|
+
self,
|
203
|
+
frequency: Union[str, Timedelta, int, float],
|
204
|
+
start: Union[str, Timestamp, int, float, None] = None,
|
205
|
+
end: Union[str, Timestamp, int, float, None] = None,
|
206
|
+
periods: Union[int, None] = None,
|
207
|
+
closed: Union[Literal["left", "right"], None] = "right",
|
208
|
+
*,
|
209
|
+
day_anchor: Day_Anchor = "SAT", # Change the default day anchor
|
210
|
+
month_anchor: Month_Anchor = "JAN",
|
211
|
+
) -> DatetimeIndex:
|
212
|
+
return super().date_range_htf(
|
213
|
+
frequency,
|
214
|
+
start,
|
215
|
+
end,
|
216
|
+
periods,
|
217
|
+
closed,
|
218
|
+
day_anchor=day_anchor,
|
219
|
+
month_anchor=month_anchor,
|
220
|
+
)
|
@@ -565,6 +565,7 @@ all_holidays = [
|
|
565
565
|
Timestamp("2023-10-05"),
|
566
566
|
Timestamp("2023-10-06"),
|
567
567
|
Timestamp("2024-01-01"),
|
568
|
+
Timestamp("2024-02-09"),
|
568
569
|
Timestamp("2024-02-12"),
|
569
570
|
Timestamp("2024-02-13"),
|
570
571
|
Timestamp("2024-02-14"),
|
@@ -583,6 +584,26 @@ all_holidays = [
|
|
583
584
|
Timestamp("2024-10-03"),
|
584
585
|
Timestamp("2024-10-04"),
|
585
586
|
Timestamp("2024-10-07"),
|
587
|
+
# 2025 holidays
|
588
|
+
Timestamp("2025-01-01"), # New Year
|
589
|
+
Timestamp("2025-01-28"), # Spring Festival
|
590
|
+
Timestamp("2025-01-29"),
|
591
|
+
Timestamp("2025-01-30"),
|
592
|
+
Timestamp("2025-01-31"),
|
593
|
+
Timestamp("2025-02-03"),
|
594
|
+
Timestamp("2025-02-04"),
|
595
|
+
Timestamp("2025-04-04"), # Tomb-sweeping Day
|
596
|
+
Timestamp("2025-04-05"),
|
597
|
+
Timestamp("2025-05-01"), # Labor Day
|
598
|
+
Timestamp("2025-05-02"),
|
599
|
+
Timestamp("2025-05-05"),
|
600
|
+
Timestamp("2025-06-02"), # Dragon Boat Festival
|
601
|
+
Timestamp("2025-10-01"), # National Day & Mid-autumn Festival
|
602
|
+
Timestamp("2025-10-02"),
|
603
|
+
Timestamp("2025-10-03"),
|
604
|
+
Timestamp("2025-10-06"),
|
605
|
+
Timestamp("2025-10-07"),
|
606
|
+
Timestamp("2025-10-08"),
|
586
607
|
]
|
587
608
|
|
588
609
|
# The following holidays are based on Solar terms or Chinese lunisolar calendar,
|
@@ -11,6 +11,7 @@ from the Tokyo exchange inauguration through 2099,
|
|
11
11
|
using pyephem (http://rhodesmill.org/pyephem/quick.html#equinoxes-solstices).
|
12
12
|
For a double check, see: https://aa.usno.navy.mil/data/docs/EarthSeasons.php
|
13
13
|
"""
|
14
|
+
|
14
15
|
import pandas as pd
|
15
16
|
from pandas.tseries.holiday import sunday_to_monday
|
16
17
|
|