ENH: Add continuous future current contract.

Add the ability for an algorithm to request the current contract for a
future chain via `data.current`.

e.g.:
```
data.current(ContinuousFuture('CL', offset=0, roll='calendar'),
'contract')
```
This commit is contained in:
Eddie Hebert
2016-10-07 18:26:23 -04:00
parent 03d77b34b4
commit ec6f298972
9 changed files with 697 additions and 5 deletions
+28 -2
View File
@@ -23,6 +23,8 @@ from six import iteritems
from six.moves import reduce
from zipline.assets import Asset, Future, Equity
from zipline.assets.continuous_futures import ContinuousFuture
from zipline.assets.roll_finder import CalendarRollFinder
from zipline.data.dispatch_bar_reader import (
AssetDispatchMinuteBarReader,
AssetDispatchSessionBarReader
@@ -54,7 +56,14 @@ from zipline.errors import (
log = Logger('DataPortal')
BASE_FIELDS = frozenset([
"open", "high", "low", "close", "volume", "price", "last_traded"
"open",
"high",
"low",
"close",
"volume",
"price",
"contract",
"last_traded",
])
OHLCV_FIELDS = frozenset([
@@ -143,6 +152,11 @@ class DataPortal(object):
else:
self._last_trading_session = None
self._roll_finders = {
'calendar': CalendarRollFinder(self.trading_calendar,
self.asset_finder)
}
aligned_equity_minute_reader = self._ensure_reader_aligned(
equity_minute_reader)
aligned_equity_session_reader = self._ensure_reader_aligned(
@@ -342,7 +356,8 @@ class DataPortal(object):
# at it if it's on something like palladium and not AAPL (since our
# own price data always wins when dealing with assets).
return not (field in BASE_FIELDS and isinstance(asset, Asset))
return not (field in BASE_FIELDS and
(isinstance(asset, (Asset, ContinuousFuture))))
def _get_fetcher_value(self, asset, field, dt):
day = normalize_date(dt)
@@ -397,6 +412,8 @@ class DataPortal(object):
return 0
elif field != "last_traded":
return np.NaN
elif field == "contract":
return None
if data_frequency == "daily":
return self._get_daily_data(asset, field, session_label)
@@ -406,6 +423,8 @@ class DataPortal(object):
elif field == "price":
return self._get_minute_spot_value(asset, "close", dt,
ffill=True)
elif field == "contract":
return self._get_current_contract(asset, dt)
else:
return self._get_minute_spot_value(asset, field, dt)
@@ -1211,3 +1230,10 @@ class DataPortal(object):
ret = np.nan
return ret
def _get_current_contract(self, continuous_future, dt):
rf = self._roll_finders[continuous_future.roll_style]
return self.asset_finder.retrieve_asset(
rf.get_contract_center(continuous_future.root_symbol,
dt,
continuous_future.offset))