diff --git a/tests/pipeline/base.py b/tests/pipeline/base.py index 47f99384..4e83958e 100644 --- a/tests/pipeline/base.py +++ b/tests/pipeline/base.py @@ -21,7 +21,7 @@ from zipline.testing import ( from zipline.utils.functional import dzip_exact from zipline.utils.pandas_utils import explode -from zipline.utils.tradingcalendar import trading_day +from zipline.utils.calendars import default_nyse_schedule def with_defaults(**default_funcs): @@ -55,7 +55,8 @@ class BasePipelineTestCase(TestCase): @classmethod def setUpClass(cls): - cls.__calendar = date_range('2014', '2015', freq=trading_day) + cls.__calendar = date_range('2014', '2015', + freq=default_nyse_schedule.day) cls.__assets = assets = Int64Index(arange(1, 20)) cls.__tmp_finder_ctx = tmp_asset_finder( equities=make_simple_equity_info( diff --git a/tests/test_algorithm.py b/tests/test_algorithm.py index 12bb2da6..5f529cd0 100644 --- a/tests/test_algorithm.py +++ b/tests/test_algorithm.py @@ -3211,7 +3211,7 @@ class TestOrderCancelation(WithDataPortal, sim_params=SimulationParameters( period_start=self.sim_params.period_start, period_end=self.sim_params.period_end, - trading_schedule=self.env, + trading_schedule=default_nyse_schedule, data_frequency=data_frequency, emission_rate='minute' if minute_emission else 'daily' ) @@ -3401,6 +3401,7 @@ class TestEquityAutoClose(WithTmpDir, ZiplineTestCase): @classmethod def init_class_fixtures(cls): super(TestEquityAutoClose, cls).init_class_fixtures() + trading_days = default_nyse_schedule.all_execution_days start_date = pd.Timestamp('2015-01-05', tz='UTC') start_date_loc = trading_days.get_loc(start_date) test_duration = 7 @@ -3416,7 +3417,7 @@ class TestEquityAutoClose(WithTmpDir, ZiplineTestCase): num_assets=3, start_date=self.test_days[0], first_end=self.first_asset_expiration, - frequency=trading_day, + frequency=default_nyse_schedule.day, periods_between_ends=2, auto_close_delta=auto_close_delta, ) @@ -3578,7 +3579,7 @@ class TestEquityAutoClose(WithTmpDir, ZiplineTestCase): Make sure that after an equity gets delisted, our portfolio holds the correct number of equities and correct amount of cash. """ - auto_close_delta = trading_day * auto_close_lag + auto_close_delta = default_nyse_schedule.day * auto_close_lag resources = self.make_data(auto_close_delta, 'daily', capital_base) assets = resources.assets @@ -3738,7 +3739,7 @@ class TestEquityAutoClose(WithTmpDir, ZiplineTestCase): canceled. Unless an equity is auto closed, any open orders for that equity will persist indefinitely. """ - auto_close_delta = trading_day + auto_close_delta = default_nyse_schedule.day resources = self.make_data(auto_close_delta, 'daily') env = resources.env assets = resources.assets @@ -3810,7 +3811,7 @@ class TestEquityAutoClose(WithTmpDir, ZiplineTestCase): ) def test_minutely_delisted_equities(self): - resources = self.make_data(trading_day, 'minute') + resources = self.make_data(default_nyse_schedule.day, 'minute') env = resources.env assets = resources.assets diff --git a/tests/test_api_shim.py b/tests/test_api_shim.py index 5ff1c85c..97c4b878 100644 --- a/tests/test_api_shim.py +++ b/tests/test_api_shim.py @@ -19,6 +19,7 @@ from zipline.testing.fixtures import ( ZiplineTestCase, ) from zipline.zipline_warnings import ZiplineDeprecationWarning +from zipline.utils.calendars import default_nyse_schedule simple_algo = """ from zipline.api import sid, order @@ -124,7 +125,7 @@ class TestAPIShim(WithDataPortal, WithSimParams, ZiplineTestCase): def make_minute_bar_data(cls): for sid in cls.sids: yield sid, create_minute_df_for_asset( - cls.env, + default_nyse_schedule, cls.SIM_PARAMS_START, cls.SIM_PARAMS_END, ) @@ -133,7 +134,7 @@ class TestAPIShim(WithDataPortal, WithSimParams, ZiplineTestCase): def make_daily_bar_data(cls): for sid in cls.sids: yield sid, create_daily_df_for_asset( - cls.env, + default_nyse_schedule, cls.SIM_PARAMS_START, cls.SIM_PARAMS_END, ) @@ -179,10 +180,10 @@ class TestAPIShim(WithDataPortal, WithSimParams, ZiplineTestCase): similar) and the new data API(data.current(sid(N), field) and similar) hit the same code paths on the DataPortal. """ - test_start_minute = self.env.market_minutes_for_day( + test_start_minute = default_nyse_schedule.execution_minutes_for_day( self.sim_params.trading_days[0] )[1] - test_end_minute = self.env.market_minutes_for_day( + test_end_minute = default_nyse_schedule.execution_minutes_for_day( self.sim_params.trading_days[0] )[-1] bar_data = BarData( @@ -260,7 +261,7 @@ class TestAPIShim(WithDataPortal, WithSimParams, ZiplineTestCase): period_start=test_start_minute, period_end=test_end_minute, data_frequency="minute", - env=self.env + trading_schedule=default_nyse_schedule, ) history_algorithm = self.create_algo( @@ -381,7 +382,7 @@ class TestAPIShim(WithDataPortal, WithSimParams, ZiplineTestCase): capital_base=self.sim_params.capital_base, data_frequency=self.sim_params.data_frequency, emission_rate=self.sim_params.emission_rate, - env=self.env, + trading_schedule=default_nyse_schedule, ) algo = self.create_algo(history_algo, @@ -424,7 +425,7 @@ class TestAPIShim(WithDataPortal, WithSimParams, ZiplineTestCase): period_start=self.sim_params.trading_days[8], period_end=self.sim_params.trading_days[-1], data_frequency="minute", - env=self.env + trading_schedule=default_nyse_schedule, ) algo = self.create_algo(simple_transforms_algo, diff --git a/tests/test_bar_data.py b/tests/test_bar_data.py index a97da758..f12dad1e 100644 --- a/tests/test_bar_data.py +++ b/tests/test_bar_data.py @@ -439,8 +439,8 @@ class TestMinuteBarData(WithBarDataChecks, def test_can_trade_at_midnight(self): # make sure that if we use `can_trade` at midnight, we don't pretend # we're in the previous day's last minute - the_day_after = self.env.next_trading_day( - self.bcolz_minute_bar_days[-1], + the_day_after = self.trading_schedule.next_execution_day( + self.bcolz_minute_bar_days[-1] ) bar_data = BarData(self.data_portal, lambda: the_day_after, "minute") diff --git a/tests/test_data_portal.py b/tests/test_data_portal.py index cad4b586..898cc708 100644 --- a/tests/test_data_portal.py +++ b/tests/test_data_portal.py @@ -16,6 +16,7 @@ from pandas.tslib import Timedelta from zipline.data.data_portal import DataPortal from zipline.testing.fixtures import WithTradingEnvironment, ZiplineTestCase +from zipline.utils.calendars import default_nyse_schedule import pandas as pd @@ -26,7 +27,8 @@ class TestDataPortal(WithTradingEnvironment, ZiplineTestCase): def init_instance_fixtures(self): super(TestDataPortal, self).init_instance_fixtures() - self.data_portal = DataPortal(self.env, first_trading_day=None) + self.data_portal = DataPortal(self.env, default_nyse_schedule, + first_trading_day=None) def test_bar_count_for_simple_transforms(self): # July 2015 @@ -40,7 +42,7 @@ class TestDataPortal(WithTradingEnvironment, ZiplineTestCase): # half an hour into july 9, getting a 4-"day" window should get us # all the minutes of 7/6, 7/7, 7/8, and 31 minutes of 7/9 - july_9_dt = self.env.get_open_and_close( + july_9_dt = default_nyse_schedule.start_and_end( pd.Timestamp("2015-07-09") )[0] + Timedelta("30 minutes") @@ -63,7 +65,7 @@ class TestDataPortal(WithTradingEnvironment, ZiplineTestCase): # half an hour into nov 30, getting a 4-"day" window should get us # all the minutes of 11/24, 11/25, 11/27 (half day!), and 31 minutes # of 11/30 - nov_30_dt = self.env.get_open_and_close( + nov_30_dt = default_nyse_schedule.start_and_end( pd.Timestamp("2015-11-30") )[0] + Timedelta("30 minutes") diff --git a/tests/test_finance.py b/tests/test_finance.py index 7df84b48..ea5ac0bb 100644 --- a/tests/test_finance.py +++ b/tests/test_finance.py @@ -280,7 +280,8 @@ class FinanceTestCase(WithLogger, else: alternator = 1 - tracker = PerformanceTracker(sim_params, self.env) + tracker = PerformanceTracker(sim_params, default_nyse_schedule, + self.env) # replicate what tradesim does by going through every minute or day # of the simulation and processing open orders each time @@ -558,18 +559,3 @@ class TradingEnvironmentTestCase(WithLogger, self.assertTrue(all(today == minutes[:31])) self.assertTrue(all(friday == minutes[31:421])) self.assertTrue(all(thursday == minutes[421:])) - - def test_min_date(self): - min_date = pd.Timestamp('2016-03-04', tz='UTC') - env = TradingEnvironment(min_date=min_date) - - self.assertGreaterEqual(env.first_trading_day, min_date) - self.assertGreaterEqual(env.treasury_curves.index[0], - min_date) - - def test_max_date(self): - max_date = pd.Timestamp('2008-08-01', tz='UTC') - env = TradingEnvironment(max_date=max_date) - - self.assertLessEqual(env.treasury_curves.index[-1], - max_date) diff --git a/tests/test_history.py b/tests/test_history.py index c3ea73da..b28a39a5 100644 --- a/tests/test_history.py +++ b/tests/test_history.py @@ -1136,6 +1136,7 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase): def test_history_window_before_first_trading_day(self): # trading_start is 2/3/2014 # get a history window that starts before that, and ends after that + self.data_portal._first_trading_day = self.TRADING_START_DT first_day_minutes = default_nyse_schedule.execution_minutes_for_day( self.TRADING_START_DT ) @@ -1670,8 +1671,8 @@ class DailyEquityHistoryTestCase(WithHistory, ZiplineTestCase): )[self.ASSET1] # Use a minute to force minute mode. - first_minute = default_nyse_schedule.open_and_closes.market_open[ - self.TRADING_START_DT] + first_minute = \ + default_nyse_schedule.schedule.market_open[self.TRADING_START_DT] with self.assertRaisesRegexp(HistoryWindowStartsBeforeData, exp_msg): self.data_portal.get_history_window( diff --git a/tests/utils/test_events.py b/tests/utils/test_events.py index 2a2c03c0..c28dd44c 100644 --- a/tests/utils/test_events.py +++ b/tests/utils/test_events.py @@ -12,7 +12,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from collections import namedtuple import datetime from functools import partial from inspect import isabstract @@ -25,7 +24,6 @@ import pandas as pd from six import iteritems from six.moves import range, map -from zipline.finance.trading import TradingEnvironment from zipline.testing import subtest, parameter_space import zipline.utils.events from zipline.utils.calendars import get_calendar @@ -213,7 +211,7 @@ def minutes_for_days(ordered_days=False): # optimization in AfterOpen and BeforeClose, we rely on the fact that # the clock only ever moves forward in a simulation. For those cases, # we guarantee that the list of trading days we test is ordered. - ordered_day_list = random.sample(list(env.trading_days), 500) + ordered_day_list = random.sample(list(cal.all_trading_days), 500) ordered_day_list.sort() def day_picker(day): diff --git a/zipline/algorithm.py b/zipline/algorithm.py index e2132437..c9a15279 100644 --- a/zipline/algorithm.py +++ b/zipline/algorithm.py @@ -906,7 +906,8 @@ class TradingAlgorithm(object): url, pre_func, post_func, - self.trading_environment, + self.asset_finder, + self.trading_schedule.day, self.sim_params.period_start, self.sim_params.period_end, date_column, @@ -1945,7 +1946,9 @@ class TradingAlgorithm(object): # If we are in before_trading_start, we need to get the window # as of the previous market minute adjusted_dt = \ - self.data_portal.env.previous_market_minute(self.datetime) + self.data_portal.trading_schedule.previous_execution_minute( + self.datetime + ) window = self.data_portal.get_history_window( assets, diff --git a/zipline/data/data_portal.py b/zipline/data/data_portal.py index 0e9b478f..2c1578ea 100644 --- a/zipline/data/data_portal.py +++ b/zipline/data/data_portal.py @@ -1018,12 +1018,13 @@ class DataPortal(object): tds = self.trading_schedule.all_execution_days end_loc = tds.get_loc(end_date) start_loc = end_loc - bar_count + 1 - start_dt = tds[start_loc] - if start_dt < self._first_trading_day: + if start_loc < self._first_trading_day_loc: raise HistoryWindowStartsBeforeData( first_trading_day=self._first_trading_day.date(), bar_count=bar_count, - suggested_start_day=tds[bar_count].date(), + suggested_start_day=tds[ + self._first_trading_day_loc + bar_count + ].date(), ) return tds[start_loc:end_loc + 1] @@ -1175,12 +1176,14 @@ class DataPortal(object): mm = self.trading_schedule.all_execution_minutes end_loc = mm.get_loc(end_dt) start_loc = end_loc - bar_count + 1 - if start_loc < 0: - suggested_start_day = \ - (mm[bar_count] + self.trading_schedule.day).date() + if start_loc < self._first_trading_minute_loc: + suggested_start_day = ( + mm[ + self._first_trading_minute_loc + bar_count + ] + self.trading_schedule.day + ).date() raise HistoryWindowStartsBeforeData( - first_trading_day=\ - self.trading_schedule.first_execution_day.date(), + first_trading_day=self._first_trading_day.date(), bar_count=bar_count, suggested_start_day=suggested_start_day, ) @@ -1704,11 +1707,13 @@ class DataPortal(object): previous_day, ) - minutes_count = \ - sum(210 if day in self.env.early_closes else 390 for day in days) + minutes_count = sum( + 210 if day in self.trading_schedule.early_ends + else 390 for day in days + ) # add the minutes for today - today_open = self.env.get_open_and_close(ending_minute)[0] + today_open = self.trading_schedule.start_and_end(ending_minute)[0] minutes_count += \ ((ending_minute - today_open).total_seconds() // 60) + 1 diff --git a/zipline/finance/performance/position_tracker.py b/zipline/finance/performance/position_tracker.py index 1893e489..7a1a2ffa 100644 --- a/zipline/finance/performance/position_tracker.py +++ b/zipline/finance/performance/position_tracker.py @@ -384,7 +384,7 @@ class PositionTracker(object): last_sale_price = data_portal.get_adjusted_value( asset, 'price', - data_portal.env.previous_market_minute(dt), + data_portal.trading_schedule.previous_execution_minute(dt), dt, self.data_frequency ) diff --git a/zipline/finance/trading.py b/zipline/finance/trading.py index ed234982..31e1c8ae 100644 --- a/zipline/finance/trading.py +++ b/zipline/finance/trading.py @@ -78,8 +78,6 @@ class TradingEnvironment(object): load=None, bm_symbol='^GSPC', exchange_tz="US/Eastern", - min_date=None, - max_date=None, trading_schedule=default_nyse_schedule, asset_db_path=':memory:' ): @@ -94,13 +92,13 @@ class TradingEnvironment(object): self.bm_symbol, ) - if max_date: - tr_c = self.treasury_curves - # Mask the treasury curves down to the current date. - # In the case of live trading, the last date in the treasury - # curves would be the day before the date considered to be - # 'today'. - self.treasury_curves = tr_c[tr_c.index <= max_date] + #if max_date: + # tr_c = self.treasury_curves + # # Mask the treasury curves down to the current date. + # # In the case of live trading, the last date in the treasury + # # curves would be the day before the date considered to be + # # 'today'. + # self.treasury_curves = tr_c[tr_c.index <= max_date] self.exchange_tz = exchange_tz diff --git a/zipline/sources/requests_csv.py b/zipline/sources/requests_csv.py index a505c271..ac35f49e 100644 --- a/zipline/sources/requests_csv.py +++ b/zipline/sources/requests_csv.py @@ -26,14 +26,14 @@ from zipline.assets import Equity logger = Logger('Requests Source Logger') -def roll_dts_to_midnight(dts, env): +def roll_dts_to_midnight(dts, trading_day): if len(dts) == 0: return dts return pd.DatetimeIndex( (dts.tz_convert('US/Eastern') - pd.Timedelta(hours=16)).date, tz='UTC', - ) + env.trading_day + ) + trading_day class FetcherEvent(Event): @@ -144,7 +144,8 @@ class PandasCSV(with_metaclass(ABCMeta, object)): def __init__(self, pre_func, post_func, - env, + asset_finder, + trading_day, start_date, end_date, date_column, @@ -175,8 +176,8 @@ class PandasCSV(with_metaclass(ABCMeta, object)): self.symbol = symbol - self.env = env - self.finder = env.asset_finder + self.finder = asset_finder + self.trading_day = trading_day self.pre_func = pre_func self.post_func = post_func @@ -194,7 +195,7 @@ class PandasCSV(with_metaclass(ABCMeta, object)): @staticmethod def parse_date_str_series(format_str, tz, date_str_series, data_frequency, - env): + trading_day): """ Efficient parsing for a 1d Pandas/numpy object containing string representations of dates. @@ -233,7 +234,7 @@ class PandasCSV(with_metaclass(ABCMeta, object)): ).tz_localize(tz_str).tz_convert('UTC') if data_frequency == 'daily': - parsed = roll_dts_to_midnight(parsed, env) + parsed = roll_dts_to_midnight(parsed, trading_day) return parsed def mask_pandas_args(self, kwargs): @@ -290,7 +291,7 @@ class PandasCSV(with_metaclass(ABCMeta, object)): self.timezone, df[self.date_column], self.data_frequency, - self.env + self.trading_day, ).values # ignore rows whose dates we couldn't parse @@ -456,7 +457,8 @@ class PandasRequestsCSV(PandasCSV): url, pre_func, post_func, - env, + asset_finder, + trading_day, start_date, end_date, date_column, @@ -488,7 +490,8 @@ class PandasRequestsCSV(PandasCSV): super(PandasRequestsCSV, self).__init__( pre_func, post_func, - env, + asset_finder, + trading_day, start_date, end_date, date_column, diff --git a/zipline/testing/core.py b/zipline/testing/core.py index 4b462412..1a1ee04e 100644 --- a/zipline/testing/core.py +++ b/zipline/testing/core.py @@ -702,9 +702,11 @@ class FakeDataPortal(DataPortal): def get_history_window(self, assets, end_dt, bar_count, frequency, field, ffill=True): if frequency == "1d": - end_idx = self.env.trading_days.searchsorted(end_dt) - days = \ - self.env.trading_days[(end_idx - bar_count + 1):(end_idx + 1)] + end_idx = \ + self.trading_schedule.all_execution_days.searchsorted(end_dt) + days = self.trading_schedule.all_execution_days[ + (end_idx - bar_count + 1):(end_idx + 1) + ] df = pd.DataFrame( np.full((bar_count, len(assets)), 100), diff --git a/zipline/testing/fixtures.py b/zipline/testing/fixtures.py index eac58d26..b1ddcbb7 100644 --- a/zipline/testing/fixtures.py +++ b/zipline/testing/fixtures.py @@ -398,8 +398,6 @@ class WithTradingEnvironment(WithAssetFinder): -------- :class:`zipline.finance.trading.TradingEnvironment` """ - TRADING_ENV_MIN_DATE = None - TRADING_ENV_MAX_DATE = None TRADING_ENV_TRADING_SCHEDULE = default_nyse_schedule @classmethod @@ -411,8 +409,6 @@ class WithTradingEnvironment(WithAssetFinder): return TradingEnvironment( load=cls.make_load_function(), asset_db_path=cls.asset_finder.engine, - min_date=cls.TRADING_ENV_MIN_DATE, - max_date=cls.TRADING_ENV_MAX_DATE, trading_schedule=cls.TRADING_ENV_TRADING_SCHEDULE, ) diff --git a/zipline/utils/calendars/trading_schedule.py b/zipline/utils/calendars/trading_schedule.py index f0964107..d82e691f 100644 --- a/zipline/utils/calendars/trading_schedule.py +++ b/zipline/utils/calendars/trading_schedule.py @@ -280,6 +280,14 @@ class TradingSchedule(object): """ raise NotImplementedError() + @abstractproperty + def early_ends(self): + """ + Returns a DatetimeIndex containing the session dates on-which there is + an early end to trading. + """ + raise NotImplementedError() + class ExchangeTradingSchedule(TradingSchedule): """ @@ -355,6 +363,10 @@ class ExchangeTradingSchedule(TradingSchedule): count=count, step=step) + @property + def early_ends(self): + return self._exchange_calendar.early_closes + class NYSETradingSchedule(ExchangeTradingSchedule): """ diff --git a/zipline/utils/events.py b/zipline/utils/events.py index 444dd1dd..80fad7c0 100644 --- a/zipline/utils/events.py +++ b/zipline/utils/events.py @@ -348,7 +348,7 @@ class AfterOpen(StatelessRule): def calculate_dates(self, dt): # given a dt, find that day's open and period end (open + offset) self._period_start, self._period_close = \ - _static_nyse_cal.get_open_and_close(dt) + _static_nyse_cal.open_and_close(dt) self._period_end = \ self._period_start + self.offset - self._one_minute @@ -392,7 +392,7 @@ class BeforeClose(StatelessRule): def calculate_dates(self, dt): # given a dt, find that day's close and period start (close - offset) - self._period_end = _static_nyse_cal.get_open_and_close(dt)[1] + self._period_end = _static_nyse_cal.open_and_close(dt)[1] self._period_start = \ self._period_end - self.offset self._period_close = self._period_end