gerrymanoim / exchange_calendars Goto Github PK
View Code? Open in Web Editor NEWThis project forked from quantopian/trading_calendars
Calendars for various securities exchanges.
License: Apache License 2.0
This project forked from quantopian/trading_calendars
Calendars for various securities exchanges.
License: Apache License 2.0
import exchange_calendars as xcals
xtai = xcals.get_calendar("XTAI")
xtai.schedule.loc["2022-01-01":"2022-02-01"]
Out[4]:
market_open ... market_close
2022-01-03 00:00:00+00:00 2022-01-03 01:00:00 ... 2022-01-03 05:30:00
2022-01-04 00:00:00+00:00 2022-01-04 01:00:00 ... 2022-01-04 05:30:00
2022-01-05 00:00:00+00:00 2022-01-05 01:00:00 ... 2022-01-05 05:30:00
2022-01-06 00:00:00+00:00 2022-01-06 01:00:00 ... 2022-01-06 05:30:00
2022-01-07 00:00:00+00:00 2022-01-07 01:00:00 ... 2022-01-07 05:30:00
2022-01-10 00:00:00+00:00 2022-01-10 01:00:00 ... 2022-01-10 05:30:00
2022-01-11 00:00:00+00:00 2022-01-11 01:00:00 ... 2022-01-11 05:30:00
2022-01-12 00:00:00+00:00 2022-01-12 01:00:00 ... 2022-01-12 05:30:00
2022-01-13 00:00:00+00:00 2022-01-13 01:00:00 ... 2022-01-13 05:30:00
2022-01-14 00:00:00+00:00 2022-01-14 01:00:00 ... 2022-01-14 05:30:00
2022-01-17 00:00:00+00:00 2022-01-17 01:00:00 ... 2022-01-17 05:30:00
2022-01-18 00:00:00+00:00 2022-01-18 01:00:00 ... 2022-01-18 05:30:00
2022-01-19 00:00:00+00:00 2022-01-19 01:00:00 ... 2022-01-19 05:30:00
2022-01-20 00:00:00+00:00 2022-01-20 01:00:00 ... 2022-01-20 05:30:00
2022-01-21 00:00:00+00:00 2022-01-21 01:00:00 ... 2022-01-21 05:30:00
2022-01-24 00:00:00+00:00 2022-01-24 01:00:00 ... 2022-01-24 05:30:00
2022-01-25 00:00:00+00:00 2022-01-25 01:00:00 ... 2022-01-25 05:30:00
2022-01-26 00:00:00+00:00 2022-01-26 01:00:00 ... 2022-01-26 05:30:00
2022-01-27 00:00:00+00:00 2022-01-27 01:00:00 ... 2022-01-27 05:30:00
while https://www.tradinghours.com/markets/twse/holidays indicates 2022-01-27 is a holiday for TWSE.
Should also port over https://github.com/quantopian/trading_calendars/pull/176/files someday.
Within us_futures_calendar.py, the class QuantopianUSFuturesCalendar has a property of default_start returning a Teimstamp dated 2000-01-01, with the comment:
# XXX: Override the default start date. This is a stopgap for memory
# issues caused by upgrading to pandas 18. This calendar is the most
# severely affected since it has the most total minutes of any of the
# zipline calendars.
This is seemingly referencing Pandas 0.18, which was released in 2016, and of course, we're many releases since there.
As exchange-calendars is used by Zipline (Reloaded), this prevents users from backtesting on futures prior to this date, requiring manual patching by the user to extend prior to this.
I'm only working with daily data and there's no noticeble particular issue with that periodicity as far as RAM is concerned, but I'm unable to say whether this is still a problem for other periodicities (such as minutes).
Given we're now 5 yeras later, could this default be extended to, say, 1970-01-01 (or earlier).
The other exchange calendars (such as NYSE) seem to default to the earliest holiday definition. For example, NYSE goes back to 1848 so is probably a non-issue regarding RAM for futures....
I'm taking the liberty to assume that the process started with PR #71 (to add a 'side' option and overhaul the test suite) will culminate in cutting 3.4. The process...
OpenDetectionTestCase
(minute_index_to_session_labels
now comprehensively tested under new suite.)NoDSTExchangeCalendarTestBase
(this case is now handled by new test base internally.)ExchangeCalendarTestBase
and renaming ExchangeCalendarTestBaseNew
as ExchangeCalendarTestBase
minute_index_to_session_labels
requires any revisions.Hi,
Dates in the future after 2022-5-18 are not considered valid days.
I also just noticed that this is a duplicate of issue #14
import trading_calendars as tc
import exchange_calendars as ec
import pandas as pd
import datetime
tcal = tc.get_calendar("XLON")
ecal = ec.get_calendar("XLON")
print(
tcal.sessions_in_range(
pd.Timestamp(datetime.date(2022, 5, 1), tz="UTC"),
pd.Timestamp(datetime.date(2022, 6, 30), tz="UTC"),
),
ecal.sessions_in_range(
pd.Timestamp(datetime.date(2022, 5, 1), tz="UTC"),
pd.Timestamp(datetime.date(2022, 6, 30), tz="UTC"),
),
)
I have a small set of metadata copied from project to project, currently looking a bit like this:
'Hard Red Winter Wheat': {
'is_rate': False,
'slice': 2,
'category': 'Grain & Oilseed',
'yahoo_prefix': 'KE',
'yahoo_suffix': '.CBT',
'product_id': 348,
},
For all instruments at CME.
I then have some code accepting one of these product names and scrapes the current calendar from the CME site, providing a data frame like:
eurodol.get_cme_ts(eurodol.CME_PRODUCTS['Hard Red Winter Wheat'])
Last Trade
2021-03-12 KEH21.CBT
2021-05-14 KEK21.CBT
2021-07-14 KEN21.CBT
2021-09-14 KEU21.CBT
2021-12-14 KEZ21.CBT
2022-03-14 KEH22.CBT
2022-05-13 KEK22.CBT
2022-07-14 KEN22.CBT
2022-09-14 KEU22.CBT
2022-12-14 KEZ22.CBT
2023-03-14 KEH23.CBT
2023-05-12 KEK23.CBT
2023-07-14 KEN23.CBT
Name: Symbol, dtype: object
Doing this generally for any instrument on any exchange requires a big database that nobody wants to maintain, but maybe if it lived in a project like exchange_calendars, there is a hope it could eventually build up over time.
What do you think? I notice there is currently no scraping in this project, but it seems to fit with the use case -- instrument calendars are still more or less calendars
Requesting a session label for a minute prior to first calendar session, with direction as 'previous', returns the last calendar session...
>>> import trading_calendars as tc
>>> import pandas as pd
>>> c = tc.get_calendar('XNYS')
>>> ts = c.first_session - pd.Timedelta(days=1)
>>> session = c.minute_to_session_label(ts, direction='previous')
>>> session == c.last_session
True
Would have expected a ValueError similar in manner to that raised by:
>>> c.previous_session_label(c.first_session)
ValueError: There is no previous session as this is the beginning of the exchange calendar.
version: 2.1.1
The orthodox_easter
method was used for some time to get Orthodox Easter holidays for ASEX. It has since been pulled out of the ASEX-specific code as it's now also used for XBSE.
The method has two arguments, start_date
and end_date
, with default values of 1980
and 2022
, respectively.
This issue is to ask if it actually makes sense to configure an end date which coincides with the current or next year (as of the time the code is written/updated).
I think it actually makes sense to have this open-ended, or possibly restricted by some global end date that automatically slides forward as time progresses. This would be to reflect that an exchange that observes holidays relative to Orthodox Easter is probably more likely to continue that in the future rather than changing observances (status quo assumption).
Ideally, any restriction would also be done per-exchange as exchanges may start or stop observing the affected holidays independently of each other.
Setting the default end date to the current year or the one after, at the time of a code update, also carries a risk for anyone using the exchange_calendars
package, but missing a few future updates. The problem then becomes that the package effectively will no longer spit out the correct holidays in future years as it will stop respecting the Orthodox Easter holidays when the end date has passed, despite the rules still being valid. So one would rely on updating the package in time, hoping that the end date has now been adjusted there. To minimize the risk, I think it would be best to put any end date far into the future.
So, in essence, should we remove the current configured default end date on the method orthodox_easter
, and if so, what's the correct end date (ideally far into the future) to configure?
Hi I received the following error:
volume1/homes/admin/Drive/stock/order/stock_buyer.py:58: FutureWarning: Indexing a timezone-aware DatetimeIndex with a timezone-naive datetime is deprecated and will raise KeyError in a future version. Use a timezone-aware object instead. if ecals.get_calendar("XKLS").is_session(pd.Timestamp(date.today().strftime('%Y-%m-%d'))):
date.today() refers to the local date. Local date is 'Asia/Kuala_lumpur'. Should I do the following instead?
if ecals.get_calendar("XKLS").is_session(pd.Timestamp(date.today().strftime('%Y-%m-%d'), tz='Asia/Kuala_lumpur')):
but if I do that the result is False when it should be True.
I have written a simple program as shown in the screenshot. However, while executing import exchange_calendars as xcals
statement, i'm getting the following error ,
File "C:\Users\Seena\anaconda3\lib\site-packages\exchange_calendars\calendar_helpers.py", line 6, in <module>
NP_NAT = np.array([pd.NaT], dtype=np.int64)[0]
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NaTType'
the detailed error is shown in screenshot, could someone help me fix this?
My Environment:
Anaconda Navigator 2.1.1
Sypder IDE 5.1.5
Python 3.8.5 64-bit | Qt 5.9.7 | PyQt5 5.9.2 | Windows 10
import exchange_calendars as xcals
import pandas as pd
xses = xcals.get_calendar("XSES")
xses.is_session(pd.Timestamp("2022-01-01"))
DateOutOfBounds Traceback (most recent call last)
in
----> 1 xses.is_session(pd.Timestamp("2022-01-01"))
~/anaconda3/lib/python3.7/site-packages/exchange_calendars/exchange_calendar.py in is_session(self, dt, _parse)
1141 """
1142 if _parse:
-> 1143 dt = parse_date(dt, "dt", self)
1144 idx = self._get_date_idx(dt, parse=False)
1145 return bool(self.sessions_nanos[idx] == dt.value) # convert from np.bool
~/anaconda3/lib/python3.7/site-packages/exchange_calendars/calendar_helpers.py in parse_date(date, param_name, calendar, raise_oob)
317 raise ValueError("calendar
must be passed if raise_oob
is True.")
318 if calendar._date_oob(ts):
--> 319 raise errors.DateOutOfBounds(calendar, ts, param_name)
320
321 return ts
DateOutOfBounds: Parameter dt
receieved as '2022-01-01 00:00:00+00:00' although cannot be later than the last session of calendar 'XSES' ('2021-12-31 00:00:00+00:00').
Originally posted by @gerrymanoim in #61 (comment)
I'd add
My preference is probably some markdown backed sphinx system on github pages.
@maread99 edit for specific documentation tasks:
ExchangeCalendar
'calendar-defintion' methods/properties.ExchangeCalendar
'functional' methods/properties (e.g. mintute_to_session_label
etc). (completed #71)@gerrymanoim, given the break with zipline, is there any reason why we would want to keep the ExchangeCalendar._minute_to_session_label_cache, or can we lose it?
19 Aug 2020
Hong Kong Exchanges and Clearing Limited (HKEX) announced that trading in the securities and derivatives markets will resume at 1:30pm, following the cancellation of Typhoon Signal No. 8. Stock Connect trading will resume from 1:30pm according to the Rules of the Exchange.
https://www.hkex.com.hk/News/Market-Communications/2020/2008192news?sc_lang=en
Because it blanket tests the edges of all sessions, the test_prev_next_minute
is one of the slowest tests of the suite.
The test could be sped up considerably by focusing on the edges of sessions of Answers.session_blocks
(as a number of other tests already do).
If anyone wants to get familiar with the test suite, this would be a good PR to take up (maybe start by having a look at the test inputs available from the Answers
class and then at how the tests for other similar methods are implemented).
I've opened this to consolidate any breaking changes that would need to be delayed until / incorporated in any release 4.0.
session_label
parameter of ExchangeCalendar
methods to be renamed session
(which is given context from Session
type and checks imposed by subsequent parsing). Methods requiring change include:
previous_session_label
(changed when renamed, #85)next_session_label
(changed when renamed, #85)session_open
(done #186)session_close
(done #186)session_break_start
(done #186)session_break_end
(done #186)open_and_close_for_session
(changed when renamed, #85)break_start_and_end_for_session
(changed when renamed, #85)minutes_for_session
(changed when renamed, #85)sessions_window
(done #184)start_session_label
/ end_session_label
parameters to be renamed start
/ end
sessions_in_range
(done #186)minutes_for_sessions_in_range
(changed when renamed, #85)session_opens_in_range
(changed when renamed, #85)session_closes_in_range
(changed when renamed, #85)session_distance
(changed when renamed, #85)start_session
/ end_session
parameters to be renamed start
/ end
minutes_count_for_sessions_in_range
(changed when renamed, #85)start_minute
/ end_minute
parameters to be renamed start
/ end
minutes_in_range
(done #194)dt
to be renamed date
:is_session
(done #186)dt
parameter of ExchangeCalendar
methods to be renamed minute
(given context from 'Minute' type and checks imposed by subsequent parsing). Methods requring change include:
minute_to_session_label
(changed when renamed, #85)is_open_on_minute
(done #186)previous_open
(done #186)previous_close
(done #186)next_open
(done #186)next_close
(done #186)previous_minute
(done #186)next_minute
(done #186)start_dt
to be renamed minute
:minutes_window
(done #184)index
parameter of minute_index_to_session_labels
to be renamed minutes
(changed when renamed, #85)ExchangeCalendar.schedule
columns: (done #186)
market_open
to open
market_close
to close
ExchangeCalendar
methods deprecated ahead of release 3.4 - all were renamed (#85) save for the four execution_*
methods: (done #186)
execution_minutes_for_session
execution_minutes_for_sessions_in_range
execution_time_from_open
execution_time_from_close
previous_session_label
next_session_label
date_to_session_label
minute_to_session_label
open_and_close_for_session
break_start_and_end_for_session
minutes_for_session
session_opens_in_range
session_closes_in_range
minutes_for_sessions_in_range
minutes_count_for_sessions_in_range
session_distance
minute_index_to_session_labels
all_sessions
all_minutes
all_minutes_nanos
first_trading_minute
last_trading_minute
first_trading_session
last_trading_session
has_breaks
market_opens_nanos
market_closes_nanos
market_break_starts_nanos
market_break_ends_nanos
sessions_opens
and sessions_closes
now that, with schedule times changing to UTC timestamps, cal.sessions_opens(start, end)
will return the same as cal.opens[start:end]
(there should be only one obvious way to do something...). (done #186)side
default for all calendars to "left" (from "right" for 24 hour calendars and from "both" for others). See #181. (done #191)ExchangeCalendar
methods sessions_window
and minutes_window
so that count
parameter matches the length of the return (the length of which is currently count + 1). i.e. just add count -= 1
as methods' first line and raise ValueError
if count
received as 0. (done #184)is_open_on_minute
to distinguish it from is_trading_minute
. Proposed that the ignore_breaks
option be removed and the method act as if ignore_breaks
were True, i.e. is_open_on_minute
would act as is_trading_minute
albeit treating any break minutes as open. Method documentation should make clear that market is considered open on break minutesExchangeCalendar
properties bound_start
and bound_end
to class attributes (they are class-specific, not instance-specific) and default_start
and default_end
to class methods valid_sides
and default_side
)errors.RequestedSessionOutOfBounds
when request session/minute falls beyond calendar bound: (done #184)
next_session
(remove from minute_to_future_session
method the current_session == last_session check and raise.)previous_session
(remove from minute_to_past_session
method the current_session == first_session check and raise.)next_minute
previous_minute
ExchangeCalendar.trading_index
, or calendar_helpers._TradingIndex
, to: (done #180)
start
and end
parameters to be passed as times (as opposed to only dates).force
option to define both force_close
and force_break_close
.Desired enhancements that are non-breaking:
While working on #4, I discovered what is likely a bug in the TradingCalendar
base class.
When a calendar, e.g. for XETR
or XWBO
, is created with end date, say, 2020-12-30
, then that day itself always seems to be treated as a regular business day if the exchange is open at all that day.
However, XETR
and XWBO
have rules in that make the last trading day of a year a special close day. This seems to be ignored in this case. If the end date is chosen to be after the special close day in question, then the special close is again reflected accurately.
The bug seems to manifest itself only in the edge case where the end date is a special open/close day.
@gerrymanoim Can you have look? You're probably quicker at finding the root cause. Let me know if I can help.
Exchange_Calendars package was working good until 31/12/2021 and after that receiving the DateOutOfBounds
error during xbom.is_session
method. I have updated the package to 3.5 and did check the code yesterday to see XBOM.py file was missing the 2022 calendar entries and at the same time there was a PR pending with changes to be merged with main branch. Today, I see that the changes are merged with main branch. However, I still get the error.
Need some text about updating tests, putting the source of the change in the PR, etc.
Hi Gerry,
Community continues Zipline development in new fork, I noticed you have started to maintain Q trading_calendars under new name but depreciated some items that are currently used by Zipline. Would you be happy to work together to include also features required by zipline trader or we would need to maintain own trading calendar?
If you are interested please join us at Zipline Trader:
For those calendars with breaks, break times should probably be declared as columns of the answers csv files in the same way as opens and closes. Associated tests could then be revised to get their expected values directly from answers.
@gerrymanoim, would you have any objections to PRs including annotations to public methods/properties for the purpose of documenting expected types / return type?
Thank you for maintaining this fork. It's a great library!
@lazyval
in favour of @functools.cached_property
Answers
and ExchangeCalendar
classes consolidate properties returning functions decorated @functools.lru_cache
with simple properties decorated with @functools.cached_property
direction
parameter of ExchangeCalendar
, minute_to_session_label
and date_to_session_label
methods as Literal["next", "previous", "none"]side
parameter of ExchangeCalendar
, test_exchange_calendar.py
and calendar_helper.py
methods as Literal["left", "right", "both", "neither"]column
parameter of Answers._get_sessions_with_times_different_to_a_contiguous_session
as Literal["opens", "closes", "break_starts", "break_ends"]Sorry, if this might be a stupid question, since I don't know how the calendars are implemented. However, when trying to check the trading days for the next year 2022, I ran into an error, with the defined end being later than the last available calendar date.
Please see the following code example, which triggers the error:
import exchange_calendars as ecal
cal_FRA = ecal.get_calendar("XFRA")
cal_XETR = ecal.get_calendar("XETR")
start, end = "2022-01-01", "2022-12-31"
df_trading_days_xetra = pd.DataFrame((cal_XETR.trading_index(start, end, "24h", intervals=False)), columns=['Dates'])
print(df_trading_days_xetra)
This results in the following error
Traceback (most recent call last): File "R:\Zentrale\ZB-S\Daten\S5\S52\AD\JL\python\python_eikon\join_test.py", line 63, in <module> df_trading_days_xetra = pd.DataFrame((cal_XETR.trading_index(start, end, "24h", intervals=False)), columns=['Dates']) File "C:\Workspace\Python_Runtime\Envs\python_eikon\lib\site-packages\exchange_calendars\exchange_calendar.py", line 2347, in trading_index start, end = self._parse_start_end_dates(start, end, parse) File "C:\Workspace\Python_Runtime\Envs\python_eikon\lib\site-packages\exchange_calendars\exchange_calendar.py", line 1980, in _parse_start_end_dates return parse_date(start, "start", self), parse_date(end, "end", self) File "C:\Workspace\Python_Runtime\Envs\python_eikon\lib\site-packages\exchange_calendars\calendar_helpers.py", line 323, in parse_date raise errors.DateOutOfBounds(calendar, ts, param_name) exchange_calendars.errors.DateOutOfBounds: Parameter
end receieved as '2022-12-31 00:00:00+00:00' although cannot be later than the last session of calendar 'XETR' ('2022-12-29 00:00:00+00:00').
When changing the start date to days before 2022-12-28, the dataframe gets created without any issue.
Another issue following this latest pandas release is that the ExchangeCalendar constructor is now raising a FutureWarning.
The cause is within the creation of the schedule DataFrame
, due to conversion of DatetimeIndex values with dtype 'datetime64[ns, UTC]'
(self._opens etc.) to 'datetime64[ns]'
.
self.schedule = DataFrame(
index=_all_days,
data=OrderedDict(
[
("market_open", self._opens),
("break_start", self._break_starts),
("break_end", self._break_ends),
("market_close", self._closes),
]
),
dtype="datetime64[ns]",
)
One option would be to change the target dtype to "datetime64[ns, UTC]" thereby defining the schedule columns in terms of UTC. This additional context would be meaningful although I suspect it would open a can of worms with respect to changes it would necessitate within exchange_calendars
and its clients. For now I'll add a fix to PR #41 that retains the existing behaviour.
Originally posted by @maread99 in #40 (comment)
@gerrymanoim, would you entertain a PR that introduces a side
parameter to get_calendar
to determine the minutes when a calendar should be considered open? Options would be as follows with default as "both" such that existing behaviour would remain unchanged:
I feel this would give the user useful flexibility.
I've employed a hack to implement the above on something I'm working on. The implementation's fairly simple (it would also be possible to add a side
option to methods such as minutes_in_range
and minute_to_session_label
to override the global side
value for any particular call).
I'd happily offer a PR if you think a side
option would be a worthy enhancement?
I notice that you previously got together a PR to expose the get_calendar
start
and end
parameters (as referenced from #24). I could introduce this at the same time.
With regards to the cache, occurs to me to either:
Thoughts?
I think the XCBF and CFE calendars (they appear to be the same thing with CFE aliased to XCBF) have incorrect dates corresponding to some but not all Good Fridays (4/10/2009, 4/2/2010, 4/3/2015, 3/25/2016, 4/10/2020, 4/2/2021). I checked since 2008 when I have data and six times it appeared that Good Friday was listed as a valid CFE date despite the NYSE being closed. (I spot checked historical data from CBOE, and for example, 4/2/2021 was not a date that a historical futures contract had listed.)
Hi @elbakramer, I'm migrating the test modules to a new base and have come across XKRXCalendarTestCase.test_calculated_against_old_csv
which is obviously specific to XKRX.
Is there any reason for continuing to test a slice of the schedule against the old csv even though the full schedule now equates with the new xkrx.csv
? Or can this test and xkrx_old.csv
now be removed?
Thanks.
ExchangeCalendar
class methods valid_sides
and default_side
to be changed to class properties (like this).ExchangeCalendar
methods deprecated in 4.0 (will be about time to remove them).
sessions_opens
sessions_closes
setup.py
if it's no longer needed, otherwise roll this item forwards to review when bumping min support to 3.10.pytz
in favor of zoneinfo
standard library zoneinfo
as its default timezone package. If it looks like pandas 2.0 could be released any time soon we might want to address this now. If it looks still to be a way off then we could roll this item forwards (to dedicated issue), although in any event pandas already supports zoneinfo
and we'd be better off depending on a stdlib library than a third-party one.On bumping min version to 3.9, roll anything not addressed to a new issue 'TODO when min support moves to python 3.10'.
Trying to get trading sessions for long term options. Always returns 255 even though it is definitely much more than that. Am I not using the library correctly?
xnys = ecals.get_calendar("XCBF")
trading_days = xnys.sessions_in_range(pd.Timestamp("2021-03-11", tz=pytz.UTC), pd.Timestamp("2023-01-20", tz=pytz.UTC))
print(len(trading_days))
255
thanks!
Over recent PRs (culminating with #71) the ExchangeCalendar
's more client-facing (as opposed to calendar-definition) properties/methods have been revised to include parsing, annotation and standardised documentation. Concepts of 'session(s)' and 'minute(s)' are now expressed consistently throughout the class:
Session
, Minute
and Date
type annotations (and anticipated TradingMinute
type).session
and minute
.I'd propose going the final step and renaming the following methods to support this consistency and make the names less verbose (the lexicographical grouping of like methods would also aid users searching for methods from auto-complete menus).
Methods to be renamed to drop '_label' part:
previous_session_label
to previous_session
next_session_label
to next_session
date_to_session_label
to date_to_session
minute_to_session_label
to minute_to_session
Methods that interrogate a session (all to be consistent with the likes of session_open
:
open_and_close_for_session
to session_open_close
.break_start_and_end_for_session
to session_break_start_end
.minutes_for_session
to session_minutes
.Methods that interrogate a range of sessions:
session_opens_in_range
to sessions_opens
.session_closes_in_range
to sessions_closes
.minutes_for_sessions_in_range
to or sessions_minutes
.minutes_count_for_sessions_in_range
to sessions_minutes_count
.session_distance
to sessions_distance
.Methods that interrogate a range of minutes:
minute_index_to_session_labels
to minutes_to_sessions
.Calendar properties:
all_sessions
to sessions
all_minutes
to minutes
all_minutes_nanos
to minutes_nanos
first_trading_minute
to first_minute
.last_trading_minute
to last_minute
.first_trading_session
to already existing property first_session
.last_trading_session
to already existing property last_session
.has_breaks
to sessions_has_break
(and add genuine property has_break
that refers to all calendar sessions).Calendar attributes:
market_opens_nanos
to opens_nanos
.market_closes_nanos
to closes_nanos
.market_break_starts_nanos
to break_starts_nanos
.market_break_ends_nanos
to break_ends_nanos
.Renaming Process
Intention would be to include newly named methods (with any newly named parameter names - #61) and deprecate the old-named methods in an upcoming release (3.4?). The deprecated methods would be retained (together with existing parameter names) although revised to:
#71 adds a deprecate
decorator to exchange_calendar.py. The decorator's currently only used for deprecating the execution_mintues_*
methods although it can accommodate deprecations for renaming - under which it raises a FutureWarning that advises the user:
@gerrymanoim, what are you thoughts? Would you be happy for me to get a PR together prior to 3.4 to put the following name changes in motion?
exchange_calendars
These will all be breaking changes.
Hi there,
I'm cleaning up a 20yr + data set before attempting my zipline backtesting and I'm calling the following example to get valid trade days:
start = '2000-01-13'
end = '2022-01-13'
nys = xcals.get_calendar("XNYS") # New York Stock Exchange
caldatelist = nys.sessions_in_range(start, end) #valid trading days list
caldatelist
return:
DateOutOfBounds: Parameter start
receieved as '2000-01-13 00:00:00+00:00' although cannot be earlier than the first session of calendar 'XNYS' ('2002-01-15 00:00:00+00:00').
It seems that passing the start value isn't overriding the 20yr default as suggested here in a similar issue:
#112
Thank you.
Hello,
The XIDX calendar does not seem to follow the information available at
https://www.idx.co.id/en-us/investhub/trading-hours/
Closing time is wrong and we're also missing the lunch break.
I tested in my pc and colaboratory.
I followed below process.
!pip install exchange_calendars
import exchange_calendars as ecals
import pandas as pd
xkrx = ecals.get_calendar("XKRX")
xkrx.last_session_close
it returns "Timestamp('2023-03-03 06:30:00')"
it also happens in other markets.
I suspect we're just not setting the env variable correctly
Dependabot cannot be made to look at a single file (only a single directory). For now, I'd like to keep the older lock file around, but aggressively update the newer one.
Some options:
requirements_locked
and requirements.in
to be in the same place?).Leaning to option 1.
Hi @elbakramer, I'm migrating the calendar test modules to a new test base and XKRX is failing a new test that checks late_opens
against late opens as evaluated from the answers file.
The calendar appears to have regular late opens although the late_opens
property returns an empty DatetimeIndex
?
The following example shows the late open on 2021-01-04:
> import exchange_calendars as xcals
> cal = xcals.get_calendar("XKRX", start="2020-12-29", end="2021-01-06")
> cal.schedule
market_open | break_start | break_end | market_close | |
---|---|---|---|---|
2020-12-29 00:00:00+00:00 | 2020-12-29 00:00:00 | NaT | NaT | 2020-12-29 06:30:00 |
2020-12-30 00:00:00+00:00 | 2020-12-30 00:00:00 | NaT | NaT | 2020-12-30 06:30:00 |
2021-01-04 00:00:00+00:00 | 2021-01-04 01:00:00 | NaT | NaT | 2021-01-04 06:30:00 |
2021-01-05 00:00:00+00:00 | 2021-01-05 00:00:00 | NaT | NaT | 2021-01-05 06:30:00 |
2021-01-06 00:00:00+00:00 | 2021-01-06 00:00:00 | NaT | NaT | 2021-01-06 06:30:00 |
yet:
> cal.late_opens
DatetimeIndex([], dtype='datetime64[ns, UTC]', freq=None)
For the default calendar, all the following sessions appear to have late opens...
DatetimeIndex(['1986-01-04 00:00:00+00:00', '1987-01-05 00:00:00+00:00',
'1988-01-04 00:00:00+00:00', '1989-01-04 00:00:00+00:00',
'1990-01-04 00:00:00+00:00', '1991-01-03 00:00:00+00:00',
'1992-01-03 00:00:00+00:00', '1993-01-04 00:00:00+00:00',
'1993-08-20 00:00:00+00:00', '1993-11-16 00:00:00+00:00',
'1994-11-23 00:00:00+00:00', '1995-01-03 00:00:00+00:00',
'1995-11-22 00:00:00+00:00', '1996-01-03 00:00:00+00:00',
'1996-11-13 00:00:00+00:00', '1997-01-03 00:00:00+00:00',
'1997-11-19 00:00:00+00:00', '1998-01-03 00:00:00+00:00',
'1998-11-18 00:00:00+00:00', '1999-01-04 00:00:00+00:00',
'1999-11-17 00:00:00+00:00', '2000-11-15 00:00:00+00:00',
'2001-01-02 00:00:00+00:00', '2001-11-07 00:00:00+00:00',
'2002-01-02 00:00:00+00:00', '2002-11-06 00:00:00+00:00',
'2003-01-02 00:00:00+00:00', '2003-11-05 00:00:00+00:00',
'2004-01-02 00:00:00+00:00', '2004-11-17 00:00:00+00:00',
'2005-01-03 00:00:00+00:00', '2005-11-23 00:00:00+00:00',
'2006-01-02 00:00:00+00:00', '2006-11-16 00:00:00+00:00',
'2007-01-02 00:00:00+00:00', '2007-11-15 00:00:00+00:00',
'2008-01-02 00:00:00+00:00', '2008-11-13 00:00:00+00:00',
'2009-01-02 00:00:00+00:00', '2009-11-12 00:00:00+00:00',
'2010-01-04 00:00:00+00:00', '2010-11-18 00:00:00+00:00',
'2011-01-03 00:00:00+00:00', '2011-11-10 00:00:00+00:00',
'2012-01-02 00:00:00+00:00', '2012-11-08 00:00:00+00:00',
'2013-01-02 00:00:00+00:00', '2013-11-07 00:00:00+00:00',
'2014-01-02 00:00:00+00:00', '2014-11-13 00:00:00+00:00',
'2015-01-02 00:00:00+00:00', '2015-11-12 00:00:00+00:00',
'2016-01-04 00:00:00+00:00', '2016-11-17 00:00:00+00:00',
'2017-01-02 00:00:00+00:00', '2017-11-16 00:00:00+00:00',
'2017-11-23 00:00:00+00:00', '2018-01-02 00:00:00+00:00',
'2018-11-15 00:00:00+00:00', '2019-01-02 00:00:00+00:00',
'2019-11-14 00:00:00+00:00', '2020-01-02 00:00:00+00:00',
'2020-12-03 00:00:00+00:00', '2021-01-04 00:00:00+00:00',
'2022-01-03 00:00:00+00:00', '2022-09-07 00:00:00+00:00'],
dtype='datetime64[ns, UTC]', freq=None)
Starting in 2022, B3 will operate normally on municipal and state holidays, namely Aniversário de São Paulo, Revolução Constitucionalista, and Consciência Negra.
Here's a circular letter issued by B3 on 2020 anticipating some of these changes:
And here are some external sources (only in portuguese, sorry):
I believe it can be fixed easily by adding the end_date
parameter to each of the aforementioned holiday instances.
Since this seems like a good first issue, I could tackle it as my first contribution.
Probing bounds of calendars' start
parameter has found following unexpected errors:
'XNYS' with start date prior to 1956-12-25 raises ValueError("Special dates [Timestamp('1956-12-24 19:00:00+0000', tz='UTC')] are not trading days.")
. Suspect related to issue quantopian#196 for which there was a pending PR quantopian@6f06484.
'XKLS' with start date prior to 1984-02-02 raises ValueError("Special dates [Timestamp('1984-02-01 04:30:00+0000', tz='UTC')] are not trading days.")
. Possibly same cause as 'XNYS'
'XPHS' with start date prior to 1901-12-14 raises NonExistentTimeError('1901-12-13 09:30:00')
.
Within #31 I'll investigate / incorporate quantopian@6f06484. Going to ignore 'XPHS' error given the date (exchange didn't open until 1927!).
I recently updated my packages, and now when calling from exchange_calendars import get_calendar
, I get the following error:
Traceback (most recent call last):
File "test.py", line 1, in <module>
from exchange_calendars import get_calendar
File "/opt/miniconda3/lib/python3.7/site-packages/exchange_calendars/__init__.py", line 16, in <module>
from .calendar_utils import (
File "/opt/miniconda3/lib/python3.7/site-packages/exchange_calendars/calendar_utils.py", line 3, in <module>
from .always_open import AlwaysOpenCalendar
File "/opt/miniconda3/lib/python3.7/site-packages/exchange_calendars/always_open.py", line 5, in <module>
from .exchange_calendar import ExchangeCalendar
File "/opt/miniconda3/lib/python3.7/site-packages/exchange_calendars/exchange_calendar.py", line 27, in <module>
from .calendar_helpers import (
File "/opt/miniconda3/lib/python3.7/site-packages/exchange_calendars/calendar_helpers.py", line 6, in <module>
NP_NAT = np.array([pd.NaT], dtype=np.int64)[0]
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NaTType'
This occurs both on macOS with Python 3.7 and Ubuntu with Python 3.8.
@gerrymanoim, what do you think about moving the ExchangeCalendar execution_minutes_for_session
and execution_minutes_for_sessions_in_range
methods (and the supporting execution_time_from_open
and execution_time_from_close
) out of ExchangeCalendar (or at least deprecating them) and into 'QuantopianUSFuturesCalendar'?
These methods seem to have been defined specifically for QuantopianUSFuturesCalendar
(and indeed for a specific usage case of that calendar) - for all other calendars these methods return the same as the normal minutes_for_session
and minutes_for_sessions_in_range
methods. Would it not be clearer (particularly in light of the break with Zipline) to lose this clutter from ExchangeCalendar and have these methods represented only on the QuantopianUSFuturesCalendar?
Hello!
I was making a calendar for Kazakhstan Stock Exchange when I ran into a bug. I tried to add several special weekmasks for the extended working weeks before the holidays. According the instructions for creating new calendars, I overrided "special_weekmasks" property and added list of (date, date, str) tuples. But it didn't worked for me. When I tried to invoke "get_calendar" method, I received this error:
> ---------------------------------------------------------------------------
> KeyError Traceback (most recent call last)
> ~/python_projects/qf_py310_project/qf_py310_venv/lib/python3.10/site-packages/exchange_calendars/utils/memoize.py in __get__(self, instance, owner)
> 46 try:
> ---> 47 return self._cache[instance]
> 48 except KeyError:
>
> /usr/lib/python3.10/weakref.py in __getitem__(self, key)
> 415 def __getitem__(self, key):
> --> 416 return self.data[ref(key)]
> 417
>
> KeyError: <weakref at 0x7faad31dde90; to 'XKAZExchangeCalendar' at 0x7faaf6d5fc10>
>
> During handling of the above exception, another exception occurred:
>
> TypeError Traceback (most recent call last)
> /tmp/ipykernel_14416/1278388085.py in <module>
> 4 # nyse = xcals.get_calendar("XNYS", side='left')
> 5 # xkrx = xcals.get_calendar("XKRX", side='left')
> ----> 6 kase = xcals.get_calendar("XKAZ", side='left')
>
> ~/python_projects/qf_py310_project/qf_py310_venv/lib/python3.10/site-packages/exchange_calendars/calendar_utils.py in get_calendar(self, name, start, end, side)
> 287
> 288 cached = self._get_cached_factory_output(name, **kwargs)
> --> 289 return cached if cached is not None else self._fabricate(name, **kwargs)
> 290
> 291 def get_calendar_names(
>
> ~/python_projects/qf_py310_project/qf_py310_venv/lib/python3.10/site-packages/exchange_calendars/calendar_utils.py in _fabricate(self, name, **kwargs)
> 183 except KeyError as e:
> 184 raise InvalidCalendarName(calendar_name=name) from e
> --> 185 calendar = factory(**kwargs)
> 186 self._factory_output_cache[name] = (calendar, kwargs)
> 187 return calendar
>
> ~/python_projects/qf_py310_project/qf_py310_venv/lib/python3.10/site-packages/exchange_calendars/exchange_calendar.py in __init__(self, start, end, side)
> 251
> 252 # Midnight in UTC for each trading day.
> --> 253 _all_days = date_range(start, end, freq=self.day, tz=UTC)
> 254 if _all_days.empty:
> 255 raise errors.NoSessionsError(calendar_name=self.name, start=start, end=end)
>
> ~/python_projects/qf_py310_project/qf_py310_venv/lib/python3.10/site-packages/exchange_calendars/utils/memoize.py in __get__(self, instance, owner)
> 47 return self._cache[instance]
> 48 except KeyError:
> ---> 49 self._cache[instance] = val = self._get(instance)
> 50 return val
> 51
>
> ~/python_projects/qf_py310_project/qf_py310_venv/lib/python3.10/site-packages/exchange_calendars/exchange_calendar.py in day(self)
> 574 def day(self):
> 575 if self.special_weekmasks:
> --> 576 return MultipleWeekmaskCustomBusinessDay(
> 577 holidays=self.adhoc_holidays,
> 578 calendar=self.regular_holidays,
>
> ~/python_projects/qf_py310_project/qf_py310_venv/lib/python3.10/site-packages/exchange_calendars/pandas_extensions/offsets.py in __init__(self, n, normalize, weekmask, holidays, calendar, offset, business_days, weekmasks)
> 291 )
> 292 ]
> --> 293 CompositeCustomBusinessDay.__init__(
> 294 self, n, normalize, weekmask, holidays, calendar, offset, business_days
> 295 )
>
> ~/python_projects/qf_py310_project/qf_py310_venv/lib/python3.10/site-packages/exchange_calendars/pandas_extensions/offsets.py in __init__(self, n, normalize, weekmask, holidays, calendar, offset, business_days)
> 40 self, n, normalize, weekmask, holidays, calendar, offset
> 41 )
> ---> 42 self.business_days = business_days
> 43
> 44 def __setstate__(self, state):
>
> ~/python_projects/qf_py310_project/qf_py310_venv/lib/python3.10/site-packages/exchange_calendars/pandas_extensions/offsets.py in business_days(self, business_days)
> 88 2, toolz.concatv(self._business_days_index)
> 89 ):
> ---> 90 if right.left - left.right > pd.Timestamp(1, unit="D"):
> 91 # if right.left - left.right > pd.Timedelta(1, unit="D"):
> 92 interval = pd.Interval(
>
> TypeError: '>' not supported between instances of 'Timedelta' and 'Timestamp'
As I got it, on the line 90 of "offset.py" module, comparison between two periods was meant. So I tried to change "pd.Timestamp" to "pd.Timedelta" like in line 91 of the error log and it worked just fine.
Given that we have a list of Korean holidays hardcoded in, how would people feel about removing all of the Korean Lunar/Solar calendar stuff? The code's not thread-safe at initialisation time, and it's relatively slow to do its computations. I'm happy to open up the PR removing it, and add any remaining necessary hardcoded holidays.
Originally posted by @philiptromans in #125 (comment)
Sorry - can you also please resolve your conflict in exchange_calendars/xkls_holidays.py
? I think it is because I merged your other PR into master.
Originally posted by @gerrymanoim in #23 (comment)
I went and reformatted everything, but this currently doesn't run automatically.
When using exchange_calendars 3.2 with python3.6 I get the following error on import:
exchange_calendars/exchange_calendar.py", line 15
from future import annotations
^
SyntaxError: future feature annotations is not defined
Is there another way I can implement a futures calendar? I'm trying to pull the next 6 months of monthly contract expirations
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.