Examples¶
import sys
sys.path.append("../")
from datetime import time
import pandas as pd
import pandas_market_calendars as mcal
Setup new exchange calendar¶
nyse = mcal.get_calendar('NYSE')
Get the time zone
nyse.tz.zone
'America/New_York'
Get the AbstractHolidayCalendar object
holidays = nyse.holidays()
holidays.holidays[-5:]
(numpy.datetime64('2200-05-26'),
numpy.datetime64('2200-07-04'),
numpy.datetime64('2200-09-01'),
numpy.datetime64('2200-11-27'),
numpy.datetime64('2200-12-25'))
Exchange open valid business days¶
Get the valid open exchange business dates between a start and end date. Note that Dec 26 (Christmas), Jan 2 (New Years) and all weekends are missing
nyse.valid_days(start_date='2016-12-20', end_date='2017-01-10')
DatetimeIndex(['2016-12-20 00:00:00+00:00', '2016-12-21 00:00:00+00:00',
'2016-12-22 00:00:00+00:00', '2016-12-23 00:00:00+00:00',
'2016-12-27 00:00:00+00:00', '2016-12-28 00:00:00+00:00',
'2016-12-29 00:00:00+00:00', '2016-12-30 00:00:00+00:00',
'2017-01-03 00:00:00+00:00', '2017-01-04 00:00:00+00:00',
'2017-01-05 00:00:00+00:00', '2017-01-06 00:00:00+00:00',
'2017-01-09 00:00:00+00:00', '2017-01-10 00:00:00+00:00'],
dtype='datetime64[ns, UTC]', freq='C')
Schedule¶
schedule = nyse.schedule(start_date='2016-12-30', end_date='2017-01-10')
schedule
market_open | market_close | |
---|---|---|
2016-12-30 | 2016-12-30 14:30:00+00:00 | 2016-12-30 21:00:00+00:00 |
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 |
2017-01-05 | 2017-01-05 14:30:00+00:00 | 2017-01-05 21:00:00+00:00 |
2017-01-06 | 2017-01-06 14:30:00+00:00 | 2017-01-06 21:00:00+00:00 |
2017-01-09 | 2017-01-09 14:30:00+00:00 | 2017-01-09 21:00:00+00:00 |
2017-01-10 | 2017-01-10 14:30:00+00:00 | 2017-01-10 21:00:00+00:00 |
# with early closes
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 |
Get early closes¶
nyse.early_closes(schedule=early)
market_open | market_close | |
---|---|---|
2012-07-03 | 2012-07-03 13:30:00+00:00 | 2012-07-03 17:00:00+00:00 |
Open at time¶
Test to see if a given timestamp is during market open hours
nyse.open_at_time(early, pd.Timestamp('2012-07-03 12:00', tz='America/New_York'))
True
nyse.open_at_time(early, pd.Timestamp('2012-07-03 16:00', tz='America/New_York'))
False
Date Range¶
This function will take a schedule DataFrame and return a DatetimeIndex with all timestamps at the frequency given for all of the exchange open dates and times.
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)
Custom open and close times¶
If you want to override the market open and close times enter these at construction
cal = mcal.get_calendar('NYSE', open_time=time(10, 0), close_time=time(14, 30))
print('open, close: %s, %s' % (cal.open_time, cal.close_time))
open, close: 10:00:00, 14:30:00
Merge schedules¶
# NYSE Calendar
nyse = mcal.get_calendar('NYSE')
schedule_nyse = nyse.schedule('2015-12-20', '2016-01-06')
schedule_nyse
market_open | market_close | |
---|---|---|
2015-12-21 | 2015-12-21 14:30:00+00:00 | 2015-12-21 21:00:00+00:00 |
2015-12-22 | 2015-12-22 14:30:00+00:00 | 2015-12-22 21:00:00+00:00 |
2015-12-23 | 2015-12-23 14:30:00+00:00 | 2015-12-23 21:00:00+00:00 |
2015-12-24 | 2015-12-24 14:30:00+00:00 | 2015-12-24 18:00:00+00:00 |
2015-12-28 | 2015-12-28 14:30:00+00:00 | 2015-12-28 21:00:00+00:00 |
2015-12-29 | 2015-12-29 14:30:00+00:00 | 2015-12-29 21:00:00+00:00 |
2015-12-30 | 2015-12-30 14:30:00+00:00 | 2015-12-30 21:00:00+00:00 |
2015-12-31 | 2015-12-31 14:30:00+00:00 | 2015-12-31 21:00:00+00:00 |
2016-01-04 | 2016-01-04 14:30:00+00:00 | 2016-01-04 21:00:00+00:00 |
2016-01-05 | 2016-01-05 14:30:00+00:00 | 2016-01-05 21:00:00+00:00 |
2016-01-06 | 2016-01-06 14:30:00+00:00 | 2016-01-06 21:00:00+00:00 |
# LSE Calendar
lse = mcal.get_calendar('LSE')
schedule_lse = lse.schedule('2015-12-20', '2016-01-06')
schedule_lse
market_open | market_close | |
---|---|---|
2015-12-21 | 2015-12-21 08:00:00+00:00 | 2015-12-21 16:30:00+00:00 |
2015-12-22 | 2015-12-22 08:00:00+00:00 | 2015-12-22 16:30:00+00:00 |
2015-12-23 | 2015-12-23 08:00:00+00:00 | 2015-12-23 16:30:00+00:00 |
2015-12-24 | 2015-12-24 08:00:00+00:00 | 2015-12-24 12:30:00+00:00 |
2015-12-29 | 2015-12-29 08:00:00+00:00 | 2015-12-29 16:30:00+00:00 |
2015-12-30 | 2015-12-30 08:00:00+00:00 | 2015-12-30 16:30:00+00:00 |
2015-12-31 | 2015-12-31 08:00:00+00:00 | 2015-12-31 12:30:00+00:00 |
2016-01-04 | 2016-01-04 08:00:00+00:00 | 2016-01-04 16:30:00+00:00 |
2016-01-05 | 2016-01-05 08:00:00+00:00 | 2016-01-05 16:30:00+00:00 |
2016-01-06 | 2016-01-06 08:00:00+00:00 | 2016-01-06 16:30:00+00:00 |
Inner merge¶
This will find the dates where both the NYSE and LSE are open. Notice that Dec 28th is open for NYSE but not LSE. Also note that some days have a close prior to the open. This function does not currently check for that.
mcal.merge_schedules(schedules=[schedule_nyse, schedule_lse], how='inner')
market_open | market_close | |
---|---|---|
2015-12-21 | 2015-12-21 14:30:00+00:00 | 2015-12-21 16:30:00+00:00 |
2015-12-22 | 2015-12-22 14:30:00+00:00 | 2015-12-22 16:30:00+00:00 |
2015-12-23 | 2015-12-23 14:30:00+00:00 | 2015-12-23 16:30:00+00:00 |
2015-12-24 | 2015-12-24 14:30:00+00:00 | 2015-12-24 12:30:00+00:00 |
2015-12-29 | 2015-12-29 14:30:00+00:00 | 2015-12-29 16:30:00+00:00 |
2015-12-30 | 2015-12-30 14:30:00+00:00 | 2015-12-30 16:30:00+00:00 |
2015-12-31 | 2015-12-31 14:30:00+00:00 | 2015-12-31 12:30:00+00:00 |
2016-01-04 | 2016-01-04 14:30:00+00:00 | 2016-01-04 16:30:00+00:00 |
2016-01-05 | 2016-01-05 14:30:00+00:00 | 2016-01-05 16:30:00+00:00 |
2016-01-06 | 2016-01-06 14:30:00+00:00 | 2016-01-06 16:30:00+00:00 |
Outer merge¶
This will return the dates and times where either the NYSE or the LSE are open
mcal.merge_schedules(schedules=[schedule_nyse, schedule_lse], how='outer')
market_open | market_close | |
---|---|---|
2015-12-21 | 2015-12-21 08:00:00+00:00 | 2015-12-21 21:00:00+00:00 |
2015-12-22 | 2015-12-22 08:00:00+00:00 | 2015-12-22 21:00:00+00:00 |
2015-12-23 | 2015-12-23 08:00:00+00:00 | 2015-12-23 21:00:00+00:00 |
2015-12-24 | 2015-12-24 08:00:00+00:00 | 2015-12-24 18:00:00+00:00 |
2015-12-28 | 2015-12-28 14:30:00+00:00 | 2015-12-28 21:00:00+00:00 |
2015-12-29 | 2015-12-29 08:00:00+00:00 | 2015-12-29 21:00:00+00:00 |
2015-12-30 | 2015-12-30 08:00:00+00:00 | 2015-12-30 21:00:00+00:00 |
2015-12-31 | 2015-12-31 08:00:00+00:00 | 2015-12-31 21:00:00+00:00 |
2016-01-04 | 2016-01-04 08:00:00+00:00 | 2016-01-04 21:00:00+00:00 |
2016-01-05 | 2016-01-05 08:00:00+00:00 | 2016-01-05 21:00:00+00:00 |
2016-01-06 | 2016-01-06 08:00:00+00:00 | 2016-01-06 21:00:00+00:00 |
Use holidays in numpy¶
This will use your exchange calendar in numpy to add business days
import numpy as np
cme = mcal.get_calendar("CME")
np.busday_offset(dates="2020-05-22", holidays=cme.holidays().holidays, offsets=1)
numpy.datetime64('2020-05-25')
Trading Breaks¶
Some markets have breaks in the day, like the CME Equity Futures markets which are closed from 4:15 - 4:35 (NY) daily. These calendars will have additional columns in the schedule() DataFrame
cme = mcal.get_calendar('CME_Equity')
schedule = cme.schedule('2020-01-01', '2020-01-04')
schedule
market_open | market_close | break_start | break_end | |
---|---|---|---|---|
2020-01-02 | 2020-01-01 23:00:00+00:00 | 2020-01-02 22:00:00+00:00 | 2020-01-02 21:15:00+00:00 | 2020-01-02 21:30:00+00:00 |
2020-01-03 | 2020-01-02 23:00:00+00:00 | 2020-01-03 22:00:00+00:00 | 2020-01-03 21:15:00+00:00 | 2020-01-03 21:30:00+00:00 |
The date_range() properly accounts for the breaks
mcal.date_range(schedule, '5min')
DatetimeIndex(['2020-01-01 23:05:00+00:00', '2020-01-01 23:10:00+00:00',
'2020-01-01 23:15:00+00:00', '2020-01-01 23:20:00+00:00',
'2020-01-01 23:25:00+00:00', '2020-01-01 23:30:00+00:00',
'2020-01-01 23:35:00+00:00', '2020-01-01 23:40:00+00:00',
'2020-01-01 23:45:00+00:00', '2020-01-01 23:50:00+00:00',
...
'2020-01-03 21:00:00+00:00', '2020-01-03 21:05:00+00:00',
'2020-01-03 21:10:00+00:00', '2020-01-03 21:15:00+00:00',
'2020-01-03 21:35:00+00:00', '2020-01-03 21:40:00+00:00',
'2020-01-03 21:45:00+00:00', '2020-01-03 21:50:00+00:00',
'2020-01-03 21:55:00+00:00', '2020-01-03 22:00:00+00:00'],
dtype='datetime64[ns, UTC]', length=546, freq=None)