From 3d8bdeb42971d5507fee221ccac00295612ff076 Mon Sep 17 00:00:00 2001 From: Eddie Hebert Date: Tue, 9 Jul 2013 11:26:26 -0400 Subject: [PATCH] ENH: Enable minute bar data with TALib transform. Add a `bars` keyword arg, as is used with BatchTransform. Also, instead of overwriting the window_length kwarg with timeperiod, always use the lookback value from the created TALib function, as timeperiod will be an input into that value if it exists. Calculate `window_length` in minute mode so that there are enough days to cover the minutes in the timeperiod. --- tests/test_transforms.py | 21 +++++++++++++++++++++ zipline/transforms/ta.py | 18 ++++++++++++------ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/tests/test_transforms.py b/tests/test_transforms.py index b1a029ba..fb1cda7c 100644 --- a/tests/test_transforms.py +++ b/tests/test_transforms.py @@ -372,3 +372,24 @@ class TestTALIB(TestCase): talib_data['close'] = data['price'][0].values expected_result = talib_fn(talib_data, **t.call_kwargs)[-1] np.testing.assert_allclose(talib_result, expected_result) + + def test_talib_with_minute_data(self): + + ma_one_day_minutes = ta.MA(timeperiod=10, bars='minute') + + # Assert that the BatchTransform window length is enough to cover + # the amount of minutes in the timeperiod. + + # Here, 10 minutes only needs a window length of 1. + self.assertEquals(1, ma_one_day_minutes.window_length) + + # With minutes greater than the 390, i.e. one trading day, we should + # have a window_length of two days. + ma_two_day_minutes = ta.MA(timeperiod=490, bars='minute') + self.assertEquals(2, ma_two_day_minutes.window_length) + + # TODO: Ensure that the lookback into the datapanel is returning + # expected results. + # Requires supplying minute instead of day data to the unit test. + # When adding test data, should add more minute events than the + # timeperiod to ensure that lookback is behaving properly. diff --git a/zipline/transforms/ta.py b/zipline/transforms/ta.py index 09292680..c9adcd26 100644 --- a/zipline/transforms/ta.py +++ b/zipline/transforms/ta.py @@ -12,6 +12,7 @@ # 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. +import math import numpy as np import talib @@ -86,6 +87,7 @@ def make_transform(talib_fn, name): low='low', volume='volume', refresh_period=0, + bars='daily', **kwargs): key_map = {'high': high, @@ -94,11 +96,6 @@ def make_transform(talib_fn, name): 'volume': volume, 'close': close} - # Rename timeperiod to window_length to conform with - # TALib interface. - if 'timeperiod' in kwargs: - kwargs['window_length'] = kwargs['timeperiod'] - self.call_kwargs = kwargs # Make deepcopy of talib abstract function. @@ -119,6 +116,15 @@ def make_transform(talib_fn, name): # get the lookback self.lookback = self.talib_fn.lookback + self.bars = bars + if bars == 'daily': + lookback = self.lookback + 1 + elif bars == 'minute': + lookback = int(math.ceil(self.lookback / (6.5 * 60))) + + # Ensure that window_length is at least 1 day's worth of data. + window_length = max(lookback, 1) + def zipline_wrapper(data): # get required TA-Lib input names if 'price' in self.talib_fn.input_names: @@ -157,7 +163,7 @@ def make_transform(talib_fn, name): super(TALibTransform, self).__init__( func=zipline_wrapper, refresh_period=refresh_period, - window_length=max(1, self.lookback + 1)) + window_length=window_length) def __repr__(self): return 'Zipline BatchTransform: {0}'.format(