Skip to content

Commit

Permalink
Deprecate the CMEExchangeCalendar and make the CMEEquityExchangeCalen…
Browse files Browse the repository at this point in the history
…dar no longer inherit from the NYSE calendar.
  • Loading branch information
rsheftel committed May 7, 2021
1 parent 4e26494 commit 4b93612
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 119 deletions.
14 changes: 12 additions & 2 deletions docs/change_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@ Change Log

Updates
-------
1.6.2 (11/3/20)
~~~~~~~~~~~~~~~
1.7 (5/6/20)
~~~~~~~~~~~~
This version eliminated the generic CMEExchangeCalendar. This calendar did not represent a specific market and thus
was not appropriate for any use. With the addition of the specific calendars for product types this is no longer
needed and is removed. To see the product specific calendars here: https://pandas-market-calendars.readthedocs.io/en/latest/calendars.html#futures-calendars

For the CMEEquityExchangeCalendar, this no longer is a mirror of the NYSE calendar as some of the holidays for the NYSE
are an open day with early close for CME. This calendar now has its own set of holiday assumptions. This may cause
some holidays missing until this calendar is fully tested and vetted.

1.6.2 (5/6/20)
~~~~~~~~~~~~~~
- Fix UK Holidays for #130
- Fix CME Bond calendar for Good Friday #132

Expand Down
1 change: 0 additions & 1 deletion pandas_market_calendars/calendar_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from .exchange_calendar_bmf import BMFExchangeCalendar
from .exchange_calendar_cfe import CFEExchangeCalendar
from .exchange_calendar_cme import \
CMEExchangeCalendar, \
CMEAgricultureExchangeCalendar, \
CMEEquityExchangeCalendar, \
CMEBondExchangeCalendar
Expand Down
88 changes: 23 additions & 65 deletions pandas_market_calendars/exchange_calendar_cme.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,56 +27,54 @@
from .market_calendar import MarketCalendar


# Useful resources for making changes to this file:
# http://www.cmegroup.com/tools-information/holiday-calendar.html
# Useful resources for making changes to this file: http://www.cmegroup.com/tools-information/holiday-calendar.html
# The CME has different holiday rules depending on the type of instrument.
# For example, http://www.cmegroup.com/tools-information/holiday-calendar/files/2016-4th-of-july-holiday-schedule.pdf # noqa
# shows that Equity, Interest Rate, FX, Energy, Metals & DME Products close at 1200 CT on July 4, 2016, while Grain,
# Oilseed & MGEX Products and Livestock, Dairy & Lumber products are completely closed.


class CMEExchangeCalendar(MarketCalendar):
class CMEEquityExchangeCalendar(MarketCalendar):
"""
Exchange calendar for CME
Open Time: 5:00 PM, America/Chicago
Close Time: 5:00 PM, America/Chicago
Exchange calendar for CME for Equity products
Regularly-Observed Holidays:
- New Years Day
- Good Friday
- Christmas
Open Time: 6:00 PM, America/New_York / 5:00 PM Chicago
Close Time: 5:00 PM, America/New_York / 4:00 PM Chicago
Break: 4:15 - 4:30pm America/New_York / 3:15 - 3:30 PM Chicago
"""
aliases = ['CME', 'CBOT', 'COMEX', 'NYMEX']
aliases = ['CME_Equity', 'CBOT_Equity']

@property
def name(self):
return "CME"
return "CME_Equity"

@property
def tz(self):
return timezone('America/Chicago')

@property
def open_time_default(self):
return time(17, 1, tzinfo=self.tz)
return time(17, 0, tzinfo=self.tz)

@property
def close_time_default(self):
return time(17, tzinfo=self.tz)
return time(16, 0, tzinfo=self.tz)

@property
def open_offset(self):
return -1

@property
def regular_holidays(self):
# The CME has different holiday rules depending on the type of
# instrument. For example, http://www.cmegroup.com/tools-information/holiday-calendar/files/2016-4th-of-july-holiday-schedule.pdf # noqa
# shows that Equity, Interest Rate, FX, Energy, Metals & DME Products
# close at 1200 CT on July 4, 2016, while Grain, Oilseed & MGEX
# Products and Livestock, Dairy & Lumber products are completely
# closed.
def break_start(self):
return time(15, 15)

@property
def break_end(self):
return time(15, 30)

# For now, we will treat the CME as having a single calendar, and just
# go with the most conservative hours - and treat July 4 as an early
# close at noon.
@property
def regular_holidays(self):
# Many days that are holidays for the NYSE are an early close day for CME
return AbstractHolidayCalendar(rules=[
USNewYearsDay,
GoodFriday,
Expand Down Expand Up @@ -105,46 +103,6 @@ def special_closes(self):
)]


class CMEEquityExchangeCalendar(NYSEExchangeCalendar):
"""
Exchange calendar for CME for Equity products
Open Time: 6:00 PM, America/New_York
Close Time: 5:00 PM, America/New_York
Break: 4:15 - 4:30pm America/New_York
Regularly-Observed Holidays same as NYSE equity markets
"""
aliases = ['CME_Equity', 'CBOT_Equity']

@property
def name(self):
return "CME_Equity"

@property
def tz(self):
return timezone('America/New_York')

@property
def open_time_default(self):
return time(18, 0, tzinfo=self.tz)

@property
def close_time_default(self):
return time(17, 0, tzinfo=self.tz)

@property
def open_offset(self):
return -1

@property
def break_start(self):
return time(16, 15)

@property
def break_end(self):
return time(16, 30)


class CMEAgricultureExchangeCalendar(MarketCalendar):
"""
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from setuptools import find_packages, setup

# version
VERSION = '1.6.2'
VERSION = '1.7'

# requirements
REQUIRED_PYTHON = '>=3.5.0'
Expand Down
48 changes: 0 additions & 48 deletions tests/test_cme_calendar.py

This file was deleted.

41 changes: 40 additions & 1 deletion tests/test_cme_equity_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,50 @@


def test_time_zone():
assert CMEEquityExchangeCalendar().tz == pytz.timezone('America/New_York')
assert CMEEquityExchangeCalendar().tz == pytz.timezone('America/Chicago')
assert CMEEquityExchangeCalendar().name == 'CME_Equity'


def test_sunday_opens():
cme = CMEEquityExchangeCalendar()
schedule = cme.schedule('2020-01-01', '2020-01-31', tz='America/New_York')
assert pd.Timestamp('2020-01-12 18:00:00', tz='America/New_York') == schedule.at['2020-01-13', 'market_open']


def test_2016_holidays():
# good friday: 2016-03-25
# christmas (observed): 2016-12-26
# new years (observed): 2016-01-02
cme = CMEEquityExchangeCalendar()
good_dates = cme.valid_days('2016-01-01', '2016-12-31')
for date in ["2016-03-25", "2016-12-26", "2016-01-02"]:
assert pd.Timestamp(date, tz='UTC') not in good_dates


def test_2016_early_closes():
# mlk day: 2016-01-18
# presidents: 2016-02-15
# mem day: 2016-05-30
# july 4: 2016-07-04
# labor day: 2016-09-05
# thanksgiving: 2016-11-24

cme = CMEEquityExchangeCalendar()
schedule = cme.schedule('2016-01-01', '2016-12-31')
early_closes = cme.early_closes(schedule).index

for date in ["2016-01-18", "2016-02-15", "2016-05-30", "2016-07-04",
"2016-09-05", "2016-11-24"]:
dt = pd.Timestamp(date, tz='UTC')
assert dt in early_closes

market_close = schedule.loc[dt].market_close
assert market_close.tz_convert(cme.tz).hour == 12


def test_dec_jan():
cme = CMEEquityExchangeCalendar()
schedule = cme.schedule('2016-12-30', '2017-01-10')

assert schedule['market_open'].iloc[0] == pd.Timestamp('2016-12-29 23:00:00', tz='UTC')
assert schedule['market_close'].iloc[6] == pd.Timestamp('2017-01-10 22:00:00', tz='UTC')
2 changes: 1 addition & 1 deletion tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def test_get_calendar():
assert cal.close_time == datetime.time(14, 30)

# confirm that import works properly
_ = mcal.get_calendar('CME')
_ = mcal.get_calendar('CME_Equity')


def test_get_calendar_names():
Expand Down

0 comments on commit 4b93612

Please sign in to comment.