DEV: Change daily mode to use last minute of session instead of session itself.

This commit is contained in:
Jean Bredeche
2016-07-21 10:00:04 -04:00
parent 2462929368
commit 3305933089
7 changed files with 65 additions and 40 deletions
+2 -1
View File
@@ -26,6 +26,7 @@ from pandas import (
Series,
Timestamp,
)
from pandas.tseries.tools import normalize_date
from six import iteritems, itervalues
from zipline.algorithm import TradingAlgorithm
@@ -512,7 +513,7 @@ class PipelineAlgorithmTestCase(WithBcolzEquityDailyBarReaderFromCSVs,
attach_pipeline(pipeline, 'test')
def handle_data(context, data):
today = get_datetime()
today = normalize_date(get_datetime())
results = pipeline_output('test')
expect_over_300 = {
AAPL: today < self.AAPL_split_date,
+21 -7
View File
@@ -3731,12 +3731,18 @@ class TestEquityAutoClose(WithTmpDir, WithTradingCalendar, ZiplineTestCase):
transactions = output['transactions']
initial_fills = transactions.iloc[1]
self.assertEqual(len(initial_fills), len(assets))
last_minute_of_session = \
self.trading_calendar.open_and_close_for_session(
self.test_days[1]
)[1]
for sid, txn in zip(sids, initial_fills):
self.assertDictContainsSubset(
{
'amount': order_size,
'commission': None,
'dt': self.test_days[1],
'dt': last_minute_of_session,
'price': initial_fill_prices[sid],
'sid': sid,
},
@@ -3803,15 +3809,17 @@ class TestEquityAutoClose(WithTmpDir, WithTradingCalendar, ZiplineTestCase):
context.portfolio.cash == context.portfolio.starting_cash
)
now = context.get_datetime()
today_session = self.trading_calendar.minute_to_session_label(
context.get_datetime()
)
if now == first_asset_end_date:
if today_session == first_asset_end_date:
# Equity 0 will no longer exist tomorrow, so this order will
# never be filled.
assert len(context.get_open_orders()) == 0
context.order(context.sid(0), 10)
assert len(context.get_open_orders()) == 1
elif now == first_asset_auto_close_date:
elif today_session == first_asset_auto_close_date:
assert len(context.get_open_orders()) == 0
algo = TradingAlgorithm(
@@ -3829,12 +3837,18 @@ class TestEquityAutoClose(WithTmpDir, WithTradingCalendar, ZiplineTestCase):
original_open_orders = orders_for_date(first_asset_end_date)
assert len(original_open_orders) == 1
last_close_for_asset = \
algo.trading_calendar.open_and_close_for_session(
first_asset_end_date
)[1]
self.assertDictContainsSubset(
{
'amount': 10,
'commission': 0,
'created': first_asset_end_date,
'dt': first_asset_end_date,
'created': last_close_for_asset,
'dt': last_close_for_asset,
'sid': assets[0],
'status': ORDER_STATUS.OPEN,
'filled': 0,
@@ -3848,7 +3862,7 @@ class TestEquityAutoClose(WithTmpDir, WithTradingCalendar, ZiplineTestCase):
{
'amount': 10,
'commission': 0,
'created': first_asset_end_date,
'created': last_close_for_asset,
'dt': first_asset_auto_close_date,
'sid': assets[0],
'status': ORDER_STATUS.CANCELLED,
+2 -1
View File
@@ -417,6 +417,7 @@ def handle_data(context, data):
algocode = """
from pandas import Timestamp
from pandas.tseries.tools import normalize_date
from zipline.api import fetch_csv, record, sid, get_datetime
def initialize(context):
@@ -432,7 +433,7 @@ def initialize(context):
context.bar_count = 0
def handle_data(context, data):
expected = context.expected_sids[get_datetime()]
expected = context.expected_sids[normalize_date(get_datetime())]
actual = data.fetcher_assets
for stk in expected:
if stk not in actual:
+19
View File
@@ -164,6 +164,7 @@ cdef class BarData:
cdef object _universe_func
cdef object _last_calculated_universe
cdef object _universe_last_updated_at
cdef bool _daily_mode
cdef bool _adjust_minutes
@@ -177,6 +178,8 @@ cdef class BarData:
self.data_frequency = data_frequency
self._views = {}
self._daily_mode = (self.data_frequency == "daily")
self._universe_func = universe_func
self._last_calculated_universe = None
self._universe_last_updated_at = None
@@ -220,12 +223,28 @@ cdef class BarData:
)
cdef _get_current_minute(self):
"""
Internal utility method to get the current simulation time.
Possible answers are:
- whatever the algorithm's get_datetime() method returns (this is what
`self.simulation_dt_func()` points to)
- sometimes we're knowingly not in a market minute, like if we're in
before_trading_start. In that case, `self._adjust_minutes` is
True, and we get the previous market minute.
- if we're in daily mode, get the session label for this minute.
"""
dt = self.simulation_dt_func()
if self._adjust_minutes:
dt = \
self.data_portal.trading_calendar.previous_minute(dt)
if self._daily_mode:
# if we're in daily mode, take the given dt (which is the last
# minute of the session) and get the session label for it.
dt = self.data_portal.trading_calendar.minute_to_session_label(dt)
return dt
@check_parameters(('assets', 'fields'), ((Asset, str), str))
+15 -12
View File
@@ -119,10 +119,7 @@ from zipline.utils.preprocess import preprocess
import zipline.protocol
from zipline.sources.requests_csv import PandasRequestsCSV
from zipline.gens.sim_engine import (
MinuteSimulationClock,
DailySimulationClock,
)
from zipline.gens.sim_engine import MinuteSimulationClock
from zipline.sources.benchmark_source import BenchmarkSource
from zipline.zipline_warnings import ZiplineDeprecationWarning
@@ -497,25 +494,31 @@ class TradingAlgorithm(object):
"""
If the clock property is not set, then create one based on frequency.
"""
trading_o_and_c = self.trading_calendar.schedule.ix[
self.sim_params.sessions]
market_closes = trading_o_and_c['market_close'].values.astype(np.int64)
if self.sim_params.data_frequency == 'minute':
trading_o_and_c = self.trading_calendar.schedule.ix[
self.sim_params.sessions]
market_opens = trading_o_and_c['market_open'].values.astype(
'datetime64[ns]').astype(np.int64)
market_closes = trading_o_and_c['market_close'].values.astype(
'datetime64[ns]').astype(np.int64)
np.int64)
minutely_emission = self.sim_params.emission_rate == "minute"
clock = MinuteSimulationClock(
return MinuteSimulationClock(
self.sim_params.sessions,
market_opens,
market_closes,
minutely_emission
)
return clock
else:
return DailySimulationClock(self.sim_params.sessions)
# in daily mode, we want to have one bar per session, timestamped
# as the last minute of the session.
return MinuteSimulationClock(
self.sim_params.sessions,
market_closes,
market_closes,
False
)
def _create_benchmark_source(self):
return BenchmarkSource(
+6 -5
View File
@@ -773,19 +773,20 @@ class DataPortal(object):
if field not in BASE_FIELDS:
raise KeyError("Invalid column: " + str(field))
session_label = self.trading_calendar.minute_to_session_label(dt)
if dt < asset.start_date or \
(data_frequency == "daily" and dt > asset.end_date) or \
(data_frequency == "daily" and
session_label > asset.end_date) or \
(data_frequency == "minute" and
normalize_date(dt) > asset.end_date):
session_label > asset.end_date):
if field == "volume":
return 0
elif field != "last_traded":
return np.NaN
if data_frequency == "daily":
day_to_use = dt
day_to_use = normalize_date(day_to_use)
return self._get_daily_data(asset, field, day_to_use)
return self._get_daily_data(asset, field, session_label)
else:
if isinstance(asset, Future):
if field == "price":
-14
View File
@@ -84,17 +84,3 @@ cdef class MinuteSimulationClock:
yield minute, MINUTE_END
yield minutes[-1], DAY_END
cdef class DailySimulationClock:
cdef object trading_days
def __init__(self, trading_days):
self.trading_days = trading_days
def __iter__(self):
for i, day in enumerate(self.trading_days):
yield day, DAY_START
yield day, BAR
yield day, DAY_END