From 5f81acea059ac5c6ede7fe04304d3f84f63d5a99 Mon Sep 17 00:00:00 2001 From: Eddie Hebert Date: Wed, 25 Nov 2015 10:16:30 -0500 Subject: [PATCH] ENH: Return -1 for missing spot prices. Return -1 when there is a zero value for a spot price. Intended for use by the incoming data portal changes. When the data portal will see a -1 value, the portal will seek back a trading day until a non-negative value is returned. --- tests/data/test_us_equity_pricing.py | 17 ++++++++++++ zipline/data/us_equity_pricing.py | 39 ++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/tests/data/test_us_equity_pricing.py b/tests/data/test_us_equity_pricing.py index 35e329f4..e68cc2ea 100644 --- a/tests/data/test_us_equity_pricing.py +++ b/tests/data/test_us_equity_pricing.py @@ -306,3 +306,20 @@ class BcolzDailyBarTestCase(TestCase): # after with self.assertRaises(NoDataOnDate): reader.spot_price(4, Timestamp('2015-06-16', tz='UTC'), 'close') + + def test_unadjusted_spot_price_empty_value(self): + table = self.writer.write(self.dest, self.trading_days, self.assets) + reader = BcolzDailyBarReader(table) + + # A sid, day and corresponding index into which to overwrite a zero. + zero_sid = 1 + zero_day = Timestamp('2015-06-02', tz='UTC') + zero_ix = reader.sid_day_index(zero_sid, zero_day) + + # Write a zero into the synthetic pricing data at the day and sid, + # so that a read should now return -1. + # This a little hacky, in lieu of changing the synthetic data set. + reader._spot_col('close')[zero_ix] = 0 + + close = reader.spot_price(zero_sid, zero_day, 'close') + self.assertEqual(-1, close) diff --git a/zipline/data/us_equity_pricing.py b/zipline/data/us_equity_pricing.py index 121e56d5..236dae5b 100644 --- a/zipline/data/us_equity_pricing.py +++ b/zipline/data/us_equity_pricing.py @@ -469,23 +469,21 @@ class BcolzDailyBarReader(object): col = self._spot_cols[colname] = self._table[colname][:] return col - def spot_price(self, sid, day, colname): + def sid_day_index(self, sid, day): """ Parameters ---------- sid : int The asset identifier. - day : datetime64 + day : datetime64-like Midnight of the day for which data is requested. - colname : string - The price field. e.g. ('open', 'high', 'low', 'close', 'volume') Returns ------- - float - The spot price for colname of the given sid on the given day. - Raises a NoDataOnDate exception if there is no data available - for the given day and sid. + int + Index into the data tape for the given sid and day. + Raises a NoDataOnDate exception if the given day and sid is before + or after the date range of the equity. """ day_loc = self._calendar.get_loc(day) offset = day_loc - self._calendar_offsets[sid] @@ -498,7 +496,32 @@ class BcolzDailyBarReader(object): raise NoDataOnDate( "No data on or after day={0} for sid={1}".format( day, sid)) + return ix + + def spot_price(self, sid, day, colname): + """ + Parameters + ---------- + sid : int + The asset identifier. + day : datetime64-like + Midnight of the day for which data is requested. + colname : string + The price field. e.g. ('open', 'high', 'low', 'close', 'volume') + + Returns + ------- + float + The spot price for colname of the given sid on the given day. + Raises a NoDataOnDate exception if the given day and sid is before + or after the date range of the equity. + Returns -1 if the day is within the date range, but the price is + 0. + """ + ix = self.sid_day_index(sid, day) price = self._spot_col(colname)[ix] + if price == 0: + return -1 if colname != 'volume': return price * 0.001 else: