From 38ff4cc9137a97d631ffe79782122379ad264788 Mon Sep 17 00:00:00 2001 From: John Ricklefs Date: Thu, 17 Sep 2015 16:54:22 -0400 Subject: [PATCH] BUG: Normalize dates in AssetDateBounds control checks Assumes that if a given asset's end_date is e.g. 9/17/2015 00:00:00 UTC that it means the asset is still tradeable on 9/17/2015 during the market day. --- tests/test_algorithm.py | 13 +++++++++++++ zipline/finance/controls.py | 35 +++++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/tests/test_algorithm.py b/tests/test_algorithm.py index 9dfcb592..5bf90b88 100644 --- a/tests/test_algorithm.py +++ b/tests/test_algorithm.py @@ -1573,6 +1573,19 @@ class TestTradingControls(TestCase): with self.assertRaises(TradingControlViolation): algo.run(df_source) + # Run the algorithm with a sid that starts on the first day and + # ends on the last day of the algorithm's parameters (*not* an error). + temp_env = TradingEnvironment() + df_source, _ = factory.create_test_df_source(self.sim_params, temp_env) + metadata = {0: {'start_date': '2006-01-03', + 'end_date': '2006-01-06'}} + algo = SetAssetDateBoundsAlgorithm( + equities_metadata=metadata, + sim_params=self.sim_params, + env=temp_env, + ) + algo.run(df_source) + class TestAccountControls(TestCase): diff --git a/zipline/finance/controls.py b/zipline/finance/controls.py index c2470a27..8986c7be 100644 --- a/zipline/finance/controls.py +++ b/zipline/finance/controls.py @@ -14,6 +14,8 @@ # limitations under the License. import abc +import pandas as pd + from six import with_metaclass from zipline.errors import ( @@ -55,14 +57,23 @@ class TradingControl(with_metaclass(abc.ABCMeta)): """ raise NotImplementedError - def fail(self, asset, amount, datetime): + def fail(self, asset, amount, datetime, metadata=None): """ Raise a TradingControlViolation with information about the failure. + + If dynamic information should be displayed as well, pass it in via + `metadata`. """ + constraint = repr(self) + if metadata: + constraint = "{constraint} (Metadata: {metadata})".format( + constraint=constraint, + metadata=metadata + ) raise TradingControlViolation(asset=asset, amount=amount, datetime=datetime, - constraint=repr(self)) + constraint=constraint) def __repr__(self): return "{name}({attrs})".format(name=self.__class__.__name__, @@ -286,12 +297,24 @@ class AssetDateBounds(TradingControl): Fail if the algo has passed this Asset's end_date, or before the Asset's start date. """ + normalized_algo_dt = pd.Timestamp(algo_datetime).normalize() + # Fail if the algo is before this Asset's start_date - if asset.start_date and (algo_datetime < asset.start_date): - self.fail(asset, amount, algo_datetime) + if asset.start_date: + normalized_start = pd.Timestamp(asset.start_date).normalize() + if normalized_algo_dt < normalized_start: + metadata = { + 'asset_start_date': normalized_start + } + self.fail(asset, amount, algo_datetime, metadata=metadata) # Fail if the algo has passed this Asset's end_date - if asset.end_date and (algo_datetime >= asset.end_date): - self.fail(asset, amount, algo_datetime) + if asset.end_date: + normalized_end = pd.Timestamp(asset.end_date).normalize() + if normalized_algo_dt > normalized_end: + metadata = { + 'asset_end_date': normalized_end + } + self.fail(asset, amount, algo_datetime, metadata=metadata) class AccountControl(with_metaclass(abc.ABCMeta)):