Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion docs/source/whatsnew/skeleton.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,18 @@ None
Bug Fixes
~~~~~~~~~

None
- Fix ``convert_cols`` in bcolz minute bar writer to use ``|=`` instead of
``&=`` for the exclude mask, so rows with uint32 overflow values are actually
filtered out. (:issue:`314`)
- Fix infinite loop in ``DataPortal._get_daily_spot_value`` when searching
backwards for a non-NaN close price by adding a bounds check against
``_first_trading_day``. (:issue:`314`)
- Fix infinite loop in ``BcolzDailyBarReader.get_last_traded_dt`` when
``NoDataAfterDate`` is raised and no previous session exists. (:issue:`314`)
- Fix ``DataPortal.get_adjustments`` to apply ``tz_localize`` to merger
adjustment dates, consistent with splits and dividends. (:issue:`314`)
- Add path traversal validation to ``tar.extractall`` in the Quandl bundle
loader (CVE-2007-4559). (:issue:`314`)

Performance
~~~~~~~~~~~
Expand Down
2 changes: 2 additions & 0 deletions src/zipline/data/bcolz_daily_bars.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,8 @@ def get_last_traded_dt(self, asset, day):
prev_day_ix = self.sessions.get_loc(search_day) - 1
if prev_day_ix > -1:
search_day = self.sessions[prev_day_ix]
else:
return pd.NaT
continue
except NoDataOnDate:
return pd.NaT
Expand Down
2 changes: 1 addition & 1 deletion src/zipline/data/bcolz_minute_bars.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def convert_cols(cols, scale_factor, sid, invalid_data_behavior):

# We want to exclude all rows that have an unsafe value in
# this column.
exclude_mask &= scaled_col >= np.iinfo(np.uint32).max
exclude_mask |= scaled_col >= np.iinfo(np.uint32).max

# Convert all cols to uint32.
opens = scaled_opens.astype(np.uint32)
Expand Down
10 changes: 10 additions & 0 deletions src/zipline/data/bundles/quandl.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

from io import BytesIO
import os
import tarfile
from zipfile import ZipFile

Expand Down Expand Up @@ -310,6 +311,15 @@ def quantopian_quandl_bundle(
with tarfile.open("r", fileobj=data) as tar:
if show_progress:
log.info("Writing data to %s.", output_dir)
for member in tar.getmembers():
member_path = os.path.join(output_dir, member.name)
if not os.path.realpath(member_path).startswith(
os.path.realpath(output_dir)
):
raise ValueError(
f"Tar member {member.name!r} would extract outside "
f"target directory"
)
tar.extractall(output_dir)


Expand Down
6 changes: 4 additions & 2 deletions src/zipline/data/data_portal.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,9 +595,9 @@ def split_adj_factor(x):
asset, self._mergers_dict, "MERGERS"
)
for adj_dt, adj in merger_adjustments:
if dt < adj_dt <= perspective_dt:
if dt < adj_dt.tz_localize(dt.tzinfo) <= perspective_dt:
adjustments_for_asset.append(adj)
elif adj_dt > perspective_dt:
elif adj_dt.tz_localize(dt.tzinfo) > perspective_dt:
break

dividend_adjustments = self._get_adjustment_list(
Expand Down Expand Up @@ -738,6 +738,8 @@ def _get_daily_spot_value(self, asset, column, dt):
)
else:
found_dt -= self.trading_calendar.day
if found_dt < self._first_trading_day:
return np.nan
except NoDataOnDate:
return np.nan

Expand Down