pandas-market-calendars 4.4.0__py3-none-any.whl → 4.6.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|