From a203f6963544170d218572343f1dab5e57d8a2cf Mon Sep 17 00:00:00 2001 From: Eddie Hebert Date: Fri, 7 Mar 2014 10:26:43 -0500 Subject: [PATCH] PERF: Remove alias_dt transform in favor of property on SIDData. Adding a copy of the Event's dt field as datetime via the `alias_dt` generator, so that the API was forgiving and allowed both datetime and dt on a SIDData object, was creating noticeable overhead, even on an noop algorithms. Instead of incurring the cost of copying the datetime value and assigning it to the Event object on every event that is passed through the system, add a property to SIDData which acts as an alias `datetime` to `dt`. Eventually support for `data['foo'].datetime` may be removed, and could be considered deprecated. --- tests/test_algorithm_gen.py | 2 +- zipline/algorithm.py | 4 +--- zipline/gens/composites.py | 9 --------- zipline/protocol.py | 15 +++++++++++++++ zipline/transforms/batch_transform.py | 5 ++--- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/test_algorithm_gen.py b/tests/test_algorithm_gen.py index 14a80691..55c3f33a 100644 --- a/tests/test_algorithm_gen.py +++ b/tests/test_algorithm_gen.py @@ -47,7 +47,7 @@ class RecordDateSlippage(slippage.FixedSlippage): self.latest_date = None def simulate(self, event, open_orders): - self.latest_date = event['datetime'] + self.latest_date = event.dt result = super(RecordDateSlippage, self).simulate(event, open_orders) return result diff --git a/zipline/algorithm.py b/zipline/algorithm.py index eeaedaab..f3b2ab37 100644 --- a/zipline/algorithm.py +++ b/zipline/algorithm.py @@ -51,7 +51,6 @@ from zipline.protocol import Event from zipline.gens.composites import ( date_sorted_sources, sequential_transforms, - alias_dt ) from zipline.gens.tradesimulation import AlgorithmSimulator @@ -263,10 +262,9 @@ class TradingAlgorithm(object): with_tnfms = sequential_transforms(date_sorted, *self.transforms) - with_alias_dt = alias_dt(with_tnfms) with_benchmarks = date_sorted_sources(benchmark_return_source, - with_alias_dt) + with_tnfms) # Group together events with the same dt field. This depends on the # events already being sorted. diff --git a/zipline/gens/composites.py b/zipline/gens/composites.py index 67c3bd66..390c684b 100644 --- a/zipline/gens/composites.py +++ b/zipline/gens/composites.py @@ -47,12 +47,3 @@ def sequential_transforms(stream_in, *transforms): stream_in) return stream_out - - -def alias_dt(stream_in): - """ - Alias the dt field to datetime on each message. - """ - for message in stream_in: - message['datetime'] = message['dt'] - yield message diff --git a/zipline/protocol.py b/zipline/protocol.py index 44825d17..91f82d3c 100644 --- a/zipline/protocol.py +++ b/zipline/protocol.py @@ -117,6 +117,21 @@ class SIDData(object): if initial_values: self.__dict__ = initial_values + @property + def datetime(self): + """ + Provides an alias from data['foo'].datetime -> data['foo'].dt + + `datetime` was previously provided by adding a seperate `datetime` + member of the SIDData object via a generator that wrapped the incoming + data feed and added the field to each equity event. + + This alias is intended to be temporary, to provide backwards + compatibility with existing algorithms, but should be considered + deprecated, and may be removed in the future. + """ + return self.dt + def __getitem__(self, name): return self.__dict__[name] diff --git a/zipline/transforms/batch_transform.py b/zipline/transforms/batch_transform.py index b7104f80..93d4b2d3 100644 --- a/zipline/transforms/batch_transform.py +++ b/zipline/transforms/batch_transform.py @@ -236,7 +236,7 @@ class BatchTransform(object): Point of entry. Process an event frame. """ # extract dates - dts = [event.datetime for event in itervalues(data._data)] + dts = [event.dt for event in itervalues(data._data)] # we have to provide the event with a dt. This is only for # checking if the event is outside the window or not so a # couple of seconds shouldn't matter. We don't add it to @@ -439,8 +439,7 @@ class BatchTransform(object): # with CUSTOM data events, there may be different fields # per sid. So the allowable keys are the union of all events. union = set.union(*sid_keys) - unwanted_fields = set(['portfolio', 'sid', 'dt', 'type', - 'datetime', 'source_id']) + unwanted_fields = set(['portfolio', 'sid', 'dt', 'type', 'source_id']) return union - unwanted_fields def _get_field_names(self, event):