mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-08 19:42:53 +08:00
BUG: Further corrections for days_at_time (#1334)
* BUG: Further corrections for days_at_time
- Revert to using DateOffset, as Timedelta doesn't handle offsetting by
one day over a tz change properly:
In [12]: pd.Timestamp('2004-04-05', tz='America/Chicago') + pd.Timedelta(days=-1)
Out[12]: Timestamp('2004-04-03 23:00:00-0600', tz='America/Chicago')
In [13]: pd.Timestamp('2004-04-05', tz='America/Chicago') + pd.DateOffset(days=-1)
Out[13]: Timestamp('2004-04-04 00:00:00-0600', tz='America/Chicago')
By creating a DateOffset using the `days` kwarg, the issue previously
fixed in bcc867b is addressed.
- To preempt any other pandas issues around day offsets, changes to
performing these with no timezone, then localizing to the local
timezone when shifting the time.
- Adds unit test for days_at_time
* STY: Remove unused import
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from datetime import time
|
||||
from os.path import (
|
||||
abspath,
|
||||
dirname,
|
||||
@@ -23,16 +24,19 @@ from collections import namedtuple
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from nose_parameterized import parameterized
|
||||
from pandas import (
|
||||
read_csv,
|
||||
Timestamp,
|
||||
)
|
||||
from pandas.util.testing import assert_index_equal
|
||||
from pytz import timezone
|
||||
from zipline.errors import (
|
||||
CalendarNameCollision,
|
||||
InvalidCalendarName,
|
||||
)
|
||||
from zipline.utils.calendars.exchange_calendar_nyse import NYSEExchangeCalendar
|
||||
from zipline.utils.calendars.trading_calendar import days_at_time
|
||||
from zipline.utils.calendars import(
|
||||
register_calendar,
|
||||
deregister_calendar,
|
||||
@@ -81,6 +85,36 @@ class CalendarRegistrationTestCase(TestCase):
|
||||
self.assertNotEqual(real_nyse, retr_cal)
|
||||
|
||||
|
||||
class DaysAtTimeTestCase(TestCase):
|
||||
@parameterized.expand([
|
||||
# NYSE standard day
|
||||
(
|
||||
'2016-07-19', 0, time(9, 31), timezone('US/Eastern'),
|
||||
'2016-07-19 9:31',
|
||||
),
|
||||
# CME standard day
|
||||
(
|
||||
'2016-07-19', -1, time(17, 1), timezone('America/Chicago'),
|
||||
'2016-07-18 17:01',
|
||||
),
|
||||
# CME day after DST start
|
||||
(
|
||||
'2004-04-05', -1, time(17, 1), timezone('America/Chicago'),
|
||||
'2004-04-04 17:01'
|
||||
),
|
||||
# ICE day after DST start
|
||||
(
|
||||
'1990-04-02', -1, time(19, 1), timezone('America/Chicago'),
|
||||
'1990-04-01 19:01',
|
||||
),
|
||||
])
|
||||
def test_days_at_time(self, day, day_offset, time_offset, tz, expected):
|
||||
days = pd.DatetimeIndex([pd.Timestamp(day, tz=tz)])
|
||||
result = days_at_time(days, time_offset, tz, day_offset)[0]
|
||||
expected = pd.Timestamp(expected, tz=tz).tz_convert('UTC')
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
|
||||
class ExchangeCalendarTestBase(object):
|
||||
|
||||
# Override in subclasses.
|
||||
|
||||
@@ -21,7 +21,7 @@ from pandas import (
|
||||
DataFrame,
|
||||
date_range,
|
||||
DatetimeIndex,
|
||||
Timedelta
|
||||
DateOffset
|
||||
)
|
||||
from pandas.tseries.offsets import CustomBusinessDay
|
||||
|
||||
@@ -677,11 +677,16 @@ def days_at_time(days, t, tz, day_offset=0):
|
||||
day_offset : int
|
||||
The number of days we want to offset @days by
|
||||
"""
|
||||
days = DatetimeIndex(days).tz_localize(None).tz_localize(tz)
|
||||
days_offset = days + Timedelta(days=day_offset)
|
||||
|
||||
# Offset days without tz to avoid timezone issues.
|
||||
days = DatetimeIndex(days).tz_localize(None)
|
||||
days_offset = days + DateOffset(days=day_offset)
|
||||
|
||||
# Shift all days to the target time in the local timezone, then
|
||||
# convert to UTC.
|
||||
return days_offset.shift(
|
||||
1, freq=Timedelta(hours=t.hour, minutes=t.minute, seconds=t.second)
|
||||
).tz_convert('UTC')
|
||||
1, freq=DateOffset(hour=t.hour, minute=t.minute, second=t.second)
|
||||
).tz_localize(tz).tz_convert('UTC')
|
||||
|
||||
|
||||
def holidays_at_time(calendar, start, end, time, tz):
|
||||
|
||||
Reference in New Issue
Block a user