diff --git a/docs/source/whatsnew/1.0.2.txt b/docs/source/whatsnew/1.0.2.txt index 303f849e..076f5776 100644 --- a/docs/source/whatsnew/1.0.2.txt +++ b/docs/source/whatsnew/1.0.2.txt @@ -18,6 +18,9 @@ Enhancements - Allow correlations and regressions to be computed between two 2D factors by doing computations asset-wise (:issue:`1307`). +- Filters have been made window_safe by default. Now they can be passed in as + arguments to other Filters, Factors and Classifiers (:issue:`1338`). + Bug Fixes ~~~~~~~~~ diff --git a/tests/pipeline/test_filter.py b/tests/pipeline/test_filter.py index 0f8c4f3b..c403e909 100644 --- a/tests/pipeline/test_filter.py +++ b/tests/pipeline/test_filter.py @@ -11,6 +11,7 @@ from numpy import ( eye, float64, full_like, + full, inf, isfinite, nan, @@ -18,12 +19,14 @@ from numpy import ( ones, ones_like, putmask, + sum as np_sum ) from numpy.random import randn, seed as random_seed from zipline.errors import BadPercentileBounds from zipline.pipeline import Filter, Factor, TermGraph -from zipline.testing import check_arrays +from zipline.pipeline.factors import CustomFactor +from zipline.testing import check_arrays, parameter_space from zipline.utils.numpy_utils import float64_dtype from .base import BasePipelineTestCase, with_default_shape @@ -379,3 +382,36 @@ class FilterTestCase(BasePipelineTestCase): initial_workspace={self.f: data}, ) check_arrays(results['isfinite'], isfinite(data)) + + @parameter_space(factor_len=[2, 3, 4]) + def test_window_safe(self, factor_len): + # all true data set of (days, securities) + data = full(self.default_shape, True, dtype=bool) + + class InputFilter(Filter): + inputs = () + window_length = 0 + + class TestFactor(CustomFactor): + dtype = float64_dtype + inputs = (InputFilter(), ) + window_length = factor_len + + def compute(self, today, assets, out, filter_): + # sum for each column + out[:] = np_sum(filter_, axis=0) + + results = self.run_graph( + TermGraph({'windowsafe': TestFactor()}), + initial_workspace={InputFilter(): data}, + ) + + # number of days in default_shape + n = self.default_shape[0] + + # shape of output array + output_shape = ((n - factor_len + 1), self.default_shape[1]) + check_arrays( + results['windowsafe'], + full(output_shape, factor_len, dtype=float64) + ) diff --git a/zipline/pipeline/filters/filter.py b/zipline/pipeline/filters/filter.py index 4d261b32..502fd031 100644 --- a/zipline/pipeline/filters/filter.py +++ b/zipline/pipeline/filters/filter.py @@ -167,6 +167,10 @@ class Filter(RestrictedDTypeMixin, ComputableTerm): output of a Pipeline and for reducing memory consumption of Pipeline results. """ + # Filters are window-safe by default, since a yes/no decision means the + # same thing from all temporal perspectives. + window_safe = True + ALLOWED_DTYPES = (bool_dtype,) # Used by RestrictedDTypeMixin dtype = bool_dtype