@@ -47,19 +47,19 @@ def is_market_open(asset_type: str, dt: datetime.datetime) -> bool:
47
47
if (
48
48
date in EQUITY_EARLY_HOLIDAYS
49
49
and time >= EQUITY_OPEN
50
- and time <= EQUITY_EARLY_CLOSE
50
+ and time < EQUITY_EARLY_CLOSE
51
51
):
52
52
return True
53
53
return False
54
- if day < 5 and time >= EQUITY_OPEN and time <= EQUITY_CLOSE :
54
+ if day < 5 and time >= EQUITY_OPEN and time < EQUITY_CLOSE :
55
55
return True
56
56
return False
57
57
58
58
if asset_type in ["fx" , "metal" ]:
59
59
if date in FX_METAL_HOLIDAYS :
60
60
return False
61
61
# On Friday the market is closed after 5pm
62
- if day == 4 and time > FX_METAL_OPEN_CLOSE_TIME :
62
+ if day == 4 and time >= FX_METAL_OPEN_CLOSE_TIME :
63
63
return False
64
64
# On Saturday the market is closed all the time
65
65
if day == 5 :
@@ -79,9 +79,6 @@ def get_next_market_open(asset_type: str, dt: datetime.datetime) -> str:
79
79
dt = dt .astimezone (NY_TZ )
80
80
time = dt .time ()
81
81
82
- if is_market_open (asset_type , dt ):
83
- return dt .astimezone (UTC_TZ ).strftime ("%Y-%m-%dT%H:%M:%S" ) + "Z"
84
-
85
82
if asset_type == "equity" :
86
83
if time < EQUITY_OPEN :
87
84
next_market_open = dt .replace (
@@ -113,30 +110,53 @@ def get_next_market_open(asset_type: str, dt: datetime.datetime) -> str:
113
110
second = 0 ,
114
111
microsecond = 0 ,
115
112
)
116
- next_market_open += datetime .timedelta (days = 1 )
113
+ while is_market_open (asset_type , next_market_open ):
114
+ next_market_open += datetime .timedelta (days = 1 )
115
+
117
116
else :
118
- next_market_open = dt .replace (hour = 0 , minute = 0 , second = 0 , microsecond = 0 )
119
- next_market_open += datetime .timedelta (days = 1 )
117
+ return None
120
118
121
119
while not is_market_open (asset_type , next_market_open ):
122
120
next_market_open += datetime .timedelta (days = 1 )
123
121
124
122
return next_market_open .astimezone (UTC_TZ ).strftime ("%Y-%m-%dT%H:%M:%S" ) + "Z"
125
123
124
+
126
125
def get_next_market_close (asset_type : str , dt : datetime .datetime ) -> str :
127
126
# make sure time is in NY timezone
128
127
dt = dt .astimezone (NY_TZ )
129
- if not is_market_open (asset_type , dt ):
130
- return dt .astimezone (UTC_TZ ).strftime ("%Y-%m-%dT%H:%M:%S" ) + "Z"
128
+ time = dt .time ()
131
129
132
130
if asset_type == "equity" :
133
131
if dt .date () in EQUITY_EARLY_HOLIDAYS :
134
-
135
- next_market_close = dt .replace (
136
- hour = EQUITY_EARLY_CLOSE .hour ,
137
- minute = EQUITY_EARLY_CLOSE .minute ,
138
- second = 0 ,
139
- microsecond = 0 ,
132
+ if time < EQUITY_EARLY_CLOSE :
133
+ next_market_close = dt .replace (
134
+ hour = EQUITY_EARLY_CLOSE .hour ,
135
+ minute = EQUITY_EARLY_CLOSE .minute ,
136
+ second = 0 ,
137
+ microsecond = 0 ,
138
+ )
139
+ else :
140
+ next_market_close = dt .replace (
141
+ hour = EQUITY_CLOSE .hour ,
142
+ minute = EQUITY_CLOSE .minute ,
143
+ second = 0 ,
144
+ microsecond = 0 ,
145
+ )
146
+ next_market_close += datetime .timedelta (days = 1 )
147
+ elif dt .date () in EQUITY_HOLIDAYS :
148
+ next_market_open = get_next_market_open (
149
+ asset_type , dt + datetime .timedelta (days = 1 )
150
+ )
151
+ next_market_close = (
152
+ datetime .datetime .fromisoformat (next_market_open .replace ("Z" , "+00:00" ))
153
+ .astimezone (NY_TZ )
154
+ .replace (
155
+ hour = EQUITY_CLOSE .hour ,
156
+ minute = EQUITY_CLOSE .minute ,
157
+ second = 0 ,
158
+ microsecond = 0 ,
159
+ )
140
160
)
141
161
else :
142
162
next_market_close = dt .replace (
@@ -145,14 +165,28 @@ def get_next_market_close(asset_type: str, dt: datetime.datetime) -> str:
145
165
second = 0 ,
146
166
microsecond = 0 ,
147
167
)
168
+ if time >= EQUITY_CLOSE :
169
+ next_market_close += datetime .timedelta (days = 1 )
170
+
171
+ # while next_market_close.date() is in EQUITY_HOLIDAYS or weekend, add 1 day
172
+ while (
173
+ next_market_close .date () in EQUITY_HOLIDAYS
174
+ or next_market_close .weekday () >= 5
175
+ ):
176
+ next_market_close += datetime .timedelta (days = 1 )
177
+
148
178
elif asset_type in ["fx" , "metal" ]:
149
179
next_market_close = dt .replace (
150
180
hour = FX_METAL_OPEN_CLOSE_TIME .hour ,
151
181
minute = FX_METAL_OPEN_CLOSE_TIME .minute ,
152
182
second = 0 ,
153
183
microsecond = 0 ,
154
184
)
155
- else : # crypto markets never close
185
+ while not is_market_open (asset_type , next_market_close ):
186
+ next_market_close += datetime .timedelta (days = 1 )
187
+ while is_market_open (asset_type , next_market_close ):
188
+ next_market_close += datetime .timedelta (days = 1 )
189
+ else : # crypto markets never close
156
190
return None
157
191
158
192
return next_market_close .astimezone (UTC_TZ ).strftime ("%Y-%m-%dT%H:%M:%S" ) + "Z"
0 commit comments