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: