Merge pull request #1381 from quantopian/test-futures-last-sale-dt

Support last sale dt and spot value for Future assets.
This commit is contained in:
Eddie Hebert
2016-08-09 15:52:50 -04:00
committed by GitHub
3 changed files with 368 additions and 155 deletions
+176 -4
View File
@@ -12,8 +12,10 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from collections import OrderedDict
from numpy import nan, full, append
from numpy import array, append, nan, full
from numpy.testing import assert_almost_equal
import pandas as pd
from pandas.tslib import Timedelta
@@ -31,10 +33,28 @@ class TestDataPortal(WithDataPortal,
ASSET_FINDER_EQUITY_SIDS = (1,)
START_DATE = pd.Timestamp('2016-08-01')
END_DATE = pd.Timestamp('2016-08-04')
END_DATE = pd.Timestamp('2016-08-08')
TRADING_CALENDAR_STRS = ('NYSE', 'CME')
EQUITY_DAILY_BAR_SOURCE_FROM_MINUTE = True
@classmethod
def make_futures_info(cls):
trading_sessions = cls.trading_sessions['CME']
return pd.DataFrame({
'sid': [10000],
'root_symbol': ['BAR'],
'symbol': ['BARA'],
'start_date': [trading_sessions[1]],
'end_date': [cls.END_DATE],
# TODO: Make separate from 'end_date'
'notice_date': [cls.END_DATE],
'expiration_date': [cls.END_DATE],
'multiplier': [500],
'exchange': ['CME'],
})
@classmethod
def make_equity_minute_bar_data(cls):
trading_calendar = cls.trading_calendars[Equity]
@@ -83,7 +103,59 @@ class TestDataPortal(WithDataPortal,
index=dts))
yield 1, pd.concat(dfs)
def test_get_last_traded_minute(self):
@classmethod
def make_future_minute_bar_data(cls):
asset = cls.asset_finder.retrieve_asset(10000)
trading_calendar = cls.trading_calendars[asset.exchange]
trading_sessions = cls.trading_sessions[asset.exchange]
# No data on first day, future asset intentionally not on the same
# dates as equities, so that cross-wiring of results do not create a
# false positive.
dts = trading_calendar.minutes_for_session(trading_sessions[1])
dfs = []
dfs.append(pd.DataFrame(
{
'open': full(len(dts), nan),
'high': full(len(dts), nan),
'low': full(len(dts), nan),
'close': full(len(dts), nan),
'volume': full(len(dts), 0),
},
index=dts))
dts = trading_calendar.minutes_for_session(trading_sessions[2])
dfs.append(pd.DataFrame(
{
'open': append(200.5, full(len(dts) - 1, nan)),
'high': append(200.9, full(len(dts) - 1, nan)),
'low': append(200.1, full(len(dts) - 1, nan)),
'close': append(200.3, full(len(dts) - 1, nan)),
'volume': append(2000, full(len(dts) - 1, nan)),
},
index=dts))
dts = trading_calendar.minutes_for_session(trading_sessions[3])
dfs.append(pd.DataFrame(
{
'open': [nan, 203.50, 202.50, 204.50, 201.50, nan],
'high': [nan, 203.90, 202.90, 204.90, 201.90, nan],
'low': [nan, 203.10, 202.10, 204.10, 201.10, nan],
'close': [nan, 203.30, 202.30, 204.30, 201.30, nan],
'volume': [0, 2003, 2002, 2004, 2001, 0]
},
index=dts[:6]
))
dts = trading_calendar.minutes_for_session(trading_sessions[4])
dfs.append(pd.DataFrame(
{
'open': full(len(dts), nan),
'high': full(len(dts), nan),
'low': full(len(dts), nan),
'close': full(len(dts), nan),
'volume': full(len(dts), 0),
},
index=dts))
yield asset.sid, pd.concat(dfs)
def test_get_last_traded_equity_minute(self):
trading_calendar = self.trading_calendars[Equity]
# Case: Missing data at front of data set, and request dt is before
# first value.
@@ -105,7 +177,29 @@ class TestDataPortal(WithDataPortal,
self.data_portal.get_last_traded_dt(
asset, dts[5], 'minute'))
def test_get_last_traded_dt_daily(self):
def test_get_last_traded_future_minute(self):
asset = self.asset_finder.retrieve_asset(10000)
trading_calendar = self.trading_calendars[asset.exchange]
# Case: Missing data at front of data set, and request dt is before
# first value.
dts = trading_calendar.minutes_for_session(self.trading_days[0])
self.assertTrue(pd.isnull(
self.data_portal.get_last_traded_dt(
asset, dts[0], 'minute')))
# Case: Data on requested dt.
dts = trading_calendar.minutes_for_session(self.trading_days[3])
self.assertEqual(dts[1],
self.data_portal.get_last_traded_dt(
asset, dts[1], 'minute'))
# Case: No data on dt, but data occuring before dt.
self.assertEqual(dts[4],
self.data_portal.get_last_traded_dt(
asset, dts[5], 'minute'))
def test_get_last_traded_dt_equity_daily(self):
# Case: Missing data at front of data set, and request dt is before
# first value.
asset = self.asset_finder.retrieve_asset(1)
@@ -123,6 +217,84 @@ class TestDataPortal(WithDataPortal,
self.data_portal.get_last_traded_dt(
asset, self.trading_days[3], 'daily'))
def test_get_spot_value_equity_minute(self):
trading_calendar = self.trading_calendars[Equity]
asset = self.asset_finder.retrieve_asset(1)
dts = trading_calendar.minutes_for_session(self.trading_days[2])
# Case: Get data on exact dt.
dt = dts[1]
expected = OrderedDict({
'open': 103.5,
'high': 103.9,
'low': 103.1,
'close': 103.3,
'volume': 1003,
'price': 103.3
})
result = [self.data_portal.get_spot_value(asset,
field,
dt,
'minute')
for field in expected.keys()]
assert_almost_equal(array(list(expected.values())), result)
# Case: Get data on empty dt, return nan or most recent data for price.
dt = dts[100]
expected = OrderedDict({
'open': nan,
'high': nan,
'low': nan,
'close': nan,
'volume': 0,
'price': 101.3
})
result = [self.data_portal.get_spot_value(asset,
field,
dt,
'minute')
for field in expected.keys()]
assert_almost_equal(array(list(expected.values())), result)
def test_get_spot_value_future_minute(self):
trading_calendar = self.trading_calendars['CME']
asset = self.asset_finder.retrieve_asset(10000)
dts = trading_calendar.minutes_for_session(self.trading_days[3])
# Case: Get data on exact dt.
dt = dts[1]
expected = OrderedDict({
'open': 203.5,
'high': 203.9,
'low': 203.1,
'close': 203.3,
'volume': 2003,
'price': 203.3
})
result = [self.data_portal.get_spot_value(asset,
field,
dt,
'minute')
for field in expected.keys()]
assert_almost_equal(array(list(expected.values())), result)
# Case: Get data on empty dt, return nan or most recent data for price.
dt = dts[100]
expected = OrderedDict({
'open': nan,
'high': nan,
'low': nan,
'close': nan,
'volume': 0,
'price': 201.3
})
result = [self.data_portal.get_spot_value(asset,
field,
dt,
'minute')
for field in expected.keys()]
assert_almost_equal(array(list(expected.values())), result)
def test_bar_count_for_simple_transforms(self):
# July 2015
# Su Mo Tu We Th Fr Sa
+15 -102
View File
@@ -14,7 +14,6 @@
# limitations under the License.
from operator import mul
import bcolz
from logbook import Logger
import numpy as np
@@ -276,50 +275,6 @@ class DataPortal(object):
self._extra_source_df = extra_source_df
def _open_minute_file(self, field, asset):
sid_str = str(int(asset))
try:
carray = self._carrays[field][sid_str]
except KeyError:
carray = self._carrays[field][sid_str] = \
self._get_ctable(asset)[field]
return carray
def _get_ctable(self, asset):
sid = int(asset)
if isinstance(asset, Future):
if self._future_minute_reader.sid_path_func is not None:
path = self._future_minute_reader.sid_path_func(
self._future_minute_reader.rootdir, sid
)
else:
path = "{0}/{1}.bcolz".format(
self._future_minute_reader.rootdir, sid)
elif isinstance(asset, Equity):
if self._equity_minute_reader.sid_path_func is not None:
path = self._equity_minute_reader.sid_path_func(
self._equity_minute_reader.rootdir, sid
)
else:
path = "{0}/{1}.bcolz".format(
self._equity_minute_reader.rootdir, sid)
else:
# TODO: Figure out if assets should be allowed if neither, and
# why this code path is being hit.
if self._equity_minute_reader.sid_path_func is not None:
path = self._equity_minute_reader.sid_path_func(
self._equity_minute_reader.rootdir, sid
)
else:
path = "{0}/{1}.bcolz".format(
self._equity_minute_reader.rootdir, sid)
return bcolz.open(path, mode='r')
def _get_pricing_reader(self, asset, data_frequency):
return self._pricing_readers[type(asset)][data_frequency]
@@ -402,23 +357,13 @@ class DataPortal(object):
if data_frequency == "daily":
return self._get_daily_data(asset, field, session_label)
else:
if isinstance(asset, Future):
if field == "price":
return self._get_minute_spot_value_future(
asset, "close", dt)
else:
return self._get_minute_spot_value_future(
asset, field, dt)
if field == "last_traded":
return self.get_last_traded_dt(asset, dt, 'minute')
elif field == "price":
return self._get_minute_spot_value(asset, "close", dt,
ffill=True)
else:
if field == "last_traded":
return self._equity_minute_reader.get_last_traded_dt(
asset, dt
)
elif field == "price":
return self._get_minute_spot_value(asset, "close", dt,
True)
else:
return self._get_minute_spot_value(asset, field, dt)
return self._get_minute_spot_value(asset, field, dt)
def get_adjustments(self, assets, field, dt, perspective_dt):
"""
@@ -537,59 +482,27 @@ class DataPortal(object):
return spot_value
def _get_minute_spot_value_future(self, asset, column, dt):
# Futures bcolz files have 1440 bars per day (24 hours), 7 days a week.
# The file attributes contain the "start_dt" and "last_dt" fields,
# which represent the time period for this bcolz file.
# The start_dt is midnight of the first day that this future started
# trading.
# figure out the # of minutes between dt and this asset's start_dt
start_date = self._get_asset_start_date(asset)
minute_offset = int((dt - start_date).total_seconds() / 60)
if minute_offset < 0:
# asking for a date that is before the asset's start date, no dice
return 0.0
# then just index into the bcolz carray at that offset
carray = self._open_minute_file(column, asset)
result = carray[minute_offset]
# if there's missing data, go backwards until we run out of file
while result == 0 and minute_offset > 0:
minute_offset -= 1
result = carray[minute_offset]
if column != 'volume':
# FIXME switch to a futures reader
return result * 0.001
else:
return result
def _get_minute_spot_value(self, asset, column, dt, ffill=False):
result = self._equity_minute_reader.get_value(
reader = self._get_pricing_reader(asset, 'minute')
result = reader.get_value(
asset.sid, dt, column
)
if column == "volume":
if result == 0:
return 0
elif not ffill or not np.isnan(result):
# if we're not forward filling, or we found a result, return it
if not ffill:
return result
# we are looking for price, and didn't find one. have to go hunting.
last_traded_dt = \
self._equity_minute_reader.get_last_traded_dt(asset, dt)
last_traded_dt = reader.get_last_traded_dt(asset, dt)
if last_traded_dt is pd.NaT:
# no last traded dt, bail
return np.nan
if column == 'volume':
return 0
else:
return np.nan
# get the value as of the last traded dt
result = self._equity_minute_reader.get_value(
result = reader.get_value(
asset.sid,
last_traded_dt,
column
+177 -49
View File
@@ -391,6 +391,7 @@ class WithTradingCalendars(object):
"""
TRADING_CALENDAR_STRS = ('NYSE',)
TRADING_CALENDAR_FOR_ASSET_TYPE = {Equity: 'NYSE'}
TRADING_CALENDAR_FOR_EXCHANGE = {}
# For backwards compatibility, exisitng tests and fixtures refer to
# `trading_calendar` with the assumption that the value is the NYSE
@@ -413,6 +414,9 @@ class WithTradingCalendars(object):
cls.TRADING_CALENDAR_FOR_ASSET_TYPE):
calendar = get_calendar(cal_str)
cls.trading_calendars[asset_type] = calendar
for exchange, cal_str in iteritems(cls.TRADING_CALENDAR_FOR_EXCHANGE):
register_calendar(exchange, get_calendar(cal_str))
cls.trading_calendars[exchange] = get_calendar(cal_str)
class WithTradingEnvironment(WithAssetFinder, WithTradingCalendars):
@@ -562,15 +566,17 @@ class WithTradingSessions(WithTradingCalendars):
for cal_str in cls.TRADING_CALENDAR_STRS:
trading_calendar = cls.trading_calendars[cal_str]
all_sessions = trading_calendar.all_sessions
start_loc = all_sessions.get_loc(cls.DATA_MIN_DAY, 'bfill')
end_loc = all_sessions.get_loc(cls.DATA_MAX_DAY, 'ffill')
sessions = all_sessions[start_loc:end_loc + 1]
sessions = trading_calendar.sessions_in_range(
cls.DATA_MIN_DAY, cls.DATA_MAX_DAY)
# Set name for aliasing.
setattr(cls,
'{0}_sessions'.format(cal_str.lower()), sessions)
cls.trading_sessions[cal_str] = sessions
for exchange, cal_str in iteritems(cls.TRADING_CALENDAR_FOR_EXCHANGE):
trading_calendar = cls.trading_calendars[cal_str]
sessions = trading_calendar.sessions_in_range(
cls.DATA_MIN_DAY, cls.DATA_MAX_DAY)
cls.trading_sessions[exchange] = sessions
class WithTmpDir(object):
@@ -632,7 +638,7 @@ class WithEquityDailyBarData(WithTradingEnvironment):
The end date up to which to create data. This defaults to ``END_DATE``.
EQUITY_DAILY_BAR_SOURCE_FROM_MINUTE : bool
If this flag is set, `make_equity_daily_bar_data` will read data from
the minute bars defined by `WithMinuteBarData`.
the minute bars defined by `WithEquityMinuteBarData`.
The current default is `False`, but could be `True` in the future.
Methods
@@ -658,7 +664,7 @@ class WithEquityDailyBarData(WithTradingEnvironment):
@classmethod
def _make_equity_daily_bar_from_minute(cls):
assets = cls.asset_finder.retrieve_all(cls.asset_finder.sids)
assets = cls.asset_finder.retrieve_all(cls.asset_finder.equities_sids)
minute_data = dict(cls.make_equity_minute_bar_data())
for asset in assets:
yield asset.sid, minute_to_session(minute_data[asset.sid],
@@ -792,12 +798,33 @@ class WithBcolzEquityDailyBarReaderFromCSVs(WithBcolzEquityDailyBarReader):
_write_method_name = 'write_csvs'
class WithEquityMinuteBarData(WithTradingEnvironment):
def _trading_days_for_minute_bars(calendar,
start_date,
end_date,
lookback_days):
first_session = calendar.minute_to_session_label(start_date)
if lookback_days > 0:
first_session = calendar.sessions_window(
first_session,
-1 * lookback_days
)[0]
return calendar.sessions_in_range(first_session, end_date)
class _WithMinuteBarDataBase(WithTradingEnvironment):
MINUTE_BAR_LOOKBACK_DAYS = 0
MINUTE_BAR_START_DATE = alias('START_DATE')
MINUTE_BAR_END_DATE = alias('END_DATE')
class WithEquityMinuteBarData(_WithMinuteBarDataBase):
"""
ZiplineTestCase mixin providing cls.equity_minute_bar_days.
After init_class_fixtures has been called:
- `cls.equyt_minute_bar_days` has the range over which data has been
- `cls.equity_minute_bar_days` has the range over which data has been
generated.
Attributes
@@ -806,10 +833,6 @@ class WithEquityMinuteBarData(WithTradingEnvironment):
The number of days of data to add before the first day.
This is used when a test needs to use history, in which case this
should be set to the largest history window that will be requested.
EQUITY_MINUTE_BAR_USE_FULL_CALENDAR : bool
If this flag is set the ``equity_daily_bar_days`` will be the full
set of trading days from the trading environment. This flag overrides
``EQUITY_MINUTE_BAR_LOOKBACK_DAYS``.
EQUITY_MINUTE_BAR_START_DATE : Timestamp
The date at to which to start creating data. This defaults to
``START_DATE``.
@@ -830,11 +853,9 @@ class WithEquityMinuteBarData(WithTradingEnvironment):
WithEquityDailyBarData
zipline.testing.create_minute_bar_data
"""
EQUITY_MINUTE_BAR_LOOKBACK_DAYS = 0
EQUITY_MINUTE_BAR_USE_FULL_CALENDAR = False
EQUITY_MINUTE_BAR_START_DATE = alias('START_DATE')
EQUITY_MINUTE_BAR_END_DATE = alias('END_DATE')
EQUITY_MINUTE_BAR_LOOKBACK_DAYS = alias('MINUTE_BAR_LOOKBACK_DAYS')
EQUITY_MINUTE_BAR_START_DATE = alias('MINUTE_BAR_START_DATE')
EQUITY_MINUTE_BAR_END_DATE = alias('MINUTE_BAR_END_DATE')
@classmethod
def make_equity_minute_bar_data(cls):
@@ -844,32 +865,80 @@ class WithEquityMinuteBarData(WithTradingEnvironment):
cls.equity_minute_bar_days[0],
cls.equity_minute_bar_days[-1],
),
cls.asset_finder.sids,
cls.asset_finder.equities_sids,
)
@classmethod
def init_class_fixtures(cls):
super(WithEquityMinuteBarData, cls).init_class_fixtures()
trading_calendar = cls.trading_calendars[Equity]
if cls.EQUITY_MINUTE_BAR_USE_FULL_CALENDAR:
days = trading_calendar.all_execution_days
else:
first_session = trading_calendar.minute_to_session_label(
pd.Timestamp(cls.EQUITY_MINUTE_BAR_START_DATE)
)
cls.equity_minute_bar_days = _trading_days_for_minute_bars(
trading_calendar,
pd.Timestamp(cls.EQUITY_MINUTE_BAR_START_DATE),
pd.Timestamp(cls.EQUITY_MINUTE_BAR_END_DATE),
cls.EQUITY_MINUTE_BAR_LOOKBACK_DAYS
)
if cls.EQUITY_MINUTE_BAR_LOOKBACK_DAYS > 0:
first_session = trading_calendar.sessions_window(
first_session,
-1 * cls.EQUITY_MINUTE_BAR_LOOKBACK_DAYS
)[0]
days = trading_calendar.sessions_in_range(
first_session,
cls.EQUITY_MINUTE_BAR_END_DATE
)
class WithFutureMinuteBarData(_WithMinuteBarDataBase):
"""
ZiplineTestCase mixin providing cls.future_minute_bar_days.
cls.equity_minute_bar_days = days
After init_class_fixtures has been called:
- `cls.future_minute_bar_days` has the range over which data has been
generated.
Attributes
----------
FUTURE_MINUTE_BAR_LOOKBACK_DAYS : int
The number of days of data to add before the first day.
This is used when a test needs to use history, in which case this
should be set to the largest history window that will be requested.
FUTURE_MINUTE_BAR_START_DATE : Timestamp
The date at to which to start creating data. This defaults to
``START_DATE``.
FUTURE_MINUTE_BAR_END_DATE = Timestamp
The end date up to which to create data. This defaults to ``END_DATE``.
Methods
-------
make_future_minute_bar_data() -> iterable[(int, pd.DataFrame)]
A class method that returns a dict mapping sid to dataframe
which will be written to into the the format of the inherited
class which writes the minute bar data for use by a reader.
By default this creates some simple sythetic data with
:func:`~zipline.testing.create_minute_bar_data`
See Also
--------
zipline.testing.create_minute_bar_data
"""
FUTURE_MINUTE_BAR_LOOKBACK_DAYS = alias('MINUTE_BAR_LOOKBACK_DAYS')
FUTURE_MINUTE_BAR_START_DATE = alias('MINUTE_BAR_START_DATE')
FUTURE_MINUTE_BAR_END_DATE = alias('MINUTE_BAR_END_DATE')
@classmethod
def make_future_minute_bar_data(cls):
trading_calendar = get_calendar('CME')
return create_minute_bar_data(
trading_calendar.minutes_for_sessions_in_range(
cls.future_minute_bar_days[0],
cls.future_minute_bar_days[-1],
),
cls.asset_finder.futures_sids,
)
@classmethod
def init_class_fixtures(cls):
super(WithFutureMinuteBarData, cls).init_class_fixtures()
# To be replaced by quanto calendar.
trading_calendar = get_calendar('CME')
cls.future_minute_bar_days = _trading_days_for_minute_bars(
trading_calendar,
pd.Timestamp(cls.FUTURE_MINUTE_BAR_START_DATE),
pd.Timestamp(cls.FUTURE_MINUTE_BAR_END_DATE),
cls.FUTURE_MINUTE_BAR_LOOKBACK_DAYS
)
class WithBcolzEquityMinuteBarReader(WithEquityMinuteBarData, WithTmpDir):
@@ -891,14 +960,6 @@ class WithBcolzEquityMinuteBarReader(WithEquityMinuteBarData, WithTmpDir):
----------
BCOLZ_MINUTE_BAR_PATH : str
The path inside the tmpdir where this will be written.
EQUITY_MINUTE_BAR_LOOKBACK_DAYS : int
The number of days of data to add before the first day.
This is used when a test needs to use history, in which case this
should be set to the largest history window that will be requested.
BCOLZ_MINUTE_BAR_USE_FULL_CALENDAR : bool
If this flag is set the ``equity_daily_bar_days`` will be the full
set of trading days from the trading environment. This flag overrides
``EQUITY_MINUTE_BAR_LOOKBACK_DAYS``.
Methods
-------
@@ -913,17 +974,17 @@ class WithBcolzEquityMinuteBarReader(WithEquityMinuteBarData, WithTmpDir):
WithDataPortal
zipline.testing.create_minute_bar_data
"""
BCOLZ_MINUTE_BAR_PATH = 'minute_equity_pricing.bcolz'
BCOLZ_EQUITY_MINUTE_BAR_PATH = 'minute_equity_pricing'
@classmethod
def make_bcolz_minute_bar_rootdir_path(cls):
return cls.tmpdir.makedir(cls.BCOLZ_MINUTE_BAR_PATH)
def make_bcolz_equity_minute_bar_rootdir_path(cls):
return cls.tmpdir.makedir(cls.BCOLZ_EQUITY_MINUTE_BAR_PATH)
@classmethod
def init_class_fixtures(cls):
super(WithBcolzEquityMinuteBarReader, cls).init_class_fixtures()
cls.bcolz_minute_bar_path = p = \
cls.make_bcolz_minute_bar_rootdir_path()
cls.bcolz_equity_minute_bar_path = p = \
cls.make_bcolz_equity_minute_bar_rootdir_path()
days = cls.equity_minute_bar_days
writer = BcolzMinuteBarWriter(
@@ -939,6 +1000,67 @@ class WithBcolzEquityMinuteBarReader(WithEquityMinuteBarData, WithTmpDir):
BcolzMinuteBarReader(p)
class WithBcolzFutureMinuteBarReader(WithFutureMinuteBarData, WithTmpDir):
"""
ZiplineTestCase mixin providing cls.bcolz_minute_bar_path,
cls.bcolz_minute_bar_ctable, and cls.bcolz_equity_minute_bar_reader
class level fixtures.
After init_class_fixtures has been called:
- `cls.bcolz_minute_bar_path` is populated with
`cls.tmpdir.getpath(cls.BCOLZ_MINUTE_BAR_PATH)`.
- `cls.bcolz_minute_bar_ctable` is populated with data returned from
`cls.make_equity_minute_bar_data`. By default this calls
:func:`zipline.pipeline.loaders.synthetic.make_equity_minute_bar_data`.
- `cls.bcolz_equity_minute_bar_reader` is a minute bar reader
pointing to the directory that was just written to.
Attributes
----------
BCOLZ_FUTURE_MINUTE_BAR_PATH : str
The path inside the tmpdir where this will be written.
Methods
-------
make_bcolz_minute_bar_rootdir_path() -> string
A class method that returns the path for the directory that contains
the minute bar ctables. By default this is a subdirectory
BCOLZ_MINUTE_BAR_PATH in the shared temp directory.
See Also
--------
WithBcolzEquityDailyBarReader
WithDataPortal
zipline.testing.create_minute_bar_data
"""
BCOLZ_FUTURE_MINUTE_BAR_PATH = 'minute_future_pricing'
@classmethod
def make_bcolz_future_minute_bar_rootdir_path(cls):
return cls.tmpdir.makedir(cls.BCOLZ_FUTURE_MINUTE_BAR_PATH)
@classmethod
def init_class_fixtures(cls):
super(WithBcolzFutureMinuteBarReader, cls).init_class_fixtures()
trading_calendar = get_calendar('CME')
cls.bcolz_future_minute_bar_path = p = \
cls.make_bcolz_future_minute_bar_rootdir_path()
days = cls.future_minute_bar_days
writer = BcolzMinuteBarWriter(
days[0],
p,
trading_calendar.schedule.market_open.loc[days],
trading_calendar.schedule.market_close.loc[days],
# TODO: Make futures minutes per day.
1440,
)
writer.write(cls.make_future_minute_bar_data())
cls.bcolz_future_minute_bar_reader = \
BcolzMinuteBarReader(p)
class WithAdjustmentReader(WithBcolzEquityDailyBarReader):
"""
ZiplineTestCase mixin providing cls.adjustment_reader as a class level
@@ -1100,7 +1222,8 @@ class WithSeededRandomPipelineEngine(WithTradingSessions, WithAssetFinder):
class WithDataPortal(WithAdjustmentReader,
# Ordered so that bcolz minute reader is used first.
WithBcolzEquityMinuteBarReader):
WithBcolzEquityMinuteBarReader,
WithBcolzFutureMinuteBarReader):
"""
ZiplineTestCase mixin providing self.data_portal as an instance level
fixture.
@@ -1162,6 +1285,11 @@ class WithDataPortal(WithAdjustmentReader,
if self.DATA_PORTAL_USE_ADJUSTMENTS else
None
),
future_minute_reader=(
self.bcolz_future_minute_bar_reader
if self.DATA_PORTAL_USE_MINUTE_DATA else
None
),
)
def init_instance_fixtures(self):