From 3541115b4ee885469f0da57fffbd26ace6869bfe Mon Sep 17 00:00:00 2001 From: Jonathan Kamens Date: Tue, 6 Aug 2013 15:30:35 -0400 Subject: [PATCH] BUG: Trading calendar dates should always be midnight UTC For consistency, datetimes returned by the trading calendar should always show HHMMSS of midnight UTC. Not only is this useful for consistency, but it also allows us to check if a particular date() is in an array of these datetimes, because they will hash to the same thing. For example: early_closes = get_early_closes() ... later ... if current_bar_datetime.date() in early_closes: ... today closes early ... If if the datetimes returned by the trading calendar functions don't have 00:00:00 for HHMMSS, then the "in" check above will fail because the date and the datetimes in early_closes won't hash to the same thing. --- zipline/utils/tradingcalendar.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/zipline/utils/tradingcalendar.py b/zipline/utils/tradingcalendar.py index de74a6f2..f8a83744 100644 --- a/zipline/utils/tradingcalendar.py +++ b/zipline/utils/tradingcalendar.py @@ -27,9 +27,18 @@ end_dln.shift('US/Eastern').truncate('day').shift(pytz.utc.zone) end = end_dln.datetime - timedelta(days=1) +def canonicalize_datetime(dt): + # Strip out any HHMMSS or timezone info in the user's datetime, so that + # all the datetimes we return will be 00:00:00 UTC. + return datetime(dt.year, dt.month, dt.day, tzinfo=pytz.utc) + + def get_non_trading_days(start, end): non_trading_rules = [] + start = canonicalize_datetime(start) + end = canonicalize_datetime(end) + weekends = rrule.rrule( rrule.YEARLY, byweekday=(rrule.SA, rrule.SU), @@ -241,6 +250,9 @@ def get_non_trading_days(start, end): def get_trading_days(start, end): + start = canonicalize_datetime(start) + end = canonicalize_datetime(end) + business_days = pd.DatetimeIndex(start=start, end=end, freq=pd.datetools.BDay()) @@ -258,6 +270,10 @@ def get_early_closes(start, end): # and verified against http://www.nyse.com/pdfs/closings.pdf # These rules are valid starting in 1993 + + start = canonicalize_datetime(start) + end = canonicalize_datetime(end) + start = max(start, datetime(1993, 1, 1, tzinfo=pytz.utc)) end = max(end, datetime(1993, 1, 1, tzinfo=pytz.utc))