Git Product home page Git Product logo

pandas_market_calendars's Introduction

pandas_market_calendars

Market calendars to use with pandas for trading applications.

image

Documentation Status

image

Documentation

http://pandas-market-calendars.readthedocs.io/en/latest/

Overview

The Pandas package is widely used in finance and specifically for time series analysis. It includes excellent functionality for generating sequences of dates and capabilities for custom holiday calendars, but as an explicit design choice it does not include the actual holiday calendars for specific exchanges or OTC markets.

The pandas_market_calendars package looks to fill that role with the holiday, late open and early close calendars for specific exchanges and OTC conventions. pandas_market_calendars also adds several functions to manipulate the market calendars and includes a date_range function to create a pandas DatetimeIndex including only the datetimes when the markets are open. Additionally the package contains product specific calendars for future exchanges which have different market open, closes, breaks and holidays based on product type.

This package provides access to over 50+ unique exchange calendars for global equity and futures markets.

This package is a fork of the Zipline package from Quantopian and extracts just the relevant parts. All credit for their excellent work to Quantopian.

Major Releases

As of v1.0 this package only works with Python3. This is consistent with Pandas dropping support for Python2.

As of v1.4 this package now has the concept of a break during the trading day. For example this can accommodate Asian markets that have a lunch break, or futures markets that are open 24 hours with a break in the day for trade processing.

As of v2.0 this package provides a mirror of all the calendars from the exchange_calendars package, which itself is the now maintained fork of the original trading_calendars package. This adds over 50 calendars.

As of v3.0, the function date_range() is more complete and consistent, for more discussion on the topic refer to PR #142 and Issue #138.

As of v4.0, this package provides the framework to add interruptions to calendars. These can also be added to a schedule and viewed using the new interruptions_df property. A full list of changes can be found in PR #210.

Source location

Hosted on GitHub: https://github.com/rsheftel/pandas_market_calendars

Installation

pip install pandas_market_calendars

Arch Linux package available here: https://aur.archlinux.org/packages/python-pandas_market_calendars/

Calendars

The list of available calendars

Quick Start

import pandas_market_calendars as mcal

# Create a calendar
nyse = mcal.get_calendar('NYSE')

# Show available calendars
print(mcal.get_calendar_names())
early = nyse.schedule(start_date='2012-07-01', end_date='2012-07-10')
early

market_open market_close

=========== ========================= =========================

2012-07-02 2012-07-02 13:30:00+00:00 2012-07-02 20:00:00+00:00 2012-07-03 2012-07-03 13:30:00+00:00 2012-07-03 17:00:00+00:00 2012-07-05 2012-07-05 13:30:00+00:00 2012-07-05 20:00:00+00:00 2012-07-06 2012-07-06 13:30:00+00:00 2012-07-06 20:00:00+00:00 2012-07-09 2012-07-09 13:30:00+00:00 2012-07-09 20:00:00+00:00 2012-07-10 2012-07-10 13:30:00+00:00 2012-07-10 20:00:00+00:00

mcal.date_range(early, frequency='1D')
DatetimeIndex(['2012-07-02 20:00:00+00:00', '2012-07-03 17:00:00+00:00',

'2012-07-05 20:00:00+00:00', '2012-07-06 20:00:00+00:00', '2012-07-09 20:00:00+00:00', '2012-07-10 20:00:00+00:00'],

dtype='datetime64[ns, UTC]', freq=None)

mcal.date_range(early, frequency='1H')
DatetimeIndex(['2012-07-02 14:30:00+00:00', '2012-07-02 15:30:00+00:00',

'2012-07-02 16:30:00+00:00', '2012-07-02 17:30:00+00:00', '2012-07-02 18:30:00+00:00', '2012-07-02 19:30:00+00:00', '2012-07-02 20:00:00+00:00', '2012-07-03 14:30:00+00:00', '2012-07-03 15:30:00+00:00', '2012-07-03 16:30:00+00:00', '2012-07-03 17:00:00+00:00', '2012-07-05 14:30:00+00:00', '2012-07-05 15:30:00+00:00', '2012-07-05 16:30:00+00:00', '2012-07-05 17:30:00+00:00', '2012-07-05 18:30:00+00:00', '2012-07-05 19:30:00+00:00', '2012-07-05 20:00:00+00:00', '2012-07-06 14:30:00+00:00', '2012-07-06 15:30:00+00:00', '2012-07-06 16:30:00+00:00', '2012-07-06 17:30:00+00:00', '2012-07-06 18:30:00+00:00', '2012-07-06 19:30:00+00:00', '2012-07-06 20:00:00+00:00', '2012-07-09 14:30:00+00:00', '2012-07-09 15:30:00+00:00', '2012-07-09 16:30:00+00:00', '2012-07-09 17:30:00+00:00', '2012-07-09 18:30:00+00:00', '2012-07-09 19:30:00+00:00', '2012-07-09 20:00:00+00:00', '2012-07-10 14:30:00+00:00', '2012-07-10 15:30:00+00:00', '2012-07-10 16:30:00+00:00', '2012-07-10 17:30:00+00:00', '2012-07-10 18:30:00+00:00', '2012-07-10 19:30:00+00:00', '2012-07-10 20:00:00+00:00'],

dtype='datetime64[ns, UTC]', freq=None)

Contributing

All improvements and additional (and corrections) in the form of pull requests are welcome. This package will grow in value and correctness the more eyes are on it.

To add new functionality please include tests which are in standard pytest format.

Use pytest to run the test suite.

For complete information on contributing see CONTRIBUTING.md

Future

This package is open sourced under the MIT license. Everyone is welcome to add more exchanges or OTC markets, confirm or correct the existing calendars, and generally do whatever they desire with this code.

Sponsor

TradingHours.com

TradingHours.com provides the most accurate and comprehensive coverage of market holidays and trading hours data available. They cover over 900 markets around the world. Their data is continually monitored for changes and updated daily. Learn more

pandas_market_calendars's People

Contributors

1dot75cm avatar bgd11 avatar busteren avatar carterjfulcher avatar danilofrp avatar danilogalisteu avatar erkandem avatar gabglus avatar glossner avatar ilcatania avatar jmcdermo avatar keli avatar leonarduschen avatar mgellman-radix avatar misantroop avatar muttermachine avatar nategeorge avatar pehowell avatar pldrouin avatar rakesh1988 avatar richardcbam avatar rsheftel avatar rundef avatar sohamsjain avatar stdsp avatar stryder-git avatar timkpaine avatar twn-wi11i4m avatar woutdenolf avatar yogiyadav08 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pandas_market_calendars's Issues

calendar_registry.py imports

It looks like when you optimized imports in this commit, you removed the imports added in this commit, which re-created the empty registry issue that you had solved in the first commit.

This produces an error similar to:

'Class {} is not one of the registered classes: {}'.format(name, cls._regmeta_class_registry.keys()))
RuntimeError: Class NYSEExchangeCalendar is not one of the registered classes: dict_keys(['MarketCalendar'])

(Added error message that so people can search and find this by the error if they encounter it.)

EUREX calendar

The EUREX calendar has 1st of May dates included in "valid_days", although correctly marked as holidays.

Error in JPX calendar: 2016-01-04 was a trading day

import pandas_market_calendars as mcal
jpx = mcal.get_calendar('JPX')
jpx_s = jpx.schedule(start_date='2016-01-01', end_date='2016-01-31')
print(jpx_s)
                     market_open              market_close

2016-01-05 2016-01-05 00:00:00+00:00 2016-01-05 06:00:00+00:00
2016-01-06 2016-01-06 00:00:00+00:00 2016-01-06 06:00:00+00:00
2016-01-07 2016-01-07 00:00:00+00:00 2016-01-07 06:00:00+00:00
2016-01-08 2016-01-08 00:00:00+00:00 2016-01-08 06:00:00+00:00
2016-01-12 2016-01-12 00:00:00+00:00 2016-01-12 06:00:00+00:00
2016-01-13 2016-01-13 00:00:00+00:00 2016-01-13 06:00:00+00:00
2016-01-14 2016-01-14 00:00:00+00:00 2016-01-14 06:00:00+00:00
2016-01-15 2016-01-15 00:00:00+00:00 2016-01-15 06:00:00+00:00
2016-01-18 2016-01-18 00:00:00+00:00 2016-01-18 06:00:00+00:00
2016-01-19 2016-01-19 00:00:00+00:00 2016-01-19 06:00:00+00:00
2016-01-20 2016-01-20 00:00:00+00:00 2016-01-20 06:00:00+00:00
2016-01-21 2016-01-21 00:00:00+00:00 2016-01-21 06:00:00+00:00
2016-01-22 2016-01-22 00:00:00+00:00 2016-01-22 06:00:00+00:00
2016-01-25 2016-01-25 00:00:00+00:00 2016-01-25 06:00:00+00:00
2016-01-26 2016-01-26 00:00:00+00:00 2016-01-26 06:00:00+00:00
2016-01-27 2016-01-27 00:00:00+00:00 2016-01-27 06:00:00+00:00
2016-01-28 2016-01-28 00:00:00+00:00 2016-01-28 06:00:00+00:00
2016-01-29 2016-01-29 00:00:00+00:00 2016-01-29 06:00:00+00:00

2016-01-04 is not in the table, however, was a trading day:

http://markets.on.nytimes.com/research/markets/holidays/holidays.asp?display=market&timeOffset=-2&exchange=TYO

CME schedule return error

I was testing the schedule method with CME market.

schedule = cme.schedule(start_date='2016-12-30', end_date='2017-01-10')

And it return error
AttributeError: 'Index' object has no attribute 'tz_localize'

is USLaborDay missing?

Today 03/09/2019, CME calendars fails because USLaborDay information is missing....

https://www.cmegroup.com/tools-information/holiday-calendar.html#cmeGlobex

Code below:
import pandas_market_calendars as mcal
cme = mcal.get_calendar('CME')
schedule_cme = cme.schedule('2019-08-26', '2019-09-03')
schedule_cme

The output:

                     market_open              market_close

2019-08-26 2019-08-25 22:01:00+00:00 2019-08-26 22:00:00+00:00
2019-08-27 2019-08-26 22:01:00+00:00 2019-08-27 22:00:00+00:00
2019-08-28 2019-08-27 22:01:00+00:00 2019-08-28 22:00:00+00:00
2019-08-29 2019-08-28 22:01:00+00:00 2019-08-29 22:00:00+00:00
2019-08-30 2019-08-29 22:01:00+00:00 2019-08-30 22:00:00+00:00
2019-09-02 2019-09-01 22:01:00+00:00 2019-09-02 17:00:00+00:00
2019-09-03 2019-09-02 22:01:00+00:00 2019-09-03 22:00:00+00:00

Cannot generate trading calendar after 2018-11-23 (Thanksgiving Friday holiday) #Bug

Using the latest version 0.21.1 of the package, there is a problem retrieving the trading calendar after 2018-11-23 on a Linux server. The Python version on the server is Python 3.6.8 with Anaconda custom (64-bit).

import pandas_market_calendars as mcal
nyse = mcal.get_calendar('NYSE')
schedule = nyse.schedule('2018-11-01','2018-11-30')

The error message:
/usr/local/anaconda3/lib/python3.6/site-packages/pandas_market_calendars/market_calendar.py:397: FutureWarning: in the future, boolean array-likes will be handled as a boolean array index
opens_or_closes.values[indexer] = special_opens_or_closes.values[good_indexes]
Traceback (most recent call last):
File "", line 1, in
File "/usr/local/anaconda3/lib/python3.6/site-packages/pandas_market_calendars/market_calendar.py", line 237, in schedule
_overwrite_special_dates(_all_days, closes, _special_closes)
File "/usr/local/anaconda3/lib/python3.6/site-packages/pandas_market_calendars/market_calendar.py", line 397, in _overwrite_special_dates
opens_or_closes.values[indexer] = special_opens_or_closes.values[good_indexes]
IndexError: index 1 is out of bounds for axis 1 with size 1

I checked several date interval input combinations and found that it is the date 2018-11-23 that brings the problem. Before that, everything works just fine but it breaks down on or after that day. It seems the code fails where the program tries to overwrite the special dates after getting a general business calendar.

Wonder if anyone could help. Thanks!

`trading_calendars` is now a standalone module

Hi @rsheftel,

I just wanted to post an FYI that we've just landed a change in Zipline to factor out zipline.utils.calendars into a standalone trading_calendars module. We're working on adding support for international markets to Quantopian, so I expect there to be a fair amount of activity over there in the coming months.

Compiling problem with cx_Freeze

I've been trying to compile with cx_Freeze but can't seem to get around this. Having pandas_market_calendars in includes instead of packages does not help.
Pycs are present in lib.

setup.py:

from cx_Freeze import setup, Executable

buildOptions = dict(excludes = ["matplotlib", "PyQt4", "PySide2"],
					includes = ['urllib3', 'ibapi', 'idna.idnadata', 'numpy.core._methods', 'pandas',
								],
					optimize = 1,
					packages = ['pkg_resources._vendor', 'pandas_market_calendars'],
				)

setup(
    name = "ALT_sendOrder_STK",
    version = "0.1",
    description = "ALT_sendOrder_STK",
    executables = [Executable(script = "ALT_sendOrder_STK.py")],
	options = dict(build_exe=buildOptions)
)
  File "C:\Python\lib\site-packages\cx_Freeze\initscripts\__startup__.py", line 14, in run
    module.run()
  File "C:\Python\lib\site-packages\cx_Freeze\initscripts\Console.py", line 26, in run
    exec(code, m.__dict__)
  File "ALT_sendOrder_STK.py", line 18, in <module>
  File "C:\Python\lib\site-packages\pandas_market_calendars\__init__.py", line 22, in <module>
    __version__ = pkg_resources.get_distribution('pandas_market_calendars').version
  File "C:\Python\lib\site-packages\pkg_resources\__init__.py", line 476, in get_distribution
    dist = get_provider(dist)
  File "C:\Python\lib\site-packages\pkg_resources\__init__.py", line 352, in get_provider
    return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]
  File "C:\Python\lib\site-packages\pkg_resources\__init__.py", line 895, in require
    needed = self.resolve(parse_requirements(requirements))
  File "C:\Python\lib\site-packages\pkg_resources\__init__.py", line 781, in resolve
    raise DistributionNotFound(req, requirers)
pkg_resources.DistributionNotFound: The 'pandas_market_calendars' distribution was not found and is required by the application

Warning deprecation

I get this warning:
Warning (from warnings module):
File "D:\Phyton\lib\site-packages\pandas_market_calendars\exchange_calendar_ice.py", line 10
from pandas.tslib import Timestamp
FutureWarning: The pandas.tslib module is deprecated and will be removed in a future version.

Something else ... Could you change the examples in documents where is "import pandas_exchange_calendars" written for "import pandas_market_calendars"?

I told in http://pandas-market-calendars.readthedocs.io/en/latest/

Thank's for all and great module

GLOBEX closed from 5pm to 6pm

how come CME NYMEX show as open between 5-6pm EST? they don't trade 24 hours a day as the schedule suggests but 22 hours and 45 minutes a day, with pauses at 4:15 to 4:30 EST and 5pm-6pm EST

ValueError getting schedule

On master

>>> cal = nyse.schedule(start_date='1950-01-03', end_date='2018-05-18')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pandas_market_calendars/market_calendar.py", line 213, in schedule
    _overwrite_special_dates(_all_days, closes, _special_closes)
  File "pandas_market_calendars/market_calendar.py", line 363, in _overwrite_special_dates
    raise ValueError("Special dates %s are not trading days." % bad_dates)
ValueError: Special dates [Timestamp('1956-12-24 19:00:00+0000', tz='UTC')] are not trading days.

I was expecting a valid schedule returned.

New stock exchange?

Hi all,

This is a great package! I am currently tracking business days for NYSE, JPX, and TSX by using this package.

However, I am also tracking other stock exchanges, Australian Securities Exchange (ASX) and South Africa (JSE). I have to use other packages to track business days for these two stock exchanges specifically, which is not very convenient. Is it possible to add these two stock exchanges in this package in the future?

Thanks again for your significant contribution. It really helps!

Best regards,
Yang

Arch Linux Package

  1. if you can continue to provide the source going forward so that I can update the Arch package whenever there is a new version. Do you want to mention somewhere that a Linux package exists? Package_AUR
  2. the toolz package is causing me some issues because it is not in the official Linux repository. Is it really a requirement ? I see it is used in example but the market_calendar does not seem to require it. Can you confirm? Note that I created the package without this requirement and tested it with a few examples and it worked fine.

eurex

I am trying to implement eurex but could not find a clear definition of their rules which seems to have changed for the past years. welcome if anyone has some more insight.

Feature request: calendar registration by metaclass

Calendar registration is currently done by modifying "calendar_utils._calendars". This could be handled automatically with metaclasses. It would look something like this:

class RegisterMeta(type):
    """Takes care of calendar registration
    """

MarketCalendarMeta = type('MarketCalendarMeta', (ABCMeta, RegisterMeta), {})

class MarketCalendar(six.with_metaclass(MarketCalendarMeta)):
    """Inherits from MarketCalendarMeta instead of ABCMeta, no other changes
    """
    
get_calendar = MarketCalendar.calendar_factory
calendars = list(MarketCalendar.calendar_class_registry.keys())

The only change is that MarketCalendar has a different metaclass. Additionally the derived calendars will have an "aliases" attribute:

class NYSEExchangeCalendar(MarketCalendar):
    aliases = ['NYSE','NASDAQ','BATS']
    ....

class CMEExchangeCalendar(MarketCalendar):
    aliases = ['CME','COMEX','CBOT','NYMEX']
    ....

Usage:

print(calendars)
['MarketCalendar', 'NYSEExchangeCalendar', 'NYSE', 'NASDAQ', 'BATS', 'CMEExchangeCalendar', 'CME', 'COMEX', 'CBOT', 'NYMEX']

mcal = get_calendar('NYSE',...)

You can use class name or alias to generate a calendar. One could consider removing "MarketCalendar" from the registry (will be there by default because it derives from RegisterMeta). Would you consider a PR that implements this idea?

Victoria Day

2015-05-25 and 2009-05-25 in TSX are treated as Victoria day. However 2015-05-18 and 2009-05-18 are the correct dates.

Bug/Question about .convert_freq() and NYSE Sep 04

Hi, this is the first time I am using this library, so not unlikely I am just doing something wrong. Anyway, I am trying to get the end and start of the NYSE for each month in 2018. Then the following code seems to me to be a bit odd behaviour. It will correctly return 4 September as the start date, however, with .convert_freq() it will start on the 3 Sep:

import pandas_market_calendars as mcal

early = nyse.valid_days(start_date='2018-07-01', end_date='2018-10-10')
early
DatetimeIndex(['2018-07-02', '2018-07-03', '2018-07-05', '2018-07-06',
               '2018-07-09', '2018-07-10', '2018-07-11', '2018-07-12',
               '2018-07-13', '2018-07-16', '2018-07-17', '2018-07-18',
               '2018-07-19', '2018-07-20', '2018-07-23', '2018-07-24',
               '2018-07-25', '2018-07-26', '2018-07-27', '2018-07-30',
               '2018-07-31', '2018-08-01', '2018-08-02', '2018-08-03',
               '2018-08-06', '2018-08-07', '2018-08-08', '2018-08-09',
               '2018-08-10', '2018-08-13', '2018-08-14', '2018-08-15',
               '2018-08-16', '2018-08-17', '2018-08-20', '2018-08-21',
               '2018-08-22', '2018-08-23', '2018-08-24', '2018-08-27',
               '2018-08-28', '2018-08-29', '2018-08-30', '2018-08-31',
               '2018-09-04', '2018-09-05', '2018-09-06', '2018-09-07',
               '2018-09-10', '2018-09-11', '2018-09-12', '2018-09-13',
               '2018-09-14', '2018-09-17', '2018-09-18', '2018-09-19',
               '2018-09-20', '2018-09-21', '2018-09-24', '2018-09-25',
               '2018-09-26', '2018-09-27', '2018-09-28', '2018-10-01',
               '2018-10-02', '2018-10-03', '2018-10-04', '2018-10-05',
               '2018-10-08', '2018-10-09', '2018-10-10'],
              dtype='datetime64[ns, UTC]', freq='C')

mcal.convert_freq(early, frequency='BMS')
DatetimeIndex(['2018-07-02', '2018-08-01', '2018-09-03', '2018-10-01'], dtype='datetime64[ns, UTC]', freq='BMS')

Is this how it should behave?
If not, then I would appreciate a workaround :)

Japan Calendar needs work

FYI, I found some problems in the JPX calendar. I have fixed all these problems in my private copy, and I have verified my changes against a list of dates for the Nikkei 225 index since 5/16/1949.

I will submit a patch as soon as I get a chance to write a few tests.

Here are the problems I found:

For dates before 1973 or so, holidays landing on a Sunday did not generally close the exchange on a Monday.

There were certain holidays that did not have a start date (some holidays only began after 1948).

The exchange was closed on December 29 and 30 until 1989.

The Emperor's birthday is switching in 2020, and this is not reflected in the prospective calendar holidays.

For 2020 also, due to the Olympics, a number of holidays are switching around, and Health and Sports Day is being renamed Sports Day starting in 2020.

No vernal or autumnal projected dates were included past 2031 (I needed the calendar through 2099).

Last holidays are in 2030

Hi, in the docs (screenshot below) we can see the last holidays are 2030. Is there a way to get holidays past 2030 and all the way up to 2100? I've looked around in the code but I can't see that this has been hard coded or is an option. Thank you very much.
LastHolidays

Version 0.21 has no calendars

import pandas_market_calendars as mcal
print(mcal.get_calendar_names())

It prints an empty array.

nyse = mcal.get_calendar('NYSE')
produces the error:
RuntimeError: Class NYSE is not one of the registered classes: dict_keys(['MarketCalendar'])

return_name

thanks for this project.
I am having difficulty getting back the name of the holiday corresponding to the dates returned in .holidays()
How can I get back the holiday name together with the date?

Issues with merge_schedules when list is larger than 2

Firstly thanks for the great project, it's very helpful. I am having issues with merge_schedules when the input list is greater than two. The issue seems to be that multiple calls to pd.merge happen causing repeated columns, e.g. market_open_x, which then fails when the lambda function is applied. Here is an illustrative example

import pandas_market_calendars as mcal

start_date = "20170103"
end_date = "20170104"

cme = mcal.get_calendar("CME")
nyse = mcal.get_calendar("NYSE")
ice = mcal.get_calendar("ICE")

s1 = cme.schedule(start_date, end_date)
s2 = nyse.schedule(start_date, end_date)
s3 = ice.schedule(start_date, end_date)

schedules = [s1, s2, s3]

mcal.merge_schedules(schedules, how='inner')

ValueError: ('Can only compare identically-labeled Series objects', 'occurred at index 2017-01-03 00:00:00')

As described above, here is an illustration of the internal code causing the
issue

how = "inner"
result = s1
result = result.merge(s2, how=how, right_index=True, left_index=True)
result['market_open'] = result.apply(lambda x: max(x.market_open_x, x.market_open_y), axis=1)
result['market_close'] = result.apply(lambda x: min(x.market_close_x, x.market_close_y), axis=1)
result = result.merge(s3, how=how, right_index=True, left_index=True)
print(result)
                       market_open_x            market_close_x  \
2017-01-03 2017-01-02 23:01:00+00:00 2017-01-03 23:00:00+00:00   
2017-01-04 2017-01-03 23:01:00+00:00 2017-01-04 23:00:00+00:00   

                       market_open_y            market_close_y  \
2017-01-03 2017-01-03 14:30:00+00:00 2017-01-03 21:00:00+00:00   
2017-01-04 2017-01-04 14:30:00+00:00 2017-01-04 21:00:00+00:00   

                       market_open_x            market_close_x  \
2017-01-03 2017-01-03 14:30:00+00:00 2017-01-03 21:00:00+00:00   
2017-01-04 2017-01-04 14:30:00+00:00 2017-01-04 21:00:00+00:00   

                       market_open_y            market_close_y  
2017-01-03 2017-01-03 01:01:00+00:00 2017-01-03 23:00:00+00:00  
2017-01-04 2017-01-04 01:01:00+00:00 2017-01-04 23:00:00+00:00 

In addition, the use of pop on the input list has the side effect of changing
the input, I believe this is an unintended side effect?

Schedule and date_range mismatch

I was trying to use the date_range function and it seems like it returns the time with an hour offset, e.g.:

>>> schedule = lse.schedule(start_date='2016-12-30', end_date='2017-01-10')
>>> schedule
                         market_open              market_close
2016-12-30 2016-12-30 08:00:00+00:00 2016-12-30 12:30:00+00:00
2017-01-03 2017-01-03 08:00:00+00:00 2017-01-03 16:30:00+00:00
2017-01-04 2017-01-04 08:00:00+00:00 2017-01-04 16:30:00+00:00
2017-01-05 2017-01-05 08:00:00+00:00 2017-01-05 16:30:00+00:00
2017-01-06 2017-01-06 08:00:00+00:00 2017-01-06 16:30:00+00:00
2017-01-09 2017-01-09 08:00:00+00:00 2017-01-09 16:30:00+00:00
2017-01-10 2017-01-10 08:00:00+00:00 2017-01-10 16:30:00+00:00

>>> schedule.iloc[0]
market_open    2016-12-30 08:00:00+00:00
market_close   2016-12-30 12:30:00+00:00
Name: 2016-12-30 00:00:00, dtype: datetime64[ns, UTC]

>>> d=mcal.date_range(schedule, frequency='1H')
>>> d[:10]
DatetimeIndex(['2016-12-30 09:00:00+00:00', '2016-12-30 10:00:00+00:00',
               '2016-12-30 11:00:00+00:00', '2016-12-30 12:00:00+00:00',
               '2016-12-30 12:30:00+00:00', '2017-01-03 09:00:00+00:00',
               '2017-01-03 10:00:00+00:00', '2017-01-03 11:00:00+00:00',
               '2017-01-03 12:00:00+00:00', '2017-01-03 13:00:00+00:00'],
              dtype='datetime64[ns, UTC]', freq=None)

I would assume that the date_range started at 08:00:00, not at 9. Is this intended?

Cannot change frequency to multiple days

My code is:

from pandas.tseries.offsets import DateOffset

tz = pytz.timezone('US/Eastern')
now_tz = datetime.datetime.now(tz)

dt_end = now_tz
dt_start = dt_end - DateOffset(days=50)

mkt_cal = mcal.get_calendar('NYSE')

schedule = mkt_cal.schedule(dt_start, dt_end)
bar_dts = mcal.date_range(schedule, frequency='3D')

The output shows that the frequency is 1 day, not 3 days:
bar_dts
DatetimeIndex(['2017-09-05 20:00:00+00:00', '2017-09-06 20:00:00+00:00',
'2017-09-07 20:00:00+00:00', '2017-09-08 20:00:00+00:00',
'2017-09-11 20:00:00+00:00', '2017-09-12 20:00:00+00:00',
'2017-09-13 20:00:00+00:00', '2017-09-14 20:00:00+00:00',
'2017-09-15 20:00:00+00:00', '2017-09-18 20:00:00+00:00',
'2017-09-19 20:00:00+00:00', '2017-09-20 20:00:00+00:00',
'2017-09-21 20:00:00+00:00', '2017-09-22 20:00:00+00:00',
'2017-09-25 20:00:00+00:00', '2017-09-26 20:00:00+00:00',
'2017-09-27 20:00:00+00:00', '2017-09-28 20:00:00+00:00',
'2017-09-29 20:00:00+00:00', '2017-10-02 20:00:00+00:00',
'2017-10-03 20:00:00+00:00', '2017-10-04 20:00:00+00:00',
'2017-10-05 20:00:00+00:00', '2017-10-06 20:00:00+00:00',
'2017-10-09 20:00:00+00:00', '2017-10-10 20:00:00+00:00',
'2017-10-11 20:00:00+00:00', '2017-10-12 20:00:00+00:00',
'2017-10-13 20:00:00+00:00', '2017-10-16 20:00:00+00:00',
'2017-10-17 20:00:00+00:00', '2017-10-18 20:00:00+00:00',
'2017-10-19 20:00:00+00:00', '2017-10-20 20:00:00+00:00',
'2017-10-23 20:00:00+00:00'],
dtype='datetime64[ns, UTC]', freq='B')

Setting frequency to '1W' also yields 1-day frequency data.
What is wrong?

schedule() error with open_time_default

If I instantiate an implementation of a MarketCalendar which does not implement open_time and close_time, the schedule function throws errors. The issue is with the call to days_at_time by the schedule function, e.g.

# `DatetimeIndex`s of standard opens/closes for each day.
opens = days_at_time(_all_days, self.open_time, self.tz, self.open_offset)
closes = days_at_time(_all_days, self.close_time, self.tz, self.close_offset)

Since self.open_time = self.open_time_default = None, this throws an AttributeError in days_at_time. A simple example is

import pandas_market_calendars as mcal
import pandas as pd
from pandas.tseries.holiday import AbstractHolidayCalendar

class DummyCalendar(mcal.MarketCalendar):

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

    @property
    def tz(self):
        return "UTC"

    @property
    def adhoc_holidays(self):
        return [pd.Timestamp("2015-01-03", tz="UTC")]

    @property
    def regular_holidays(self):
        return AbstractHolidayCalendar()


dummy = DummyCalendar()
dummy.schedule("2015-01-01", "2015-01-10")

Unless I'm missing something, my thoughts are that as it currently stands it seems like making open_time and close_time abstract methods would be better unless there is a default value that would address this?

Early market closes fail when using include_close=True

market_open = nyse.schedule(start_date='2012-07-03', end_date='2012-07-03')

market_open

market_open market_close
2012-07-03 13:30:00+00:00 2012-07-03 17:00:00+00:00

nyse.open_at_time(early, pd.Timestamp('2012-07-03 01:00:00', tz='America/New_York'), include_close=True)

False

nyse.open_at_time(early, pd.Timestamp('2012-07-03 12:59:00', tz='America/New_York'), include_close=True)

True


Seems like they should both be producing True?


HKEX calendar KeyError on call to holidays() with pandas 1.0.0

using pandas_market_calendars version 1.2 on python 3.7 with pandas 1.0.0

import pandas_market_calendars as mcal
from pandas.tseries.offsets import CustomBusinessDay

exchange = 'HKEX'
cal = mcal.get_calendar(exchange)
try:
    cal.holidays()
except Exception as ex:
    print(type(ex))
    print(ex)

result in:

<class 'KeyError'>
2100

relevant stack trace detail:

...lib/python3.7/site-packages/pandas_market_calendars/exchange_calendar_hkex.py in process_date(dt, mapping, func, delta, offset)
     16 
     17 def process_date(dt, mapping=None, func=None, delta=None, offset=None):
---> 18     new_dt = mapping and mapping[dt.year] or dt
     19     if delta:
     20         new_dt = new_dt + timedelta(delta)

KeyError: 2100

Same code with other exchanges works fine:

exchange = 'JPX'
cal = mcal.get_calendar(exchange)
try:
    cal.holidays()
except Exception as ex:
    print(type(ex))
    print(ex)

Irregular English bank holidays missing from the LSE calender

Could you please account for the following occasions in which the LSE was either closed due to a one-off English bank holiday or open due to the removal of a regular bank holiday in compensation [1, 2].

This code includes all the dates on which ad-hoc holiday addition or removal is required:

import pandas as pd
import pandas_market_calendars as mcal

England_unique_hols_names = [
                                "VE_50", "VE_75", 
                                "QEII_Jubilee_25", "QEII_Jubilee_50", "QEII_Jubilee_60",
                                "Royal_Wedding_Anne_1973", "Royal_Wedding_Charles_1981", "Royal_Wedding_William_2011",
                                "3rd_Millenium_Eve",
                            ]
England_unique_hols = {i: {"closed": None, "open": None} for i in England_unique_hols_names}

#=====================================================
# One-off holiday additions and removals in England
#=====================================================

## VE-Day Anniversary
# 50th Anniversary
England_unique_hols["VE_50"]["closed"] = [pd.Timestamp("1995-05-08")]      
England_unique_hols["VE_50"]["open"] = [pd.Timestamp("1995-05-01")]     # Early May bank holiday removed
# 75th Anniversary
England_unique_hols["VE_75"]["closed"] = [pd.Timestamp("2020-05-08")]      
England_unique_hols["VE_75"]["open"] = [pd.Timestamp("2020-05-04")]     # Early May bank holiday removed

## Queen Elizabeth II Jubilees
# Silver Jubilee
England_unique_hols["QEII_Jubilee_25"]["closed"] = [pd.Timestamp("1977-06-07")]
# Golden Jubilee
England_unique_hols["QEII_Jubilee_50"]["closed"] = [pd.Timestamp("2002-06-03"), pd.Timestamp("2002-06-04")]    
England_unique_hols["QEII_Jubilee_50"]["open"] = [pd.Timestamp("2002-05-27")]                                   # Spring bank holiday removed
# Diamond Jubilee
England_unique_hols["QEII_Jubilee_60" ]["closed"] = [pd.Timestamp("2012-06-04"), pd.Timestamp("2012-06-05")]    # Already added in ecd8ec4
England_unique_hols["QEII_Jubilee_60" ]["open"] = [pd.Timestamp("2012-05-28")]                                  # Spring bank holiday removed (Not removed as of release 1.2)

## Royal Weddings
# Wedding Day of Princess Anne and Mark Phillips
England_unique_hols["Royal_Wedding_Anne_1973"]["closed"] = [pd.Timestamp("1973-11-14")]      
# Wedding Day of Prince Charles and Diana Spencer
England_unique_hols["Royal_Wedding_Charles_1981"]["closed"] = [pd.Timestamp("1981-07-29")]     
# Wedding Day of Prince William and Catherine Middleton
England_unique_hols["Royal_Wedding_William_2011"]["closed"] = [pd.Timestamp("2011-04-29")]  

## Miscellaneous
# Eve of 3rd Millenium A.D.
England_unique_hols["3rd_Millenium_Eve"]["closed"] = [pd.Timestamp("1999-12-31")] 


#=====================================================
# Test of current LSE calender
#=====================================================

LSE_sch = mcal.get_calendar("LSE").schedule(start_date="1900-01-01", end_date="2099-12-31")

for i in England_unique_hols:

    print(i)

    min_closed = np.min(England_unique_hols[i]["closed"])
    max_closed = np.max(England_unique_hols[i]["closed"])
    print("should be closed:")
    print(LSE_sch.iloc[np.logical_and(min_closed <= LSE_sch.index, LSE_sch.index <= max_closed)]) 
    if England_unique_hols[i]["open"] is not None:
        min_open = np.min(England_unique_hols[i]["open"])
        max_open = np.max(England_unique_hols[i]["open"])
        print("should be open:")
        print(LSE_sch.iloc[np.logical_and(min_open <= LSE_sch.index, LSE_sch.index <= max_open)]) 
        
    print("")

Running the above gives the following output:

VE_50
should be closed:
                         market_open              market_close
1995-05-08 1995-05-08 07:00:00+00:00 1995-05-08 15:30:00+00:00
should be open:
Empty DataFrame
Columns: [market_open, market_close]
Index: []

VE_75
should be closed:
                         market_open              market_close
2020-05-08 2020-05-08 07:00:00+00:00 2020-05-08 15:30:00+00:00
should be open:
Empty DataFrame
Columns: [market_open, market_close]
Index: []

QEII_Jubilee_25
should be closed:
                         market_open              market_close
1977-06-07 1977-06-07 07:00:00+00:00 1977-06-07 15:30:00+00:00

QEII_Jubilee_50
should be closed:
                         market_open              market_close
2002-06-03 2002-06-03 07:00:00+00:00 2002-06-03 15:30:00+00:00
2002-06-04 2002-06-04 07:00:00+00:00 2002-06-04 15:30:00+00:00
should be open:
Empty DataFrame
Columns: [market_open, market_close]
Index: []

QEII_Jubilee_60
should be closed:
Empty DataFrame
Columns: [market_open, market_close]
Index: []
should be open:
Empty DataFrame
Columns: [market_open, market_close]
Index: []

Royal_Wedding_Anne_1973
should be closed:
                         market_open              market_close
1973-11-14 1973-11-14 08:00:00+00:00 1973-11-14 16:30:00+00:00

Royal_Wedding_Charles_1981
should be closed:
                         market_open              market_close
1981-07-29 1981-07-29 07:00:00+00:00 1981-07-29 15:30:00+00:00

Royal_Wedding_William_2011
should be closed:
                         market_open              market_close
2011-04-29 2011-04-29 07:00:00+00:00 2011-04-29 15:30:00+00:00

3rd_Millenium_Eve
should be closed:
                         market_open              market_close
1999-12-31 1999-12-31 08:00:00+00:00 1999-12-31 12:30:00+00:00

I note that you have already added the additional holidays on 2012-06-04 and 2012-06-05 for the Diamond Jubilee, but did not remove the corresonding spring bank holiday on 2012-05-28.

Thank you in advance.

source tarball for Linux package

Hello @rsheftel

I wish to make an Arch Linux package for pandas_market_calendars. Would you be able to save the source tarball whenever you make a Python wheel ?
Usually a source tarball is available in pypi but not for pandas_market_calendars,

This is typically where I would pickup the source here but there are only .whl

Alternatively, if you prefer I can pick up releases you would make on GitHub.

Thanks

days_at_time throws exception if there are no open days, proposed change included

Hi,

Calling the .schedule() method will throw an exception if there are no business days between start_date and end_date. For example

nyse_cal = mcal.get_calendar('NYSE')
nyse_schedule = nyse_cal.schedule(start_date = '2018-06-30',end_date = '2018-06-30')

The specific error message is
File "/home/username/.local/lib/python3.5/site-packages/pandas_market_calendars/market_calendar.py", line 312, in days_at_time
return pd.DatetimeIndex(days).tz_localize(tz).tz_convert('UTC')
File "/home/username/.local/lib/python3.5/site-packages/pandas/core/indexes/datetimes.py", line 2379, in tz_localize
raise TypeError("Already tz-aware, use tz_convert to convert.")
TypeError: Already tz-aware, use tz_convert to convert.

Would it be appropriate to change the relevant code section as follows?
if pd.DatetimeIndex(days).tzinfo is not None:
return pd.DatetimeIndex(days).tz_convert('UTC')
else:
return pd.DatetimeIndex(days).tz_localize(tz).tz_convert('UTC')

Apologies in advance if this isn't the right format in which to bring this up. I'm not confident enough in my proposed change to submit a pull request (if that's even the correct term) ...

Wondering about trading hours

Hi,

I'm looking to trade and need to know when are exchanges open. I think I will move forward with this library.

One issue I have is that it doesn't have trading hours of NASDAQ (but it does have NYSE). I am comparing the trading hours and holidays of NASDAQ and NYSE and they seem very similar. Also, when I check on

https://www.worldtimezone.com/markets24.php

, I see that they do not show NASDAQ (I don't know how to understand DFIX, NASDAQ Dubai), but they do show NYSE.

Are NYSE's and NASDAQ's trading hours the same? Or almost the same? Where would be a better place to ask this?

Also, this library does not tell you what the pre-market and after market hours are.

Is there any way to know the pre-market and after market hours if you're given the regular trading hours? Is it always a certain numbers of hours before market open and and a certain number of hours after close?

Thank you,

kovkev

Feature request: get market calendar in various timezones

I think it would be nice to have the option in get_calendar() to specify a timezone you want the calendar in. Here is some code I've written recently to do this:

def get_eastern_market_open_close():
    ny = pytz.timezone('America/New_York')
    today_ny = datetime.datetime.now(ny)
    ndq = mcal.get_calendar('NASDAQ')
    open_days = ndq.schedule(start_date=today_ny - pd.Timedelta(str(3*365) + ' days'),
                             end_date=today_ny)
    # convert times to eastern
    for m in ['market_open', 'market_close']:
        open_days[m] = open_days[m].dt.tz_convert('America/New_York')

    return open_days

I'd be happy to implement this, I don't see any guidelines on collaborating though. Am I good to just code it and issue a pull request?

Not sure if it's better suited in get_calendar or .schedule

How to create a market schedule for a given day, on that day?

I have no problem determining opens\closes for a range of dates in the future, but if the parameters of my query using the .schedule() method are 'start_date=today, end_date=today', an error's raised when the code compiles involving self.tz : 'already tz-aware, use tz_convert'. Is there another way to determine if, say, the NYSE is open right now? Thanks in advance for any help with this.

London calendar does not account for Queen's Diamond Jubilee Holidays

Can you please account for the following dates in the london schedule as this has caused a headache wondering why data wasn't being returned for these dates:

# Bank Holiday + Queen's Diamond Jubilee
schedule.drop([pd.Timestamp('2012-06-04T00:00:00.000000000'), pd.Timestamp('2012-06-05T00:00:00.000000000')], inplace=True)

calendar_registry imports

Commit was rejected but I get this when not importing calendars into calendar_registry (3.6.7):

  File "C:\Python\lib\site-packages\pandas_market_calendars\calendar_registry.py", line 14, in get_calendar
    return MarketCalendar.factory(name, open_time=open_time, close_time=close_time)
  File "C:\Python\lib\site-packages\pandas_market_calendars\market_calendar.py", line 51, in factory
    return self._regmeta_instance_factory(name, open_time=open_time, close_time=close_time)
  File "C:\Python\lib\site-packages\pandas_market_calendars\class_registry.py", line 20, in _regmeta_instance_factory
    return cls._regmeta_class_factory(name)(*args,**kwargs)
  File "C:\Python\lib\site-packages\pandas_market_calendars\class_registry.py", line 10, in _regmeta_class_factory
    raise RuntimeError('Class {} is not one of the registered classes: {}'.format(name,cls._regmeta_class_registry.keys()))
RuntimeError: Class JPX is not one of the registered classes: dict_keys(['MarketCalendar'])

Add is_open_now convenience method

It would be very convenient to have a is_open_now method (naming to be discussed) that returns True/False based on the systems current datetime, without having to explicitly pass a timestamp.

CME schedule displaying invalid dates

I'm receiving bad dates when I use the CME calendar.

I could get the holiday's via cme.early_closes(schedule) but these are regular holidays for CME, and not early closes:

        USNewYearsDay,
        USMartinLutherKingJrAfter1998,
        USPresidentsDay,
        GoodFriday,
        USMemorialDay,
        USIndependenceDay,
        USLaborDay,
        USThanksgivingDay,
        Christmas,

Here is a code snippet that demonstrates:

import pandas_market_calendars as mcal
import pandas as pd
cme = mcal.get_calendar("CME")
schedule = cme.schedule(start_date="2020-01-01", end_date="2020-12-31")
print(schedule)
sessions = schedule["market_close"]

# See 2020 Calendar here:
# http://investor.cmegroup.com/static-files/bae826b9-bac3-4559-be69-0f5e04fc9c2b
INVALID_HOLIDAYS_FOR_TRADING = [
    "2020-01-20",
    "2020-02-17",
    "2020-04-10",
    "2020-05-25",
    "2020-07-03",
    "2020-09-07",
    "2020-11-26",
    "2020-12-25",
]

for day in INVALID_HOLIDAYS_FOR_TRADING:
    if pd.to_datetime(day) in sessions:
        print(f"ERROR: {day} found in schedule")
    else:
        print(f"OK: {day} not in schedule")


This gave me:

ERROR: 2020-01-20 found in schedule
ERROR: 2020-02-17 found in schedule
OK: 2020-04-10 not in schedule
ERROR: 2020-05-25 found in schedule
ERROR: 2020-07-03 found in schedule
ERROR: 2020-09-07 found in schedule
ERROR: 2020-11-26 found in schedule
OK: 2020-12-25 not in schedule

Versions:

  • Python: 3.6.1
  • pandas 1.0.2
  • pandas_market_calendars 1.2

Error in JPX calendar.

There is an error in the JPX calendar for 2016:

import pandas_market_calendars as mcal
jpx = mcal.get_calendar('JPX')
jpx_s = jpx.schedule(start_date='2016-09-01', end_date='2016-09-30')
jpx_s
market_open market_close
2016-09-01 2016-09-01 00:00:00+00:00 2016-09-01 06:00:00+00:00
2016-09-02 2016-09-02 00:00:00+00:00 2016-09-02 06:00:00+00:00
2016-09-05 2016-09-05 00:00:00+00:00 2016-09-05 06:00:00+00:00
2016-09-06 2016-09-06 00:00:00+00:00 2016-09-06 06:00:00+00:00
2016-09-07 2016-09-07 00:00:00+00:00 2016-09-07 06:00:00+00:00
2016-09-08 2016-09-08 00:00:00+00:00 2016-09-08 06:00:00+00:00
2016-09-09 2016-09-09 00:00:00+00:00 2016-09-09 06:00:00+00:00
2016-09-12 2016-09-12 00:00:00+00:00 2016-09-12 06:00:00+00:00
2016-09-13 2016-09-13 00:00:00+00:00 2016-09-13 06:00:00+00:00
2016-09-14 2016-09-14 00:00:00+00:00 2016-09-14 06:00:00+00:00
2016-09-15 2016-09-15 00:00:00+00:00 2016-09-15 06:00:00+00:00
2016-09-16 2016-09-16 00:00:00+00:00 2016-09-16 06:00:00+00:00
2016-09-20 2016-09-20 00:00:00+00:00 2016-09-20 06:00:00+00:00
2016-09-21 2016-09-21 00:00:00+00:00 2016-09-21 06:00:00+00:00
2016-09-22 2016-09-22 00:00:00+00:00 2016-09-22 06:00:00+00:00
2016-09-26 2016-09-26 00:00:00+00:00 2016-09-26 06:00:00+00:00
2016-09-27 2016-09-27 00:00:00+00:00 2016-09-27 06:00:00+00:00
2016-09-28 2016-09-28 00:00:00+00:00 2016-09-28 06:00:00+00:00
2016-09-29 2016-09-29 00:00:00+00:00 2016-09-29 06:00:00+00:00
2016-09-30 2016-09-30 00:00:00+00:00 2016-09-30 06:00:00+00:00

However, 2016-09-22 was a public holiday (Autumn Equinox):

http://markets.on.nytimes.com/research/markets/holidays/holidays.asp?display=market&timeOffset=-2&exchange=TYO

while on 2016-09-23 the market was open.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.