mirror of
https://github.com/wassname/catalyst.git
synced 2026-08-15 12:15:22 +08:00
ENH: Adds ExchangeCalendar, TradingSchedule, and implementations
Conflicts: tests/data/test_minute_bars.py tests/data/test_us_equity_pricing.py tests/finance/test_slippage.py tests/pipeline/test_engine.py tests/pipeline/test_us_equity_pricing_loader.py tests/serialization_cases.py tests/test_algorithm.py tests/test_assets.py tests/test_bar_data.py tests/test_benchmark.py tests/test_exception_handling.py tests/test_fetcher.py tests/test_finance.py tests/test_history.py tests/test_perf_tracking.py tests/test_security_list.py tests/utils/test_events.py zipline/algorithm.py zipline/data/data_portal.py zipline/data/us_equity_loader.py zipline/errors.py zipline/finance/trading.py zipline/testing/core.py zipline/utils/events.py
This commit is contained in:
@@ -45,8 +45,7 @@ from zipline.data.minute_bars import (
|
||||
US_EQUITIES_MINUTES_PER_DAY,
|
||||
BcolzMinuteWriterColumnMismatch
|
||||
)
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
|
||||
from zipline.utils.calendars import get_calendar, default_nyse_schedule
|
||||
|
||||
# Calendar is set to cover several half days, to check a case where half
|
||||
# days would be read out of order in cases of windows which spanned over
|
||||
@@ -59,15 +58,11 @@ class BcolzMinuteBarTestCase(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
all_market_opens = cls.env.open_and_closes.market_open
|
||||
all_market_closes = cls.env.open_and_closes.market_close
|
||||
indexer = all_market_opens.index.slice_indexer(
|
||||
start=TEST_CALENDAR_START,
|
||||
end=TEST_CALENDAR_STOP
|
||||
trading_days = get_calendar('NYSE').trading_days(
|
||||
TEST_CALENDAR_START, TEST_CALENDAR_STOP
|
||||
)
|
||||
cls.market_opens = all_market_opens[indexer]
|
||||
cls.market_closes = all_market_closes[indexer]
|
||||
cls.market_opens = trading_days.market_open
|
||||
cls.market_closes = trading_days.market_close
|
||||
cls.test_calendar_start = cls.market_opens.index[0]
|
||||
cls.test_calendar_stop = cls.market_opens.index[-1]
|
||||
|
||||
@@ -802,10 +797,12 @@ class BcolzMinuteBarTestCase(TestCase):
|
||||
|
||||
data = {sids[0]: data_1, sids[1]: data_2}
|
||||
|
||||
start_minute_loc = self.env.market_minutes.get_loc(minutes[0])
|
||||
minute_locs = [self.env.market_minutes.get_loc(minute) -
|
||||
start_minute_loc
|
||||
for minute in minutes]
|
||||
start_minute_loc = \
|
||||
default_nyse_schedule.all_execution_minutes.get_loc(minutes[0])
|
||||
minute_locs = [
|
||||
default_nyse_schedule.all_execution_minutes.get_loc(minute) \
|
||||
- start_minute_loc
|
||||
for minute in minutes]
|
||||
|
||||
for i, col in enumerate(columns):
|
||||
for j, sid in enumerate(sids):
|
||||
@@ -824,7 +821,9 @@ class BcolzMinuteBarTestCase(TestCase):
|
||||
'close': arange(1, 781),
|
||||
'volume': arange(1, 781)
|
||||
}
|
||||
dts = array(self.env.minutes_for_days_in_range(start_day, end_day))
|
||||
dts = array(default_nyse_schedule.execution_minutes_for_days_in_range(
|
||||
start_day, end_day
|
||||
))
|
||||
self.writer.write_cols(sid, dts, cols)
|
||||
|
||||
self.assertEqual(
|
||||
@@ -866,7 +865,9 @@ class BcolzMinuteBarTestCase(TestCase):
|
||||
'close': arange(1, 601),
|
||||
'volume': arange(1, 601)
|
||||
}
|
||||
dts = array(self.env.minutes_for_days_in_range(start_day, end_day))
|
||||
dts = array(default_nyse_schedule.execution_minutes_for_days_in_range(
|
||||
start_day, end_day
|
||||
))
|
||||
self.writer.write_cols(sid, dts, cols)
|
||||
|
||||
self.assertEqual(
|
||||
|
||||
@@ -46,6 +46,7 @@ from zipline.testing.fixtures import (
|
||||
WithBcolzDailyBarReader,
|
||||
ZiplineTestCase,
|
||||
)
|
||||
from zipline.utils.calendars import get_calendar
|
||||
|
||||
TEST_CALENDAR_START = Timestamp('2015-06-01', tz='UTC')
|
||||
TEST_CALENDAR_STOP = Timestamp('2015-06-30', tz='UTC')
|
||||
@@ -96,11 +97,9 @@ class BcolzDailyBarTestCase(WithBcolzDailyBarReader, ZiplineTestCase):
|
||||
@classmethod
|
||||
def init_class_fixtures(cls):
|
||||
super(BcolzDailyBarTestCase, cls).init_class_fixtures()
|
||||
all_trading_days = cls.env.trading_days
|
||||
cls.trading_days = all_trading_days[
|
||||
all_trading_days.get_loc(TEST_CALENDAR_START):
|
||||
all_trading_days.get_loc(TEST_CALENDAR_STOP) + 1
|
||||
]
|
||||
cls.trading_days = get_calendar('NYSE').trading_days(
|
||||
TEST_CALENDAR_START, TEST_CALENDAR_STOP
|
||||
).index
|
||||
|
||||
@property
|
||||
def assets(self):
|
||||
|
||||
@@ -38,6 +38,7 @@ from zipline.testing.fixtures import (
|
||||
WithSimParams,
|
||||
ZiplineTestCase,
|
||||
)
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
|
||||
|
||||
class SlippageTestCase(WithSimParams, WithDataPortal, ZiplineTestCase):
|
||||
@@ -93,7 +94,7 @@ class SlippageTestCase(WithSimParams, WithDataPortal, ZiplineTestCase):
|
||||
)
|
||||
with tmp_bcolz_minute_bar_reader(self.env, days, assets) as reader:
|
||||
data_portal = DataPortal(
|
||||
self.env,
|
||||
self.env, default_nyse_schedule,
|
||||
first_trading_day=reader.first_trading_day,
|
||||
equity_minute_reader=reader,
|
||||
)
|
||||
@@ -482,8 +483,12 @@ class SlippageTestCase(WithSimParams, WithDataPortal, ZiplineTestCase):
|
||||
)
|
||||
with tmp_bcolz_minute_bar_reader(self.env, days, assets) as reader:
|
||||
data_portal = DataPortal(
|
||||
<<<<<<< HEAD
|
||||
self.env,
|
||||
first_trading_day=reader.first_trading_day,
|
||||
=======
|
||||
self.env, default_nyse_schedule,
|
||||
>>>>>>> ENH: Adds ExchangeCalendar, TradingSchedule, and implementations
|
||||
equity_minute_reader=reader,
|
||||
)
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ from zipline.testing.fixtures import (
|
||||
ZiplineTestCase,
|
||||
)
|
||||
from zipline.utils.memoize import lazyval
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
|
||||
|
||||
class RollingSumDifference(CustomFactor):
|
||||
@@ -826,7 +827,7 @@ class FrameInputTestCase(WithTradingEnvironment, ZiplineTestCase):
|
||||
cls.dates = date_range(
|
||||
cls.start,
|
||||
cls.end,
|
||||
freq=cls.env.trading_day,
|
||||
freq=default_nyse_schedule.day,
|
||||
tz='UTC',
|
||||
)
|
||||
cls.assets = cls.asset_finder.retrieve_all(cls.asset_ids)
|
||||
@@ -985,7 +986,7 @@ class SyntheticBcolzTestCase(WithAdjustmentReader,
|
||||
def test_SMA(self):
|
||||
engine = SimplePipelineEngine(
|
||||
lambda column: self.pipeline_loader,
|
||||
self.env.trading_days,
|
||||
default_nyse_schedule.all_execution_days,
|
||||
self.asset_finder,
|
||||
)
|
||||
window_length = 5
|
||||
@@ -1039,7 +1040,7 @@ class SyntheticBcolzTestCase(WithAdjustmentReader,
|
||||
# valuable.
|
||||
engine = SimplePipelineEngine(
|
||||
lambda column: self.pipeline_loader,
|
||||
self.env.trading_days,
|
||||
default_nyse_schedule.all_execution_days,
|
||||
self.asset_finder,
|
||||
)
|
||||
window_length = 5
|
||||
@@ -1083,7 +1084,7 @@ class ParameterizedFactorTestCase(WithTradingEnvironment, ZiplineTestCase):
|
||||
@classmethod
|
||||
def init_class_fixtures(cls):
|
||||
super(ParameterizedFactorTestCase, cls).init_class_fixtures()
|
||||
day = cls.env.trading_day
|
||||
day = default_nyse_schedule.day
|
||||
|
||||
cls.dates = dates = date_range(
|
||||
'2015-02-01',
|
||||
|
||||
@@ -60,7 +60,7 @@ from zipline.testing.fixtures import (
|
||||
WithDataPortal,
|
||||
ZiplineTestCase,
|
||||
)
|
||||
from zipline.utils.tradingcalendar import trading_day
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
|
||||
|
||||
TEST_RESOURCE_PATH = join(
|
||||
@@ -70,6 +70,9 @@ TEST_RESOURCE_PATH = join(
|
||||
)
|
||||
|
||||
|
||||
trading_day = default_nyse_schedule.day
|
||||
|
||||
|
||||
def rolling_vwap(df, length):
|
||||
"Simple rolling vwap implementation for testing"
|
||||
closes = df['close'].values
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@ import zipline.finance.risk as risk
|
||||
from zipline.utils import factory
|
||||
|
||||
from zipline.finance.trading import SimulationParameters, TradingEnvironment
|
||||
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
from . import answer_key
|
||||
ANSWER_KEY = answer_key.ANSWER_KEY
|
||||
|
||||
@@ -51,7 +51,7 @@ class TestRisk(unittest.TestCase):
|
||||
self.sim_params = SimulationParameters(
|
||||
period_start=start_date,
|
||||
period_end=end_date,
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
self.algo_returns_06 = factory.create_returns_from_list(
|
||||
@@ -60,7 +60,9 @@ class TestRisk(unittest.TestCase):
|
||||
)
|
||||
|
||||
self.cumulative_metrics_06 = risk.RiskMetricsCumulative(
|
||||
self.sim_params, env=self.env
|
||||
self.sim_params,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
for dt, returns in answer_key.RETURNS_DATA.iterrows():
|
||||
|
||||
@@ -26,7 +26,7 @@ import zipline.finance.risk as risk
|
||||
from zipline.utils import factory
|
||||
|
||||
from zipline.finance.trading import SimulationParameters, TradingEnvironment
|
||||
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
from . import answer_key
|
||||
from . answer_key import AnswerKey
|
||||
|
||||
@@ -60,7 +60,7 @@ class TestRisk(unittest.TestCase):
|
||||
self.sim_params = SimulationParameters(
|
||||
period_start=start_date,
|
||||
period_end=end_date,
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
self.algo_returns_06 = factory.create_returns_from_list(
|
||||
@@ -75,7 +75,8 @@ class TestRisk(unittest.TestCase):
|
||||
self.algo_returns_06,
|
||||
self.sim_params,
|
||||
benchmark_returns=self.benchmark_returns_06,
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
)
|
||||
|
||||
start_08 = datetime.datetime(
|
||||
@@ -95,7 +96,7 @@ class TestRisk(unittest.TestCase):
|
||||
self.sim_params08 = SimulationParameters(
|
||||
period_start=start_08,
|
||||
period_end=end_08,
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
@@ -116,8 +117,9 @@ class TestRisk(unittest.TestCase):
|
||||
returns.index[0],
|
||||
returns.index[-1],
|
||||
returns,
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
benchmark_returns=self.env.benchmark_returns,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
)
|
||||
self.assertEqual(metrics.max_drawdown, 0.505)
|
||||
|
||||
@@ -142,7 +144,10 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
def test_trading_days_06(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params, env=self.env)
|
||||
metrics = risk.RiskReport(returns, self.sim_params,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
benchmark_returns=self.env.benchmark_returns)
|
||||
self.assertEqual([x.num_trading_days for x in metrics.year_periods],
|
||||
[251])
|
||||
self.assertEqual([x.num_trading_days for x in metrics.month_periods],
|
||||
@@ -366,7 +371,10 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
def test_benchmark_returns_08(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08, env=self.env)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
benchmark_returns=self.env.benchmark_returns)
|
||||
|
||||
self.assertEqual([round(x.benchmark_period_returns, 3)
|
||||
for x in metrics.month_periods],
|
||||
@@ -412,7 +420,10 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
def test_trading_days_08(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08, env=self.env)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
benchmark_returns=self.env.benchmark_returns)
|
||||
self.assertEqual([x.num_trading_days for x in metrics.year_periods],
|
||||
[253])
|
||||
|
||||
@@ -421,7 +432,10 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
def test_benchmark_volatility_08(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08, env=self.env)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
benchmark_returns=self.env.benchmark_returns)
|
||||
|
||||
self.assertEqual([round(x.benchmark_volatility, 3)
|
||||
for x in metrics.month_periods],
|
||||
@@ -469,7 +483,10 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
def test_treasury_returns_06(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params, env=self.env)
|
||||
metrics = risk.RiskReport(returns, self.sim_params,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
benchmark_returns=self.env.benchmark_returns)
|
||||
self.assertEqual([round(x.treasury_period_return, 4)
|
||||
for x in metrics.month_periods],
|
||||
[0.0037,
|
||||
@@ -533,12 +550,15 @@ class TestRisk(unittest.TestCase):
|
||||
sim_params90s = SimulationParameters(
|
||||
period_start=start,
|
||||
period_end=end,
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
returns = factory.create_returns_from_range(sim_params90s)
|
||||
returns = returns[:-10] # truncate the returns series to end mid-month
|
||||
metrics = risk.RiskReport(returns, sim_params90s, env=self.env)
|
||||
metrics = risk.RiskReport(returns, sim_params90s,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
benchmark_returns=self.env.benchmark_returns)
|
||||
total_months = 60
|
||||
self.check_metrics(metrics, total_months, start)
|
||||
|
||||
@@ -546,10 +566,13 @@ class TestRisk(unittest.TestCase):
|
||||
sim_params = SimulationParameters(
|
||||
period_start=start_date,
|
||||
period_end=start_date.replace(year=(start_date.year + years)),
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
returns = factory.create_returns_from_range(sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params, env=self.env)
|
||||
metrics = risk.RiskReport(returns, self.sim_params,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
benchmark_returns=self.env.benchmark_returns)
|
||||
total_months = years * 12
|
||||
self.check_metrics(metrics, total_months, start_date)
|
||||
|
||||
@@ -636,7 +659,8 @@ class TestRisk(unittest.TestCase):
|
||||
self.algo_returns_06,
|
||||
self.sim_params,
|
||||
benchmark_returns=benchmark_returns,
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
treasury_curves=self.env.treasury_curves,
|
||||
)
|
||||
for risk_period in chain.from_iterable(itervalues(report.to_dict())):
|
||||
self.assertIsNone(risk_period['beta'])
|
||||
|
||||
+35
-24
@@ -166,7 +166,7 @@ from zipline.utils.control_flow import nullctx
|
||||
import zipline.utils.events
|
||||
from zipline.utils.events import date_rules, time_rules, Always
|
||||
import zipline.utils.factory as factory
|
||||
from zipline.utils.tradingcalendar import trading_day, trading_days
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
|
||||
# Because test cases appear to reuse some resources.
|
||||
|
||||
@@ -826,7 +826,7 @@ def before_trading_start(context, data):
|
||||
self.sim_params.data_frequency = 'daily'
|
||||
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
num_days=4, env=self.env, data_frequency='daily')
|
||||
num_days=4, data_frequency='daily')
|
||||
|
||||
algo = TestRegisterTransformAlgorithm(
|
||||
sim_params=sim_params,
|
||||
@@ -835,7 +835,7 @@ def before_trading_start(context, data):
|
||||
self.assertEqual(algo.sim_params.data_frequency, 'daily')
|
||||
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
num_days=4, env=self.env, data_frequency='minute')
|
||||
num_days=4, data_frequency='minute')
|
||||
|
||||
algo = TestRegisterTransformAlgorithm(
|
||||
sim_params=sim_params,
|
||||
@@ -953,7 +953,7 @@ def before_trading_start(context, data):
|
||||
period_end=period_end,
|
||||
capital_base=float("1.0e5"),
|
||||
data_frequency='minute',
|
||||
env=env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
data_portal = create_data_portal(
|
||||
@@ -961,6 +961,7 @@ def before_trading_start(context, data):
|
||||
tempdir,
|
||||
sim_params,
|
||||
equities.index,
|
||||
default_nyse_schedule,
|
||||
)
|
||||
algo = algo_class(sim_params=sim_params, env=env)
|
||||
algo.run(data_portal)
|
||||
@@ -1551,9 +1552,10 @@ def handle_data(context, data):
|
||||
env=self.env,
|
||||
)
|
||||
trades = factory.create_daily_trade_source(
|
||||
[0], self.sim_params, self.env)
|
||||
[0], self.sim_params, self.env, default_nyse_schedule)
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env, tempdir, self.sim_params, {0: trades})
|
||||
self.env, default_nyse_schedule, tempdir, self.sim_params,
|
||||
{0: trades})
|
||||
results = test_algo.run(data_portal)
|
||||
|
||||
all_txns = [
|
||||
@@ -1640,7 +1642,7 @@ def handle_data(context, data):
|
||||
params = SimulationParameters(
|
||||
period_start=pd.Timestamp("2007-01-03", tz='UTC'),
|
||||
period_end=pd.Timestamp("2007-01-05", tz='UTC'),
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
# order method shouldn't blow up
|
||||
@@ -2719,7 +2721,6 @@ class TestTradingControls(WithSimParams, WithDataPortal, ZiplineTestCase):
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=start,
|
||||
num_days=4,
|
||||
env=env,
|
||||
data_frequency='minute',
|
||||
)
|
||||
|
||||
@@ -2727,7 +2728,8 @@ class TestTradingControls(WithSimParams, WithDataPortal, ZiplineTestCase):
|
||||
env,
|
||||
tempdir,
|
||||
sim_params,
|
||||
[1]
|
||||
[1],
|
||||
default_nyse_schedule,
|
||||
)
|
||||
|
||||
def handle_data(algo, data):
|
||||
@@ -2848,7 +2850,8 @@ class TestTradingControls(WithSimParams, WithDataPortal, ZiplineTestCase):
|
||||
env,
|
||||
tempdir,
|
||||
self.sim_params,
|
||||
[0]
|
||||
[0],
|
||||
default_nyse_schedule,
|
||||
)
|
||||
algo.run(data_portal)
|
||||
|
||||
@@ -2862,7 +2865,8 @@ class TestTradingControls(WithSimParams, WithDataPortal, ZiplineTestCase):
|
||||
env,
|
||||
tempdir,
|
||||
self.sim_params,
|
||||
[0]
|
||||
[0],
|
||||
default_nyse_schedule,
|
||||
)
|
||||
algo = SetAssetDateBoundsAlgorithm(
|
||||
sim_params=self.sim_params,
|
||||
@@ -2881,7 +2885,8 @@ class TestTradingControls(WithSimParams, WithDataPortal, ZiplineTestCase):
|
||||
env,
|
||||
tempdir,
|
||||
self.sim_params,
|
||||
[0]
|
||||
[0],
|
||||
default_nyse_schedule,
|
||||
)
|
||||
algo = SetAssetDateBoundsAlgorithm(
|
||||
sim_params=self.sim_params,
|
||||
@@ -2907,7 +2912,7 @@ class TestAccountControls(WithDataPortal, WithSimParams, ZiplineTestCase):
|
||||
[100, 100, 100, 300],
|
||||
timedelta(days=1),
|
||||
cls.sim_params,
|
||||
cls.env,
|
||||
default_nyse_schedule,
|
||||
),
|
||||
},
|
||||
index=cls.sim_params.trading_days,
|
||||
@@ -3054,7 +3059,7 @@ class TestFutureFlip(WithSimParams, WithDataPortal, ZiplineTestCase):
|
||||
[1e9, 1e9, 1e9],
|
||||
timedelta(days=1),
|
||||
cls.sim_params,
|
||||
cls.env
|
||||
default_nyse_schedule,
|
||||
),
|
||||
},
|
||||
index=cls.sim_params.trading_days,
|
||||
@@ -3064,7 +3069,7 @@ class TestFutureFlip(WithSimParams, WithDataPortal, ZiplineTestCase):
|
||||
def test_flip_algo(self):
|
||||
metadata = {1: {'symbol': 'TEST',
|
||||
'start_date': self.sim_params.trading_days[0],
|
||||
'end_date': self.env.next_trading_day(
|
||||
'end_date': default_nyse_schedule.next_execution_day(
|
||||
self.sim_params.trading_days[-1]),
|
||||
'multiplier': 5}}
|
||||
|
||||
@@ -3206,7 +3211,7 @@ class TestOrderCancelation(WithDataPortal,
|
||||
sim_params=SimulationParameters(
|
||||
period_start=self.sim_params.period_start,
|
||||
period_end=self.sim_params.period_end,
|
||||
env=self.env,
|
||||
trading_schedule=self.env,
|
||||
data_frequency=data_frequency,
|
||||
emission_rate='minute' if minute_emission else 'daily'
|
||||
)
|
||||
@@ -3419,8 +3424,12 @@ class TestEquityAutoClose(WithTmpDir, ZiplineTestCase):
|
||||
sids = asset_info.index
|
||||
|
||||
env = self.enter_instance_context(tmp_trading_env(equities=asset_info))
|
||||
market_opens = env.open_and_closes.market_open.loc[self.test_days]
|
||||
market_closes = env.open_and_closes.market_close.loc[self.test_days]
|
||||
market_opens = default_nyse_schedule.schedule.market_open.loc[
|
||||
self.test_days
|
||||
]
|
||||
market_closes = default_nyse_schedule.schedule.market_close.loc[
|
||||
self.test_days
|
||||
]
|
||||
|
||||
if frequency == 'daily':
|
||||
dates = self.test_days
|
||||
@@ -3441,12 +3450,12 @@ class TestEquityAutoClose(WithTmpDir, ZiplineTestCase):
|
||||
)
|
||||
reader = BcolzDailyBarReader(path)
|
||||
data_portal = DataPortal(
|
||||
env,
|
||||
env, default_nyse_schedule,
|
||||
first_trading_day=reader.first_trading_day,
|
||||
equity_daily_reader=reader,
|
||||
)
|
||||
elif frequency == 'minute':
|
||||
dates = env.minutes_for_days_in_range(
|
||||
dates = default_nyse_schedule.execution_minutes_for_days_in_range(
|
||||
self.test_days[0],
|
||||
self.test_days[-1],
|
||||
)
|
||||
@@ -3471,7 +3480,7 @@ class TestEquityAutoClose(WithTmpDir, ZiplineTestCase):
|
||||
)
|
||||
reader = BcolzMinuteBarReader(self.tmpdir.path)
|
||||
data_portal = DataPortal(
|
||||
env,
|
||||
env, default_nyse_schedule,
|
||||
first_trading_day=reader.first_trading_day,
|
||||
equity_minute_reader=reader,
|
||||
)
|
||||
@@ -3485,7 +3494,6 @@ class TestEquityAutoClose(WithTmpDir, ZiplineTestCase):
|
||||
end=self.test_days[-1],
|
||||
data_frequency=frequency,
|
||||
emission_rate=frequency,
|
||||
env=env,
|
||||
capital_base=capital_base,
|
||||
)
|
||||
|
||||
@@ -3498,7 +3506,7 @@ class TestEquityAutoClose(WithTmpDir, ZiplineTestCase):
|
||||
else:
|
||||
final_prices = {
|
||||
asset.sid: trade_data_by_sid[asset.sid].loc[
|
||||
env.get_open_and_close(asset.end_date)[1]
|
||||
default_nyse_schedule.start_and_end(asset.end_date)[1]
|
||||
].close
|
||||
for asset in assets
|
||||
}
|
||||
@@ -3852,6 +3860,9 @@ class TestEquityAutoClose(WithTmpDir, ZiplineTestCase):
|
||||
expected_cash.extend([after_second_auto_close] * (390 + 390))
|
||||
expected_position_counts.extend([1] * (390 + 390))
|
||||
|
||||
# Check list lengths first to avoid expensive comparison
|
||||
self.assertEqual(len(algo.cash), len(expected_cash))
|
||||
# TODO find more efficient way to compare these lists
|
||||
self.assertEqual(algo.cash, expected_cash)
|
||||
self.assertEqual(
|
||||
list(output['ending_cash']),
|
||||
@@ -3987,7 +3998,7 @@ class TestOrderAfterDelist(WithTradingEnvironment, ZiplineTestCase):
|
||||
sim_params=SimulationParameters(
|
||||
period_start=pd.Timestamp("2016-01-06", tz='UTC'),
|
||||
period_end=pd.Timestamp("2016-01-07", tz='UTC'),
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
data_frequency="minute"
|
||||
)
|
||||
)
|
||||
|
||||
@@ -83,7 +83,7 @@ from zipline.testing.fixtures import (
|
||||
WithAssetFinder,
|
||||
ZiplineTestCase,
|
||||
)
|
||||
from zipline.utils.tradingcalendar import trading_day
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
|
||||
|
||||
@contextmanager
|
||||
@@ -776,6 +776,7 @@ class AssetFinderTestCase(ZiplineTestCase):
|
||||
|
||||
def test_compute_lifetimes(self):
|
||||
num_assets = 4
|
||||
trading_day = default_nyse_schedule.day
|
||||
first_start = pd.Timestamp('2015-04-01', tz='UTC')
|
||||
|
||||
frame = make_rotating_equity_info(
|
||||
|
||||
+28
-18
@@ -28,6 +28,7 @@ from zipline.testing.fixtures import (
|
||||
WithDataPortal,
|
||||
ZiplineTestCase,
|
||||
)
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
|
||||
OHLC = ["open", "high", "low", "close"]
|
||||
OHLCP = OHLC + ["price"]
|
||||
@@ -165,8 +166,10 @@ class TestMinuteBarData(WithBarDataChecks,
|
||||
|
||||
def test_minute_before_assets_trading(self):
|
||||
# grab minutes that include the day before the asset start
|
||||
minutes = self.env.market_minutes_for_day(
|
||||
self.env.previous_trading_day(self.bcolz_minute_bar_days[0])
|
||||
minutes = self.trading_schedule.execution_minutes_for_day(
|
||||
self.trading_schedule.previous_execution_day(
|
||||
self.bcolz_minute_bar_days[0]
|
||||
)
|
||||
)
|
||||
|
||||
# this entire day is before either asset has started trading
|
||||
@@ -192,8 +195,8 @@ class TestMinuteBarData(WithBarDataChecks,
|
||||
self.assertTrue(asset_value is pd.NaT)
|
||||
|
||||
def test_regular_minute(self):
|
||||
minutes = self.env.market_minutes_for_day(
|
||||
self.bcolz_minute_bar_days[0],
|
||||
minutes = self.trading_schedule.execution_minutes_for_day(
|
||||
self.bcolz_minute_bar_days[0]
|
||||
)
|
||||
|
||||
for idx, minute in enumerate(minutes):
|
||||
@@ -284,7 +287,7 @@ class TestMinuteBarData(WithBarDataChecks,
|
||||
asset2_value)
|
||||
|
||||
def test_minute_of_last_day(self):
|
||||
minutes = self.env.market_minutes_for_day(
|
||||
minutes = self.trading_schedule.execution_minutes_for_day(
|
||||
self.bcolz_daily_bar_days[-1],
|
||||
)
|
||||
|
||||
@@ -296,12 +299,15 @@ class TestMinuteBarData(WithBarDataChecks,
|
||||
self.assertTrue(bar_data.can_trade(self.ASSET2))
|
||||
|
||||
def test_minute_after_assets_stopped(self):
|
||||
minutes = self.env.market_minutes_for_day(
|
||||
self.env.next_trading_day(self.bcolz_minute_bar_days[-1])
|
||||
minutes = self.trading_schedule.execution_minutes_for_day(
|
||||
self.trading_schedule.next_execution_day(
|
||||
self.bcolz_minute_bar_days[-1]
|
||||
)
|
||||
)
|
||||
|
||||
last_trading_minute = \
|
||||
self.env.market_minutes_for_day(self.bcolz_minute_bar_days[-1])[-1]
|
||||
last_trading_minute = self.trading_schedule.execution_minutes_for_day(
|
||||
self.bcolz_minute_bar_days[-1]
|
||||
)[-1]
|
||||
|
||||
# this entire day is after both assets have stopped trading
|
||||
for idx, minute in enumerate(minutes):
|
||||
@@ -341,9 +347,9 @@ class TestMinuteBarData(WithBarDataChecks,
|
||||
)
|
||||
|
||||
# ... but that's it's not applied when using spot value
|
||||
minutes = self.env.minutes_for_days_in_range(
|
||||
minutes = self.trading_schedule.execution_minutes_for_days_in_range(
|
||||
start=self.bcolz_minute_bar_days[0],
|
||||
end=self.bcolz_minute_bar_days[1],
|
||||
end=self.bcolz_minute_bar_days[1]
|
||||
)
|
||||
|
||||
for idx, minute in enumerate(minutes):
|
||||
@@ -356,11 +362,11 @@ class TestMinuteBarData(WithBarDataChecks,
|
||||
def test_spot_price_is_adjusted_if_needed(self):
|
||||
# on cls.days[1], the first 9 minutes of ILLIQUID_SPLIT_ASSET are
|
||||
# missing. let's get them.
|
||||
day0_minutes = self.env.market_minutes_for_day(
|
||||
self.bcolz_minute_bar_days[0],
|
||||
day0_minutes = self.trading_schedule.execution_minutes_for_day(
|
||||
self.bcolz_minute_bar_days[0]
|
||||
)
|
||||
day1_minutes = self.env.market_minutes_for_day(
|
||||
self.bcolz_minute_bar_days[1],
|
||||
day1_minutes = self.trading_schedule.execution_minutes_for_day(
|
||||
self.bcolz_minute_bar_days[1]
|
||||
)
|
||||
|
||||
for idx, minute in enumerate(day0_minutes[-10:-1]):
|
||||
@@ -604,7 +610,7 @@ class TestDailyBarData(WithBarDataChecks,
|
||||
def make_daily_bar_data(cls):
|
||||
for sid in cls.sids:
|
||||
yield sid, create_daily_df_for_asset(
|
||||
cls.env,
|
||||
default_nyse_schedule,
|
||||
cls.bcolz_daily_bar_days[0],
|
||||
cls.bcolz_daily_bar_days[-1],
|
||||
interval=2 - sid % 2
|
||||
@@ -638,7 +644,9 @@ class TestDailyBarData(WithBarDataChecks,
|
||||
|
||||
def test_day_before_assets_trading(self):
|
||||
# use the day before self.bcolz_daily_bar_days[0]
|
||||
day = self.env.previous_trading_day(self.bcolz_daily_bar_days[0])
|
||||
day = self.trading_schedule.previous_execution_day(
|
||||
self.bcolz_daily_bar_days[0]
|
||||
)
|
||||
|
||||
bar_data = BarData(self.data_portal, lambda: day, "daily")
|
||||
self.check_internal_consistency(bar_data)
|
||||
@@ -741,7 +749,9 @@ class TestDailyBarData(WithBarDataChecks,
|
||||
|
||||
def test_after_assets_dead(self):
|
||||
# both assets end on self.day[-1], so let's try the next day
|
||||
next_day = self.env.next_trading_day(self.bcolz_daily_bar_days[-1])
|
||||
next_day = self.trading_schedule.next_execution_day(
|
||||
self.bcolz_daily_bar_days[-1]
|
||||
)
|
||||
|
||||
bar_data = BarData(self.data_portal, lambda: next_day, "daily")
|
||||
self.check_internal_consistency(bar_data)
|
||||
|
||||
@@ -32,6 +32,7 @@ from zipline.testing.fixtures import (
|
||||
WithSimParams,
|
||||
ZiplineTestCase,
|
||||
)
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
|
||||
|
||||
class TestBenchmark(WithDataPortal, WithSimParams, ZiplineTestCase):
|
||||
@@ -85,7 +86,7 @@ class TestBenchmark(WithDataPortal, WithSimParams, ZiplineTestCase):
|
||||
days_to_use = self.sim_params.trading_days[1:]
|
||||
|
||||
source = BenchmarkSource(
|
||||
1, self.env, days_to_use, self.data_portal
|
||||
1, self.env, default_nyse_schedule, days_to_use, self.data_portal
|
||||
)
|
||||
|
||||
# should be the equivalent of getting the price history, then doing
|
||||
@@ -111,6 +112,7 @@ class TestBenchmark(WithDataPortal, WithSimParams, ZiplineTestCase):
|
||||
BenchmarkSource(
|
||||
3,
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.sim_params.trading_days[1:],
|
||||
self.data_portal
|
||||
)
|
||||
@@ -125,6 +127,7 @@ class TestBenchmark(WithDataPortal, WithSimParams, ZiplineTestCase):
|
||||
BenchmarkSource(
|
||||
3,
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.sim_params.trading_days[120:],
|
||||
self.data_portal
|
||||
)
|
||||
@@ -138,7 +141,7 @@ class TestBenchmark(WithDataPortal, WithSimParams, ZiplineTestCase):
|
||||
def test_asset_IPOed_same_day(self):
|
||||
# gotta get some minute data up in here.
|
||||
# add sid 4 for a couple of days
|
||||
minutes = self.env.minutes_for_days_in_range(
|
||||
minutes = default_nyse_schedule.execution_minutes_for_days_in_range(
|
||||
self.sim_params.trading_days[0],
|
||||
self.sim_params.trading_days[5]
|
||||
)
|
||||
@@ -160,6 +163,7 @@ class TestBenchmark(WithDataPortal, WithSimParams, ZiplineTestCase):
|
||||
source = BenchmarkSource(
|
||||
2,
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.sim_params.trading_days,
|
||||
data_portal
|
||||
)
|
||||
@@ -188,7 +192,8 @@ class TestBenchmark(WithDataPortal, WithSimParams, ZiplineTestCase):
|
||||
|
||||
with self.assertRaises(InvalidBenchmarkAsset) as exc:
|
||||
BenchmarkSource(
|
||||
4, self.env, self.sim_params.trading_days, self.data_portal
|
||||
4, self.env, default_nyse_schedule,
|
||||
self.sim_params.trading_days, self.data_portal
|
||||
)
|
||||
|
||||
self.assertEqual("4 cannot be used as the benchmark because it has a "
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
#
|
||||
# Copyright 2016 Quantopian, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# 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 os.path import (
|
||||
abspath,
|
||||
dirname,
|
||||
join,
|
||||
)
|
||||
from unittest import TestCase
|
||||
|
||||
import pandas as pd
|
||||
import pytz
|
||||
from pandas import (
|
||||
read_csv,
|
||||
datetime,
|
||||
Timestamp,
|
||||
Timedelta,
|
||||
date_range,
|
||||
)
|
||||
from pandas.util.testing import assert_frame_equal
|
||||
|
||||
from zipline.utils.calendars.nyse_exchange_calendar import NYSEExchangeCalendar
|
||||
|
||||
|
||||
class ExchangeCalendarTestBase(object):
|
||||
|
||||
# Override in subclasses.
|
||||
answer_key_filename = None
|
||||
calendar_class = None
|
||||
|
||||
@staticmethod
|
||||
def load_answer_key(filename):
|
||||
"""
|
||||
Load a CSV from tests/resources/calendars/{filename}.csv
|
||||
"""
|
||||
fullpath = join(
|
||||
dirname(abspath(__file__)),
|
||||
'resources',
|
||||
'calendars',
|
||||
filename + '.csv',
|
||||
)
|
||||
return read_csv(
|
||||
fullpath,
|
||||
index_col=0,
|
||||
# NOTE: Merely passing parse_dates=True doesn't cause pandas to set
|
||||
# the dtype correctly, and passing all reasonable inputs to the
|
||||
# dtype kwarg cause read_csv to barf.
|
||||
parse_dates=[0, 1, 2],
|
||||
).tz_localize('UTC')
|
||||
|
||||
@classmethod
|
||||
def setupClass(cls):
|
||||
cls.answers = cls.load_answer_key(cls.answer_key_filename)
|
||||
cls.start_date = cls.answers.index[0]
|
||||
cls.end_date = cls.answers.index[-1]
|
||||
cls.calendar = cls.calendar_class(cls.start_date, cls.end_date)
|
||||
|
||||
def test_calculated_against_csv(self):
|
||||
assert_frame_equal(self.calendar.schedule, self.answers)
|
||||
|
||||
def test_is_open_on_minute(self):
|
||||
for market_minute in self.answers.market_open:
|
||||
market_minute_utc = market_minute.tz_localize('UTC')
|
||||
# The exchange should be classified as open on its first minute
|
||||
self.assertTrue(
|
||||
self.calendar.is_open_on_minute(market_minute_utc)
|
||||
)
|
||||
# Decrement minute by one, to minute where the market was not open
|
||||
pre_market = market_minute_utc - pd.Timedelta(minutes=1)
|
||||
self.assertFalse(
|
||||
self.calendar.is_open_on_minute(pre_market)
|
||||
)
|
||||
|
||||
def test_open_and_close(self):
|
||||
for index, row in self.answers.iterrows():
|
||||
o_and_c = self.calendar.open_and_close(index)
|
||||
self.assertEqual(o_and_c[0],
|
||||
row['market_open'].tz_localize('UTC'))
|
||||
self.assertEqual(o_and_c[1],
|
||||
row['market_close'].tz_localize('UTC'))
|
||||
|
||||
def test_no_nones_from_open_and_close(self):
|
||||
"""
|
||||
Ensures that, for all minutes in a week, the open_and_close method
|
||||
never returns a tuple of Nones.
|
||||
"""
|
||||
start_week = Timestamp('11/18/2012 12:00AM', tz='EST')
|
||||
end_week = start_week + Timedelta(days=7)
|
||||
minutes_in_week = date_range(start_week, end_week, freq='Min')
|
||||
|
||||
for dt in minutes_in_week:
|
||||
open, close = self.calendar.open_and_close(dt)
|
||||
self.assertIsNotNone(open, "Open value is None")
|
||||
self.assertIsNotNone(close, "Close value is None")
|
||||
|
||||
# def test_minutes_for_date(self):
|
||||
# for date in self.answers.index:
|
||||
# mins_for_date = self.calendar.minutes_for_date(date)
|
||||
|
||||
def test_minute_window(self):
|
||||
for open in self.answers.market_open:
|
||||
open_tz = open.tz_localize('UTC')
|
||||
window = self.calendar.minute_window(open_tz, 390, 1)
|
||||
self.assertEqual(len(window), 390)
|
||||
|
||||
|
||||
class NYSECalendarTestCase(ExchangeCalendarTestBase, TestCase):
|
||||
|
||||
answer_key_filename = 'nyse'
|
||||
calendar_class = NYSEExchangeCalendar
|
||||
|
||||
def test_newyears(self):
|
||||
"""
|
||||
Check whether tradingcalendar contains certain dates.
|
||||
"""
|
||||
# January 2012
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4 5 6 7
|
||||
# 8 9 10 11 12 13 14
|
||||
# 15 16 17 18 19 20 21
|
||||
# 22 23 24 25 26 27 28
|
||||
# 29 30 31
|
||||
|
||||
start_dt = Timestamp('1/1/12', tz='UTC')
|
||||
end_dt = Timestamp('12/31/13', tz='UTC')
|
||||
trading_days = self.calendar.trading_days(start=start_dt,
|
||||
end=end_dt)
|
||||
|
||||
day_after_new_years_sunday = datetime(
|
||||
2012, 1, 2, tzinfo=pytz.utc)
|
||||
|
||||
self.assertNotIn(day_after_new_years_sunday,
|
||||
trading_days.index,
|
||||
"""
|
||||
If NYE falls on a weekend, {0} the Monday after is a holiday.
|
||||
""".strip().format(day_after_new_years_sunday)
|
||||
)
|
||||
|
||||
first_trading_day_after_new_years_sunday = datetime(
|
||||
2012, 1, 3, tzinfo=pytz.utc)
|
||||
|
||||
self.assertIn(first_trading_day_after_new_years_sunday,
|
||||
trading_days.index,
|
||||
"""
|
||||
If NYE falls on a weekend, {0} the Tuesday after is the first trading day.
|
||||
""".strip().format(first_trading_day_after_new_years_sunday)
|
||||
)
|
||||
|
||||
# January 2013
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4 5
|
||||
# 6 7 8 9 10 11 12
|
||||
# 13 14 15 16 17 18 19
|
||||
# 20 21 22 23 24 25 26
|
||||
# 27 28 29 30 31
|
||||
|
||||
new_years_day = datetime(
|
||||
2013, 1, 1, tzinfo=pytz.utc)
|
||||
|
||||
self.assertNotIn(new_years_day,
|
||||
trading_days.index,
|
||||
"""
|
||||
If NYE falls during the week, e.g. {0}, it is a holiday.
|
||||
""".strip().format(new_years_day)
|
||||
)
|
||||
|
||||
first_trading_day_after_new_years = datetime(
|
||||
2013, 1, 2, tzinfo=pytz.utc)
|
||||
|
||||
self.assertIn(first_trading_day_after_new_years,
|
||||
trading_days.index,
|
||||
"""
|
||||
If the day after NYE falls during the week, {0} \
|
||||
is the first trading day.
|
||||
""".strip().format(first_trading_day_after_new_years)
|
||||
)
|
||||
|
||||
def test_thanksgiving(self):
|
||||
"""
|
||||
Check tradingcalendar Thanksgiving dates.
|
||||
"""
|
||||
# November 2005
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4 5
|
||||
# 6 7 8 9 10 11 12
|
||||
# 13 14 15 16 17 18 19
|
||||
# 20 21 22 23 24 25 26
|
||||
# 27 28 29 30
|
||||
|
||||
start_dt = Timestamp('1/1/05', tz='UTC')
|
||||
end_dt = Timestamp('12/31/12', tz='UTC')
|
||||
trading_days = self.calendar.trading_days(start=start_dt,
|
||||
end=end_dt)
|
||||
|
||||
thanksgiving_with_four_weeks = datetime(
|
||||
2005, 11, 24, tzinfo=pytz.utc)
|
||||
|
||||
self.assertNotIn(thanksgiving_with_four_weeks,
|
||||
trading_days.index,
|
||||
"""
|
||||
If Nov has 4 Thursdays, {0} Thanksgiving is the last Thursady.
|
||||
""".strip().format(thanksgiving_with_four_weeks)
|
||||
)
|
||||
|
||||
# November 2006
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4
|
||||
# 5 6 7 8 9 10 11
|
||||
# 12 13 14 15 16 17 18
|
||||
# 19 20 21 22 23 24 25
|
||||
# 26 27 28 29 30
|
||||
thanksgiving_with_five_weeks = datetime(
|
||||
2006, 11, 23, tzinfo=pytz.utc)
|
||||
|
||||
self.assertNotIn(thanksgiving_with_five_weeks,
|
||||
trading_days.index,
|
||||
"""
|
||||
If Nov has 5 Thursdays, {0} Thanksgiving is not the last week.
|
||||
""".strip().format(thanksgiving_with_five_weeks)
|
||||
)
|
||||
|
||||
first_trading_day_after_new_years_sunday = datetime(
|
||||
2012, 1, 3, tzinfo=pytz.utc)
|
||||
|
||||
self.assertIn(first_trading_day_after_new_years_sunday,
|
||||
trading_days.index,
|
||||
"""
|
||||
If NYE falls on a weekend, {0} the Tuesday after is the first trading day.
|
||||
""".strip().format(first_trading_day_after_new_years_sunday)
|
||||
)
|
||||
|
||||
def test_day_after_thanksgiving(self):
|
||||
# November 2012
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3
|
||||
# 4 5 6 7 8 9 10
|
||||
# 11 12 13 14 15 16 17
|
||||
# 18 19 20 21 22 23 24
|
||||
# 25 26 27 28 29 30
|
||||
fourth_friday_open = Timestamp('11/23/2012 11:00AM', tz='EST')
|
||||
fourth_friday = Timestamp('11/23/2012 3:00PM', tz='EST')
|
||||
self.assertTrue(self.calendar.is_open_on_minute(fourth_friday_open))
|
||||
self.assertFalse(self.calendar.is_open_on_minute(fourth_friday))
|
||||
|
||||
# November 2013
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2
|
||||
# 3 4 5 6 7 8 9
|
||||
# 10 11 12 13 14 15 16
|
||||
# 17 18 19 20 21 22 23
|
||||
# 24 25 26 27 28 29 30
|
||||
fifth_friday_open = Timestamp('11/29/2013 11:00AM', tz='EST')
|
||||
fifth_friday = Timestamp('11/29/2013 3:00PM', tz='EST')
|
||||
self.assertTrue(self.calendar.is_open_on_minute(fifth_friday_open))
|
||||
self.assertFalse(self.calendar.is_open_on_minute(fifth_friday))
|
||||
|
||||
def test_early_close_independence_day_thursday(self):
|
||||
"""
|
||||
Until 2013, the market closed early the Friday after an
|
||||
Independence Day on Thursday. Since then, the early close is on
|
||||
Wednesday.
|
||||
"""
|
||||
# July 2002
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4 5 6
|
||||
# 7 8 9 10 11 12 13
|
||||
# 14 15 16 17 18 19 20
|
||||
# 21 22 23 24 25 26 27
|
||||
# 28 29 30 31
|
||||
wednesday_before = Timestamp('7/3/2002 3:00PM', tz='EST')
|
||||
friday_after_open = Timestamp('7/5/2002 11:00AM', tz='EST')
|
||||
friday_after = Timestamp('7/5/2002 3:00PM', tz='EST')
|
||||
self.assertTrue(self.calendar.is_open_on_minute(wednesday_before))
|
||||
self.assertTrue(self.calendar.is_open_on_minute(friday_after_open))
|
||||
self.assertFalse(self.calendar.is_open_on_minute(friday_after))
|
||||
|
||||
# July 2013
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4 5 6
|
||||
# 7 8 9 10 11 12 13
|
||||
# 14 15 16 17 18 19 20
|
||||
# 21 22 23 24 25 26 27
|
||||
# 28 29 30 31
|
||||
wednesday_before = Timestamp('7/3/2013 3:00PM', tz='EST')
|
||||
friday_after_open = Timestamp('7/5/2013 11:00AM', tz='EST')
|
||||
friday_after = Timestamp('7/5/2013 3:00PM', tz='EST')
|
||||
self.assertFalse(self.calendar.is_open_on_minute(wednesday_before))
|
||||
self.assertTrue(self.calendar.is_open_on_minute(friday_after_open))
|
||||
self.assertTrue(self.calendar.is_open_on_minute(friday_after))
|
||||
@@ -28,6 +28,7 @@ from zipline.testing.fixtures import (
|
||||
WithSimParams,
|
||||
ZiplineTestCase,
|
||||
)
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
from .resources.fetcher_inputs.fetcher_test_data import (
|
||||
AAPL_CSV_DATA,
|
||||
AAPL_IBM_CSV_DATA,
|
||||
@@ -108,7 +109,8 @@ class FetcherTestCase(WithResponses,
|
||||
data_frequency=data_frequency
|
||||
)
|
||||
|
||||
results = test_algo.run(FetcherDataPortal(self.env))
|
||||
results = test_algo.run(FetcherDataPortal(self.env,
|
||||
default_nyse_schedule))
|
||||
|
||||
return results
|
||||
|
||||
@@ -141,7 +143,8 @@ def handle_data(context, data):
|
||||
# manually setting data portal and getting generator because we need
|
||||
# the minutely emission packets here. TradingAlgorithm.run() only
|
||||
# returns daily packets.
|
||||
test_algo.data_portal = FetcherDataPortal(self.env)
|
||||
test_algo.data_portal = FetcherDataPortal(self.env,
|
||||
default_nyse_schedule)
|
||||
gen = test_algo.get_generator()
|
||||
perf_packets = list(gen)
|
||||
|
||||
|
||||
+31
-27
@@ -50,6 +50,10 @@ from zipline.testing.fixtures import (
|
||||
)
|
||||
|
||||
import zipline.utils.factory as factory
|
||||
from zipline.utils.calendars import (
|
||||
default_nyse_schedule,
|
||||
get_calendar,
|
||||
)
|
||||
|
||||
DEFAULT_TIMEOUT = 15 # seconds
|
||||
EXTENDED_TIMEOUT = 90
|
||||
@@ -199,7 +203,7 @@ class FinanceTestCase(WithLogger,
|
||||
data_frequency="minute"
|
||||
)
|
||||
|
||||
minutes = env.market_minute_window(
|
||||
minutes = default_nyse_schedule.minute_window(
|
||||
sim_params.first_open,
|
||||
int((trade_interval.total_seconds() / 60) * trade_count)
|
||||
+ 100)
|
||||
@@ -217,8 +221,9 @@ class FinanceTestCase(WithLogger,
|
||||
}
|
||||
|
||||
write_bcolz_minute_data(
|
||||
env,
|
||||
env.days_in_range(minutes[0], minutes[-1]),
|
||||
default_nyse_schedule,
|
||||
default_nyse_schedule.execution_days_in_range(minutes[0],
|
||||
minutes[-1]),
|
||||
tempdir.path,
|
||||
iteritems(assets),
|
||||
)
|
||||
@@ -226,7 +231,7 @@ class FinanceTestCase(WithLogger,
|
||||
equity_minute_reader = BcolzMinuteBarReader(tempdir.path)
|
||||
|
||||
data_portal = DataPortal(
|
||||
env,
|
||||
env, default_nyse_schedule,
|
||||
first_trading_day=equity_minute_reader.first_trading_day,
|
||||
equity_minute_reader=equity_minute_reader,
|
||||
)
|
||||
@@ -254,7 +259,7 @@ class FinanceTestCase(WithLogger,
|
||||
equity_daily_reader = BcolzDailyBarReader(path)
|
||||
|
||||
data_portal = DataPortal(
|
||||
env,
|
||||
env, default_nyse_schedule,
|
||||
first_trading_day=equity_daily_reader.first_trading_day,
|
||||
equity_daily_reader=equity_daily_reader,
|
||||
)
|
||||
@@ -417,25 +422,25 @@ class TradingEnvironmentTestCase(WithLogger,
|
||||
]
|
||||
|
||||
for holiday in holidays:
|
||||
self.assertTrue(not self.env.is_trading_day(holiday))
|
||||
self.assertTrue(not self.cal.is_open_on_day(holiday))
|
||||
|
||||
first_trading_day = datetime(2008, 1, 2, tzinfo=pytz.utc)
|
||||
last_trading_day = datetime(2008, 12, 31, tzinfo=pytz.utc)
|
||||
workdays = [first_trading_day, last_trading_day]
|
||||
|
||||
for workday in workdays:
|
||||
self.assertTrue(self.env.is_trading_day(workday))
|
||||
self.assertTrue(self.cal.is_open_on_day(workday))
|
||||
|
||||
def test_simulation_parameters(self):
|
||||
env = SimulationParameters(
|
||||
sp = SimulationParameters(
|
||||
period_start=datetime(2008, 1, 1, tzinfo=pytz.utc),
|
||||
period_end=datetime(2008, 12, 31, tzinfo=pytz.utc),
|
||||
capital_base=100000,
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
self.assertTrue(env.last_close.month == 12)
|
||||
self.assertTrue(env.last_close.day == 31)
|
||||
self.assertTrue(sp.last_close.month == 12)
|
||||
self.assertTrue(sp.last_close.day == 31)
|
||||
|
||||
@timed(DEFAULT_TIMEOUT)
|
||||
def test_sim_params_days_in_period(self):
|
||||
@@ -452,7 +457,7 @@ class TradingEnvironmentTestCase(WithLogger,
|
||||
period_start=datetime(2007, 12, 31, tzinfo=pytz.utc),
|
||||
period_end=datetime(2008, 1, 7, tzinfo=pytz.utc),
|
||||
capital_base=100000,
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
expected_trading_days = (
|
||||
@@ -473,7 +478,7 @@ class TradingEnvironmentTestCase(WithLogger,
|
||||
params.trading_days.tolist())
|
||||
|
||||
@timed(DEFAULT_TIMEOUT)
|
||||
def test_market_minute_window(self):
|
||||
def test_minute_window(self):
|
||||
|
||||
# January 2008
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
@@ -488,10 +493,10 @@ class TradingEnvironmentTestCase(WithLogger,
|
||||
|
||||
# 10:01 AM Eastern on January 7th..
|
||||
start = us_east.localize(datetime(2008, 1, 7, 10, 1))
|
||||
utc_start = start.astimezone(utc)
|
||||
utc_start = pd.Timestamp(start.astimezone(utc))
|
||||
|
||||
# Get the next 10 minutes
|
||||
minutes = self.env.market_minute_window(
|
||||
minutes = self.cal.minute_window(
|
||||
utc_start, 10,
|
||||
)
|
||||
self.assertEqual(len(minutes), 10)
|
||||
@@ -499,7 +504,7 @@ class TradingEnvironmentTestCase(WithLogger,
|
||||
self.assertEqual(minutes[i], utc_start + timedelta(minutes=i))
|
||||
|
||||
# Get the previous 10 minutes.
|
||||
minutes = self.env.market_minute_window(
|
||||
minutes = self.cal.minute_window(
|
||||
utc_start, 10, step=-1,
|
||||
)
|
||||
self.assertEqual(len(minutes), 10)
|
||||
@@ -512,14 +517,14 @@ class TradingEnvironmentTestCase(WithLogger,
|
||||
# Today: 10:01 AM -> 4:00 PM (360 minutes)
|
||||
# Tomorrow: 9:31 AM -> 4:00 PM (390 minutes, 750 total)
|
||||
# Last Day: 9:31 AM -> 12:00 PM (150 minutes, 900 total)
|
||||
minutes = self.env.market_minute_window(
|
||||
utc_start, 900,
|
||||
minutes = self.cal.minute_window(
|
||||
start, 900,
|
||||
)
|
||||
today = self.env.market_minutes_for_day(start)[30:]
|
||||
tomorrow = self.env.market_minutes_for_day(
|
||||
today = self.cal.minutes_for_date(utc_start)[30:]
|
||||
tomorrow = self.cal.minutes_for_date(
|
||||
start + timedelta(days=1)
|
||||
)
|
||||
last_day = self.env.market_minutes_for_day(
|
||||
last_day = self.cal.minutes_for_date(
|
||||
start + timedelta(days=2))[:150]
|
||||
|
||||
self.assertEqual(len(minutes), 900)
|
||||
@@ -534,17 +539,17 @@ class TradingEnvironmentTestCase(WithLogger,
|
||||
# Today: 10:01 AM -> 9:31 AM (31 minutes)
|
||||
# Friday: 4:00 PM -> 9:31 AM (390 minutes, 421 total)
|
||||
# Thursday: 4:00 PM -> 9:41 AM (380 minutes, 801 total)
|
||||
minutes = self.env.market_minute_window(
|
||||
utc_start, 801, step=-1,
|
||||
minutes = self.cal.minute_window(
|
||||
start, 801, step=-1,
|
||||
)
|
||||
|
||||
today = self.env.market_minutes_for_day(start)[30::-1]
|
||||
today = self.cal.minutes_for_date(utc_start)[30::-1]
|
||||
# minus an extra two days from each of these to account for the two
|
||||
# weekend days we skipped
|
||||
friday = self.env.market_minutes_for_day(
|
||||
friday = self.cal.minutes_for_date(
|
||||
start + timedelta(days=-3),
|
||||
)[::-1]
|
||||
thursday = self.env.market_minutes_for_day(
|
||||
thursday = self.cal.minutes_for_date(
|
||||
start + timedelta(days=-4),
|
||||
)[:9:-1]
|
||||
|
||||
@@ -566,6 +571,5 @@ class TradingEnvironmentTestCase(WithLogger,
|
||||
max_date = pd.Timestamp('2008-08-01', tz='UTC')
|
||||
env = TradingEnvironment(max_date=max_date)
|
||||
|
||||
self.assertLessEqual(env.last_trading_day, max_date)
|
||||
self.assertLessEqual(env.treasury_curves.index[-1],
|
||||
max_date)
|
||||
|
||||
+33
-26
@@ -24,6 +24,7 @@ from zipline.testing import (
|
||||
str_to_seconds,
|
||||
MockDailyBarReader,
|
||||
)
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
from zipline.testing.fixtures import (
|
||||
WithBcolzMinuteBarReader,
|
||||
WithDataPortal,
|
||||
@@ -78,7 +79,7 @@ class WithHistory(WithDataPortal):
|
||||
@classmethod
|
||||
def init_class_fixtures(cls):
|
||||
super(WithHistory, cls).init_class_fixtures()
|
||||
cls.trading_days = cls.env.days_in_range(
|
||||
cls.trading_days = default_nyse_schedule.execution_days_in_range(
|
||||
start=cls.TRADING_START_DT,
|
||||
end=cls.TRADING_END_DT
|
||||
)
|
||||
@@ -455,14 +456,14 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
for sid in sids:
|
||||
asset = cls.asset_finder.retrieve_asset(sid)
|
||||
data[sid] = create_minute_df_for_asset(
|
||||
cls.env,
|
||||
default_nyse_schedule,
|
||||
asset.start_date,
|
||||
asset.end_date,
|
||||
start_val=2,
|
||||
)
|
||||
|
||||
data[1] = create_minute_df_for_asset(
|
||||
cls.env,
|
||||
default_nyse_schedule,
|
||||
pd.Timestamp('2014-01-03', tz='utc'),
|
||||
pd.Timestamp('2016-01-30', tz='utc'),
|
||||
start_val=2,
|
||||
@@ -509,7 +510,7 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
))
|
||||
asset3 = cls.asset_finder.retrieve_asset(3)
|
||||
data[3] = create_minute_df_for_asset(
|
||||
cls.env,
|
||||
default_nyse_schedule,
|
||||
asset3.start_date,
|
||||
asset3.end_date,
|
||||
start_val=2,
|
||||
@@ -539,7 +540,7 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
capital_base=float('1.0e5'),
|
||||
data_frequency='minute',
|
||||
emission_rate='daily',
|
||||
env=self.env,
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
test_algo = TradingAlgorithm(
|
||||
@@ -678,8 +679,10 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
def test_minute_before_assets_trading(self):
|
||||
# since asset2 and asset3 both started trading on 1/5/2015, let's do
|
||||
# some history windows that are completely before that
|
||||
minutes = self.env.market_minutes_for_day(
|
||||
self.env.previous_trading_day(pd.Timestamp('2015-01-05', tz='UTC'))
|
||||
minutes = default_nyse_schedule.execution_minutes_for_day(
|
||||
default_nyse_schedule.previous_execution_day(
|
||||
pd.Timestamp('2015-01-05', tz='UTC')
|
||||
)
|
||||
)[0:60]
|
||||
|
||||
for idx, minute in enumerate(minutes):
|
||||
@@ -726,7 +729,7 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
# 10 minutes
|
||||
asset = self.env.asset_finder.retrieve_asset(sid)
|
||||
|
||||
minutes = self.env.market_minutes_for_day(
|
||||
minutes = default_nyse_schedule.execution_minutes_for_day(
|
||||
pd.Timestamp('2015-01-05', tz='UTC')
|
||||
)[0:60]
|
||||
|
||||
@@ -737,7 +740,9 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
|
||||
def test_minute_midnight(self):
|
||||
midnight = pd.Timestamp('2015-01-06', tz='UTC')
|
||||
last_minute = self.env.previous_open_and_close(midnight)[1]
|
||||
last_minute = default_nyse_schedule.start_and_end(
|
||||
default_nyse_schedule.previous_execution_day(midnight)
|
||||
)[1]
|
||||
|
||||
midnight_bar_data = \
|
||||
BarData(self.data_portal, lambda: midnight, 'minute')
|
||||
@@ -755,7 +760,7 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
def test_minute_after_asset_stopped(self):
|
||||
# SHORT_ASSET's last day was 2015-01-06
|
||||
# get some history windows that straddle the end
|
||||
minutes = self.env.market_minutes_for_day(
|
||||
minutes = default_nyse_schedule.execution_minutes_for_day(
|
||||
pd.Timestamp('2015-01-07', tz='UTC')
|
||||
)[0:60]
|
||||
|
||||
@@ -850,7 +855,7 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
# before any of the adjustments, last 10 minutes of jan 5
|
||||
window1 = self.data_portal.get_history_window(
|
||||
[asset],
|
||||
self.env.get_open_and_close(jan5)[1],
|
||||
default_nyse_schedule.start_and_end(jan5)[1],
|
||||
10,
|
||||
'1m',
|
||||
'close'
|
||||
@@ -1099,20 +1104,21 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
|
||||
def test_minute_different_lifetimes(self):
|
||||
# at trading start, only asset1 existed
|
||||
day = self.env.next_trading_day(self.TRADING_START_DT)
|
||||
day = default_nyse_schedule.next_execution_day(self.TRADING_START_DT)
|
||||
|
||||
asset1_minutes = self.env.minutes_for_days_in_range(
|
||||
asset1_minutes = \
|
||||
default_nyse_schedule.execution_minutes_for_days_in_range(
|
||||
start=self.ASSET1.start_date,
|
||||
end=self.ASSET1.end_date
|
||||
)
|
||||
|
||||
asset1_idx = asset1_minutes.searchsorted(
|
||||
self.env.get_open_and_close(day)[0]
|
||||
default_nyse_schedule.start_and_end(day)[0]
|
||||
)
|
||||
|
||||
window = self.data_portal.get_history_window(
|
||||
[self.ASSET1, self.ASSET2],
|
||||
self.env.get_open_and_close(day)[0],
|
||||
default_nyse_schedule.start_and_end(day)[0],
|
||||
100,
|
||||
'1m',
|
||||
'close'
|
||||
@@ -1130,7 +1136,7 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
def test_history_window_before_first_trading_day(self):
|
||||
# trading_start is 2/3/2014
|
||||
# get a history window that starts before that, and ends after that
|
||||
first_day_minutes = self.env.market_minutes_for_day(
|
||||
first_day_minutes = default_nyse_schedule.execution_minutes_for_day(
|
||||
self.TRADING_START_DT
|
||||
)
|
||||
exp_msg = (
|
||||
@@ -1150,7 +1156,7 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
|
||||
# January 2015 has both daily and minute data for ASSET2
|
||||
day = pd.Timestamp('2015-01-07', tz='UTC')
|
||||
minutes = self.env.market_minutes_for_day(day)
|
||||
minutes = default_nyse_schedule.execution_minutes_for_day(day)
|
||||
|
||||
# minute data, baseline:
|
||||
# Jan 5: 2 to 391
|
||||
@@ -1214,7 +1220,7 @@ class MinuteEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
|
||||
# January 2015 has both daily and minute data for ASSET2
|
||||
day = pd.Timestamp('2015-01-08', tz='UTC')
|
||||
minutes = self.env.market_minutes_for_day(day)
|
||||
minutes = default_nyse_schedule.execution_minutes_for_day(day)
|
||||
|
||||
# minute data, baseline:
|
||||
# Jan 5: 2 to 391
|
||||
@@ -1333,7 +1339,8 @@ class DailyEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
@classmethod
|
||||
def create_df_for_asset(cls, start_day, end_day, interval=1,
|
||||
force_zeroes=False):
|
||||
days = cls.env.days_in_range(start_day, end_day)
|
||||
days = default_nyse_schedule.execution_days_in_range(start_day,
|
||||
end_day)
|
||||
days_count = len(days)
|
||||
|
||||
# default to 2 because the low array subtracts 1, and we don't
|
||||
@@ -1362,7 +1369,7 @@ class DailyEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
def test_daily_before_assets_trading(self):
|
||||
# asset2 and asset3 both started trading in 2015
|
||||
|
||||
days = self.env.days_in_range(
|
||||
days = default_nyse_schedule.execution_days_in_range(
|
||||
start=pd.Timestamp('2014-12-15', tz='UTC'),
|
||||
end=pd.Timestamp('2014-12-18', tz='UTC'),
|
||||
)
|
||||
@@ -1400,9 +1407,9 @@ class DailyEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
# get the first 30 days of 2015
|
||||
jan5 = pd.Timestamp('2015-01-04')
|
||||
|
||||
days = self.env.days_in_range(
|
||||
days = default_nyse_schedule.execution_days_in_range(
|
||||
start=jan5,
|
||||
end=self.env.add_trading_days(30, jan5)
|
||||
end=default_nyse_schedule.add_execution_days(30, jan5)
|
||||
)
|
||||
|
||||
for idx, day in enumerate(days):
|
||||
@@ -1445,7 +1452,7 @@ class DailyEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
def test_daily_after_asset_stopped(self):
|
||||
# SHORT_ASSET trades on 1/5, 1/6, that's it.
|
||||
|
||||
days = self.env.days_in_range(
|
||||
days = default_nyse_schedule.execution_days_in_range(
|
||||
start=pd.Timestamp('2015-01-07', tz='UTC'),
|
||||
end=pd.Timestamp('2015-01-08', tz='UTC')
|
||||
)
|
||||
@@ -1637,7 +1644,7 @@ class DailyEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
# trading_start is 2/3/2014
|
||||
# get a history window that starts before that, and ends after that
|
||||
|
||||
second_day = self.env.next_trading_day(self.TRADING_START_DT)
|
||||
second_day = default_nyse_schedule.next_execution_day(self.TRADING_START_DT)
|
||||
|
||||
exp_msg = (
|
||||
'History window extends before 2014-01-03. To use this history '
|
||||
@@ -1663,7 +1670,7 @@ class DailyEquityHistoryTestCase(WithHistory, ZiplineTestCase):
|
||||
)[self.ASSET1]
|
||||
|
||||
# Use a minute to force minute mode.
|
||||
first_minute = self.env.open_and_closes.market_open[
|
||||
first_minute = default_nyse_schedule.open_and_closes.market_open[
|
||||
self.TRADING_START_DT]
|
||||
|
||||
with self.assertRaisesRegexp(HistoryWindowStartsBeforeData, exp_msg):
|
||||
@@ -1794,7 +1801,7 @@ class MinuteToDailyAggregationTestCase(WithBcolzMinuteBarReader,
|
||||
# Set up a fresh data portal for each test, since order of calling
|
||||
# needs to be tested.
|
||||
self.equity_daily_aggregator = DailyHistoryAggregator(
|
||||
self.env.open_and_closes.market_open,
|
||||
default_nyse_schedule.schedule.market_open,
|
||||
self.bcolz_minute_bar_reader,
|
||||
)
|
||||
|
||||
|
||||
+68
-41
@@ -59,6 +59,7 @@ from zipline.testing.fixtures import (
|
||||
WithTradingEnvironment,
|
||||
ZiplineTestCase,
|
||||
)
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
|
||||
logger = logging.getLogger('Test Perf Tracking')
|
||||
|
||||
@@ -175,7 +176,9 @@ def calculate_results(sim_params,
|
||||
splits = splits or {}
|
||||
commissions = commissions or {}
|
||||
|
||||
perf_tracker = perf.PerformanceTracker(sim_params, env)
|
||||
perf_tracker = perf.PerformanceTracker(sim_params,
|
||||
default_nyse_schedule,
|
||||
env)
|
||||
|
||||
results = []
|
||||
|
||||
@@ -240,7 +243,9 @@ def setup_env_data(env, sim_params, sids, futures_sids=[]):
|
||||
for sid in sids:
|
||||
data[sid] = {
|
||||
"start_date": sim_params.trading_days[0],
|
||||
"end_date": env.next_trading_day(sim_params.trading_days[-1])
|
||||
"end_date": default_nyse_schedule.next_execution_day(
|
||||
sim_params.trading_days[-1]
|
||||
)
|
||||
}
|
||||
|
||||
env.write_data(equities_data=data)
|
||||
@@ -249,7 +254,9 @@ def setup_env_data(env, sim_params, sids, futures_sids=[]):
|
||||
for future_sid in futures_sids:
|
||||
futures_data[future_sid] = {
|
||||
"start_date": sim_params.trading_days[0],
|
||||
"end_date": env.next_trading_day(sim_params.trading_days[-1]),
|
||||
"end_date": default_nyse_schedule.next_execution_day(
|
||||
sim_params.trading_days[-1]
|
||||
),
|
||||
"multiplier": 100
|
||||
}
|
||||
|
||||
@@ -271,7 +278,9 @@ class TestSplitPerformance(WithSimParams, WithTmpDir, ZiplineTestCase):
|
||||
def test_multiple_splits(self):
|
||||
# if multiple positions all have splits at the same time, verify that
|
||||
# the total leftover cash is correct
|
||||
perf_tracker = perf.PerformanceTracker(self.sim_params, self.env)
|
||||
perf_tracker = perf.PerformanceTracker(self.sim_params,
|
||||
default_nyse_schedule,
|
||||
self.env)
|
||||
|
||||
asset1 = self.asset_finder.retrieve_asset(1)
|
||||
asset2 = self.asset_finder.retrieve_asset(2)
|
||||
@@ -300,13 +309,14 @@ class TestSplitPerformance(WithSimParams, WithTmpDir, ZiplineTestCase):
|
||||
[100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
# set up a long position in sid 1
|
||||
# 100 shares at $20 apiece = $2000 position
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.tmpdir,
|
||||
self.sim_params,
|
||||
{1: events},
|
||||
@@ -411,7 +421,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
after = factory.get_next_trading_dt(
|
||||
before,
|
||||
timedelta(days=1),
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
)
|
||||
self.assertEqual(after.hour, 13)
|
||||
|
||||
@@ -423,7 +433,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
dbpath = self.instance_tmpdir.getpath('adjustments.sqlite')
|
||||
@@ -431,7 +441,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
writer = SQLiteAdjustmentWriter(
|
||||
dbpath,
|
||||
MockDailyBarReader(),
|
||||
self.env.trading_days,
|
||||
default_nyse_schedule.all_execution_days,
|
||||
)
|
||||
splits = mergers = create_empty_splits_mergers_frame()
|
||||
dividends = pd.DataFrame({
|
||||
@@ -446,6 +456,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
adjustment_reader = SQLiteAdjustmentReader(dbpath)
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: events},
|
||||
@@ -488,7 +499,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
dbpath = self.instance_tmpdir.getpath('adjustments.sqlite')
|
||||
@@ -496,7 +507,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
writer = SQLiteAdjustmentWriter(
|
||||
dbpath,
|
||||
MockDailyBarReader(),
|
||||
self.env.trading_days,
|
||||
default_nyse_schedule.all_execution_days,
|
||||
)
|
||||
splits = mergers = create_empty_splits_mergers_frame()
|
||||
dividends = pd.DataFrame({
|
||||
@@ -522,6 +533,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
events,
|
||||
@@ -562,7 +574,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
dbpath = self.instance_tmpdir.getpath('adjustments.sqlite')
|
||||
@@ -570,7 +582,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
writer = SQLiteAdjustmentWriter(
|
||||
dbpath,
|
||||
MockDailyBarReader(),
|
||||
self.env.trading_days,
|
||||
default_nyse_schedule.all_execution_days,
|
||||
)
|
||||
splits = mergers = create_empty_splits_mergers_frame()
|
||||
dividends = pd.DataFrame({
|
||||
@@ -586,6 +598,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: events},
|
||||
@@ -623,7 +636,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
dbpath = self.instance_tmpdir.getpath('adjustments.sqlite')
|
||||
@@ -631,7 +644,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
writer = SQLiteAdjustmentWriter(
|
||||
dbpath,
|
||||
MockDailyBarReader(),
|
||||
self.env.trading_days,
|
||||
default_nyse_schedule.all_execution_days,
|
||||
)
|
||||
splits = mergers = create_empty_splits_mergers_frame()
|
||||
dividends = pd.DataFrame({
|
||||
@@ -647,6 +660,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: events},
|
||||
@@ -685,14 +699,14 @@ class TestDividendPerformance(WithSimParams,
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
dbpath = self.instance_tmpdir.getpath('adjustments.sqlite')
|
||||
|
||||
writer = SQLiteAdjustmentWriter(
|
||||
dbpath,
|
||||
MockDailyBarReader(),
|
||||
self.env.trading_days,
|
||||
default_nyse_schedule.all_execution_days,
|
||||
)
|
||||
splits = mergers = create_empty_splits_mergers_frame()
|
||||
|
||||
@@ -709,6 +723,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: events},
|
||||
@@ -745,20 +760,21 @@ class TestDividendPerformance(WithSimParams,
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
pay_date = self.sim_params.first_open
|
||||
# find pay date that is much later.
|
||||
for i in range(30):
|
||||
pay_date = factory.get_next_trading_dt(pay_date, oneday, self.env)
|
||||
pay_date = factory.get_next_trading_dt(pay_date, oneday,
|
||||
default_nyse_schedule)
|
||||
|
||||
dbpath = self.instance_tmpdir.getpath('adjustments.sqlite')
|
||||
|
||||
writer = SQLiteAdjustmentWriter(
|
||||
dbpath,
|
||||
MockDailyBarReader(),
|
||||
self.env.trading_days,
|
||||
default_nyse_schedule.all_execution_days,
|
||||
)
|
||||
splits = mergers = create_empty_splits_mergers_frame()
|
||||
dividends = pd.DataFrame({
|
||||
@@ -774,6 +790,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: events},
|
||||
@@ -811,7 +828,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
dbpath = self.instance_tmpdir.getpath('adjustments.sqlite')
|
||||
@@ -819,7 +836,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
writer = SQLiteAdjustmentWriter(
|
||||
dbpath,
|
||||
MockDailyBarReader(),
|
||||
self.env.trading_days,
|
||||
default_nyse_schedule.all_execution_days,
|
||||
)
|
||||
splits = mergers = create_empty_splits_mergers_frame()
|
||||
dividends = pd.DataFrame({
|
||||
@@ -835,6 +852,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: events},
|
||||
@@ -869,7 +887,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
dbpath = self.instance_tmpdir.getpath('adjustments.sqlite')
|
||||
@@ -877,7 +895,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
writer = SQLiteAdjustmentWriter(
|
||||
dbpath,
|
||||
MockDailyBarReader(),
|
||||
self.env.trading_days,
|
||||
default_nyse_schedule.all_execution_days,
|
||||
)
|
||||
splits = mergers = create_empty_splits_mergers_frame()
|
||||
dividends = pd.DataFrame({
|
||||
@@ -893,6 +911,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: events},
|
||||
@@ -925,7 +944,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
dbpath = self.instance_tmpdir.getpath('adjustments.sqlite')
|
||||
@@ -933,7 +952,7 @@ class TestDividendPerformance(WithSimParams,
|
||||
writer = SQLiteAdjustmentWriter(
|
||||
dbpath,
|
||||
MockDailyBarReader(),
|
||||
self.env.trading_days,
|
||||
default_nyse_schedule.all_execution_days,
|
||||
)
|
||||
splits = mergers = create_empty_splits_mergers_frame()
|
||||
dividends = pd.DataFrame({
|
||||
@@ -942,8 +961,9 @@ class TestDividendPerformance(WithSimParams,
|
||||
'declared_date': np.array([events[-3].dt], dtype='datetime64[ns]'),
|
||||
'ex_date': np.array([events[-2].dt], dtype='datetime64[ns]'),
|
||||
'record_date': np.array([events[0].dt], dtype='datetime64[ns]'),
|
||||
'pay_date': np.array([self.env.next_trading_day(events[-1].dt)],
|
||||
dtype='datetime64[ns]'),
|
||||
'pay_date': np.array(
|
||||
[default_nyse_schedule.next_execution_day(events[-1].dt)],
|
||||
dtype='datetime64[ns]'),
|
||||
})
|
||||
writer.write(splits, mergers, dividends)
|
||||
adjustment_reader = SQLiteAdjustmentReader(dbpath)
|
||||
@@ -957,10 +977,11 @@ class TestDividendPerformance(WithSimParams,
|
||||
)
|
||||
|
||||
sim_params.period_end = events[-1].dt
|
||||
sim_params.update_internal_from_env(self.env)
|
||||
sim_params.update_internal_from_trading_schedule(default_nyse_schedule)
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
sim_params,
|
||||
{1: events},
|
||||
@@ -1049,7 +1070,7 @@ class TestPositionPerformance(WithInstanceTmpDir, ZiplineTestCase):
|
||||
[100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
trades_2 = factory.create_trade_history(
|
||||
@@ -1058,11 +1079,12 @@ class TestPositionPerformance(WithInstanceTmpDir, ZiplineTestCase):
|
||||
[100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: trades_1, 2: trades_2}
|
||||
@@ -1154,11 +1176,12 @@ class TestPositionPerformance(WithInstanceTmpDir, ZiplineTestCase):
|
||||
[100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: trades})
|
||||
@@ -1245,11 +1268,12 @@ class TestPositionPerformance(WithInstanceTmpDir, ZiplineTestCase):
|
||||
[100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: trades})
|
||||
@@ -1360,13 +1384,14 @@ single short-sale transaction"""
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
trades_1 = trades[:-2]
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: trades})
|
||||
@@ -1593,11 +1618,12 @@ cost of sole txn in test"
|
||||
[100, 100, 100, 100],
|
||||
oneday,
|
||||
sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{3: trades}
|
||||
@@ -1712,11 +1738,12 @@ single short-sale transaction"""
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{3: trades}
|
||||
@@ -1956,11 +1983,12 @@ trade after cover"""
|
||||
[100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: trades})
|
||||
@@ -2042,13 +2070,14 @@ shares in position"
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
self.env
|
||||
default_nyse_schedule,
|
||||
)
|
||||
trades = factory.create_trade_history(*history_args)
|
||||
transactions = factory.create_txn_history(*history_args)[:4]
|
||||
|
||||
data_portal = create_data_portal_from_trade_history(
|
||||
self.env,
|
||||
default_nyse_schedule,
|
||||
self.instance_tmpdir,
|
||||
self.sim_params,
|
||||
{1: trades})
|
||||
@@ -2167,7 +2196,7 @@ shares in position"
|
||||
[200, -100, -100, 100, -300, 100, 500, 400],
|
||||
oneday,
|
||||
self.sim_params,
|
||||
self.env
|
||||
default_nyse_schedule,
|
||||
)
|
||||
cost_bases = [10, 10, 0, 8, 9, 9, 13, 13.5]
|
||||
|
||||
@@ -2318,9 +2347,7 @@ class TestPositionTracker(WithTradingEnvironment,
|
||||
Originally this bug was due to np.dot([], []) returning
|
||||
np.bool_(False)
|
||||
"""
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
num_days=4, env=self.env
|
||||
)
|
||||
sim_params = factory.create_simulation_parameters(num_days=4)
|
||||
|
||||
pt = perf.PositionTracker(self.env.asset_finder,
|
||||
sim_params.data_frequency)
|
||||
|
||||
@@ -18,6 +18,7 @@ from zipline.utils.security_list import (
|
||||
SecurityListSet,
|
||||
load_from_directory,
|
||||
)
|
||||
from zipline.utils.calendars import default_nyse_schedule
|
||||
|
||||
LEVERAGED_ETFS = load_from_directory('leveraged_etf_list')
|
||||
|
||||
@@ -87,7 +88,7 @@ class SecurityListTestCase(WithLogger, ZiplineTestCase):
|
||||
cls.sim_params = factory.create_simulation_parameters(
|
||||
start=start,
|
||||
num_days=4,
|
||||
env=cls.env
|
||||
trading_schedule=default_nyse_schedule
|
||||
)
|
||||
|
||||
cls.sim_params2 = sp2 = factory.create_simulation_parameters(
|
||||
@@ -110,13 +111,15 @@ class SecurityListTestCase(WithLogger, ZiplineTestCase):
|
||||
tempdir=cls.tempdir,
|
||||
sim_params=cls.sim_params,
|
||||
sids=range(0, 5),
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
cls.data_portal2 = create_data_portal(
|
||||
env=cls.env2,
|
||||
tempdir=cls.tempdir2,
|
||||
sim_params=cls.sim_params2,
|
||||
sids=range(0, 5)
|
||||
sids=range(0, 5),
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
def test_iterate_over_restricted_list(self):
|
||||
@@ -212,14 +215,14 @@ class SecurityListTestCase(WithLogger, ZiplineTestCase):
|
||||
def test_algo_with_rl_violation_after_knowledge_date(self):
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=list(
|
||||
LEVERAGED_ETFS.keys())[0] + timedelta(days=7), num_days=5,
|
||||
env=self.env)
|
||||
LEVERAGED_ETFS.keys())[0] + timedelta(days=7), num_days=5)
|
||||
|
||||
data_portal = create_data_portal(
|
||||
self.env,
|
||||
self.tempdir,
|
||||
sim_params=sim_params,
|
||||
sids=range(0, 5)
|
||||
sids=range(0, 5),
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
algo = RestrictedAlgoWithoutCheck(symbol='BZQ',
|
||||
@@ -270,7 +273,8 @@ class SecurityListTestCase(WithLogger, ZiplineTestCase):
|
||||
env,
|
||||
new_tempdir,
|
||||
sim_params,
|
||||
range(0, 5)
|
||||
range(0, 5),
|
||||
trading_schedule=default_nyse_schedule,
|
||||
)
|
||||
|
||||
algo = RestrictedAlgoWithoutCheck(
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from pandas import (
|
||||
Timestamp,
|
||||
date_range,
|
||||
)
|
||||
|
||||
from zipline.utils.calendars import (
|
||||
get_calendar,
|
||||
ExchangeTradingSchedule,
|
||||
normalize_date,
|
||||
)
|
||||
|
||||
|
||||
class TestExchangeTradingSchedule(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.nyse_cal = get_calendar('NYSE')
|
||||
cls.nyse_exchange_schedule = ExchangeTradingSchedule(cal=cls.nyse_cal)
|
||||
|
||||
def test_nyse_data_availability_time(self):
|
||||
"""
|
||||
Ensure that the NYSE schedule's data availability time is the market
|
||||
open.
|
||||
"""
|
||||
# This is a time on the day after Thanksgiving when the market was open
|
||||
test_dt = Timestamp('11/23/2012 11:00AM', tz='EST')
|
||||
test_date = normalize_date(test_dt)
|
||||
desired_data_time = Timestamp('11/23/2012 9:31AM', tz='EST')
|
||||
|
||||
# Get the data availability time from the NYSE schedule
|
||||
data_time = self.nyse_exchange_schedule.data_availability_time(
|
||||
date=test_date
|
||||
)
|
||||
|
||||
# Check the schedule answer against the hard-coded answer
|
||||
self.assertEqual(data_time, desired_data_time,
|
||||
"Data availability time is not the market open")
|
||||
|
||||
def test_nyse_execution_time(self):
|
||||
"""
|
||||
Runs a series of times through both the NYSE calendar and NYSE
|
||||
schedule, ensuring that the schedule and calendar agree.
|
||||
"""
|
||||
# Get all of the minutes in a 24-hour day
|
||||
start_range = Timestamp('11/23/2012 12:00AM', tz='EST')
|
||||
end_range = Timestamp('11/23/2012 11:59PM', tz='EST')
|
||||
time_range = date_range(start_range, end_range, freq='Min')
|
||||
|
||||
for dt in time_range:
|
||||
cal_open = self.nyse_cal.is_open_on_minute(dt)
|
||||
sched_exec = self.nyse_exchange_schedule.is_executing_on_minute(dt)
|
||||
self.assertEqual(
|
||||
cal_open, sched_exec,
|
||||
"Mismatch between schedule: %s and calendar: %s at time %s"
|
||||
% (cal_open, sched_exec, dt)
|
||||
)
|
||||
@@ -1,265 +0,0 @@
|
||||
#
|
||||
# Copyright 2013 Quantopian, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# 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 unittest import TestCase
|
||||
from zipline.utils import tradingcalendar
|
||||
from zipline.utils import tradingcalendar_lse
|
||||
from zipline.utils import tradingcalendar_tse
|
||||
from zipline.utils import tradingcalendar_bmf
|
||||
import pytz
|
||||
import datetime
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
from nose.tools import nottest
|
||||
|
||||
|
||||
class TestTradingCalendar(TestCase):
|
||||
|
||||
def test_calendar_vs_environment(self):
|
||||
"""
|
||||
test_calendar_vs_environment checks whether the
|
||||
historical data from yahoo matches our rule based system.
|
||||
handy, if not canonical, reference:
|
||||
http://www.chronos-st.org/NYSE_Observed_Holidays-1885-Present.html
|
||||
"""
|
||||
|
||||
env = TradingEnvironment()
|
||||
bench_days = env.benchmark_returns[tradingcalendar.start:].index
|
||||
bounds = env.trading_days.slice_locs(start=tradingcalendar.start,
|
||||
end=bench_days[-1])
|
||||
env_days = env.trading_days[bounds[0]:bounds[1]]
|
||||
self.check_days(env_days, bench_days)
|
||||
|
||||
@nottest
|
||||
def test_lse_calendar_vs_environment(self):
|
||||
env = TradingEnvironment(
|
||||
bm_symbol='^FTSE',
|
||||
exchange_tz='Europe/London'
|
||||
)
|
||||
|
||||
env_start_index = \
|
||||
env.trading_days.searchsorted(tradingcalendar_lse.start)
|
||||
env_days = env.trading_days[env_start_index:]
|
||||
cal_days = tradingcalendar_lse.trading_days
|
||||
self.check_days(env_days, cal_days)
|
||||
|
||||
@nottest
|
||||
def test_tse_calendar_vs_environment(self):
|
||||
env = TradingEnvironment(
|
||||
bm_symbol='^GSPTSE',
|
||||
exchange_tz='US/Eastern'
|
||||
)
|
||||
|
||||
env_start_index = \
|
||||
env.trading_days.searchsorted(tradingcalendar_tse.start)
|
||||
env_days = env.trading_days[env_start_index:]
|
||||
cal_days = tradingcalendar_tse.trading_days
|
||||
self.check_days(env_days, cal_days)
|
||||
|
||||
@nottest
|
||||
def test_bmf_calendar_vs_environment(self):
|
||||
env = TradingEnvironment(
|
||||
bm_symbol='^BVSP',
|
||||
exchange_tz='America/Sao_Paulo'
|
||||
)
|
||||
|
||||
env_start_index = \
|
||||
env.trading_days.searchsorted(tradingcalendar_bmf.start)
|
||||
env_days = env.trading_days[env_start_index:]
|
||||
cal_days = tradingcalendar_bmf.trading_days
|
||||
self.check_days(env_days, cal_days)
|
||||
|
||||
def check_days(self, env_days, cal_days):
|
||||
diff = env_days.difference(cal_days)
|
||||
self.assertEqual(
|
||||
len(diff),
|
||||
0,
|
||||
"{diff} should be empty".format(diff=diff)
|
||||
)
|
||||
|
||||
diff2 = cal_days.difference(env_days)
|
||||
self.assertEqual(
|
||||
len(diff2),
|
||||
0,
|
||||
"{diff} should be empty".format(diff=diff2)
|
||||
)
|
||||
|
||||
def test_newyears(self):
|
||||
"""
|
||||
Check whether tradingcalendar contains certain dates.
|
||||
"""
|
||||
# January 2012
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4 5 6 7
|
||||
# 8 9 10 11 12 13 14
|
||||
# 15 16 17 18 19 20 21
|
||||
# 22 23 24 25 26 27 28
|
||||
# 29 30 31
|
||||
|
||||
day_after_new_years_sunday = datetime.datetime(
|
||||
2012, 1, 2, tzinfo=pytz.utc)
|
||||
|
||||
self.assertNotIn(day_after_new_years_sunday,
|
||||
tradingcalendar.trading_days,
|
||||
"""
|
||||
If NYE falls on a weekend, {0} the Monday after is a holiday.
|
||||
""".strip().format(day_after_new_years_sunday)
|
||||
)
|
||||
|
||||
first_trading_day_after_new_years_sunday = datetime.datetime(
|
||||
2012, 1, 3, tzinfo=pytz.utc)
|
||||
|
||||
self.assertIn(first_trading_day_after_new_years_sunday,
|
||||
tradingcalendar.trading_days,
|
||||
"""
|
||||
If NYE falls on a weekend, {0} the Tuesday after is the first trading day.
|
||||
""".strip().format(first_trading_day_after_new_years_sunday)
|
||||
)
|
||||
|
||||
# January 2013
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4 5
|
||||
# 6 7 8 9 10 11 12
|
||||
# 13 14 15 16 17 18 19
|
||||
# 20 21 22 23 24 25 26
|
||||
# 27 28 29 30 31
|
||||
|
||||
new_years_day = datetime.datetime(
|
||||
2013, 1, 1, tzinfo=pytz.utc)
|
||||
|
||||
self.assertNotIn(new_years_day,
|
||||
tradingcalendar.trading_days,
|
||||
"""
|
||||
If NYE falls during the week, e.g. {0}, it is a holiday.
|
||||
""".strip().format(new_years_day)
|
||||
)
|
||||
|
||||
first_trading_day_after_new_years = datetime.datetime(
|
||||
2013, 1, 2, tzinfo=pytz.utc)
|
||||
|
||||
self.assertIn(first_trading_day_after_new_years,
|
||||
tradingcalendar.trading_days,
|
||||
"""
|
||||
If the day after NYE falls during the week, {0} \
|
||||
is the first trading day.
|
||||
""".strip().format(first_trading_day_after_new_years)
|
||||
)
|
||||
|
||||
def test_thanksgiving(self):
|
||||
"""
|
||||
Check tradingcalendar Thanksgiving dates.
|
||||
"""
|
||||
# November 2005
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4 5
|
||||
# 6 7 8 9 10 11 12
|
||||
# 13 14 15 16 17 18 19
|
||||
# 20 21 22 23 24 25 26
|
||||
# 27 28 29 30
|
||||
thanksgiving_with_four_weeks = datetime.datetime(
|
||||
2005, 11, 24, tzinfo=pytz.utc)
|
||||
|
||||
self.assertNotIn(thanksgiving_with_four_weeks,
|
||||
tradingcalendar.trading_days,
|
||||
"""
|
||||
If Nov has 4 Thursdays, {0} Thanksgiving is the last Thursady.
|
||||
""".strip().format(thanksgiving_with_four_weeks)
|
||||
)
|
||||
|
||||
# November 2006
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4
|
||||
# 5 6 7 8 9 10 11
|
||||
# 12 13 14 15 16 17 18
|
||||
# 19 20 21 22 23 24 25
|
||||
# 26 27 28 29 30
|
||||
thanksgiving_with_five_weeks = datetime.datetime(
|
||||
2006, 11, 23, tzinfo=pytz.utc)
|
||||
|
||||
self.assertNotIn(thanksgiving_with_five_weeks,
|
||||
tradingcalendar.trading_days,
|
||||
"""
|
||||
If Nov has 5 Thursdays, {0} Thanksgiving is not the last week.
|
||||
""".strip().format(thanksgiving_with_five_weeks)
|
||||
)
|
||||
|
||||
first_trading_day_after_new_years_sunday = datetime.datetime(
|
||||
2012, 1, 3, tzinfo=pytz.utc)
|
||||
|
||||
self.assertIn(first_trading_day_after_new_years_sunday,
|
||||
tradingcalendar.trading_days,
|
||||
"""
|
||||
If NYE falls on a weekend, {0} the Tuesday after is the first trading day.
|
||||
""".strip().format(first_trading_day_after_new_years_sunday)
|
||||
)
|
||||
|
||||
def test_day_after_thanksgiving(self):
|
||||
early_closes = tradingcalendar.get_early_closes(
|
||||
tradingcalendar.start,
|
||||
tradingcalendar.end.replace(year=tradingcalendar.end.year + 1)
|
||||
)
|
||||
|
||||
# November 2012
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3
|
||||
# 4 5 6 7 8 9 10
|
||||
# 11 12 13 14 15 16 17
|
||||
# 18 19 20 21 22 23 24
|
||||
# 25 26 27 28 29 30
|
||||
fourth_friday = datetime.datetime(2012, 11, 23, tzinfo=pytz.utc)
|
||||
self.assertIn(fourth_friday, early_closes)
|
||||
|
||||
# November 2013
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2
|
||||
# 3 4 5 6 7 8 9
|
||||
# 10 11 12 13 14 15 16
|
||||
# 17 18 19 20 21 22 23
|
||||
# 24 25 26 27 28 29 30
|
||||
fifth_friday = datetime.datetime(2013, 11, 29, tzinfo=pytz.utc)
|
||||
self.assertIn(fifth_friday, early_closes)
|
||||
|
||||
def test_early_close_independence_day_thursday(self):
|
||||
"""
|
||||
Until 2013, the market closed early the Friday after an
|
||||
Independence Day on Thursday. Since then, the early close is on
|
||||
Wednesday.
|
||||
"""
|
||||
early_closes = tradingcalendar.get_early_closes(
|
||||
tradingcalendar.start,
|
||||
tradingcalendar.end.replace(year=tradingcalendar.end.year + 1)
|
||||
)
|
||||
# July 2002
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4 5 6
|
||||
# 7 8 9 10 11 12 13
|
||||
# 14 15 16 17 18 19 20
|
||||
# 21 22 23 24 25 26 27
|
||||
# 28 29 30 31
|
||||
wednesday_before = datetime.datetime(2002, 7, 3, tzinfo=pytz.utc)
|
||||
friday_after = datetime.datetime(2002, 7, 5, tzinfo=pytz.utc)
|
||||
self.assertNotIn(wednesday_before, early_closes)
|
||||
self.assertIn(friday_after, early_closes)
|
||||
|
||||
# July 2013
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4 5 6
|
||||
# 7 8 9 10 11 12 13
|
||||
# 14 15 16 17 18 19 20
|
||||
# 21 22 23 24 25 26 27
|
||||
# 28 29 30 31
|
||||
wednesday_before = datetime.datetime(2013, 7, 3, tzinfo=pytz.utc)
|
||||
friday_after = datetime.datetime(2013, 7, 5, tzinfo=pytz.utc)
|
||||
self.assertIn(wednesday_before, early_closes)
|
||||
self.assertNotIn(friday_after, early_closes)
|
||||
+29
-44
@@ -28,6 +28,7 @@ from six.moves import range, map
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
from zipline.testing import subtest, parameter_space
|
||||
import zipline.utils.events
|
||||
from zipline.utils.calendars import get_calendar
|
||||
from zipline.utils.events import (
|
||||
EventRule,
|
||||
StatelessRule,
|
||||
@@ -165,7 +166,7 @@ class TestEventManager(TestCase):
|
||||
class CountingRule(Always):
|
||||
count = 0
|
||||
|
||||
def should_trigger(self, dt, env):
|
||||
def should_trigger(self, dt):
|
||||
CountingRule.count += 1
|
||||
return True
|
||||
|
||||
@@ -174,9 +175,7 @@ class TestEventManager(TestCase):
|
||||
Event(r(), lambda context, data: None)
|
||||
)
|
||||
|
||||
mock_algo_class = namedtuple('FakeAlgo', ['trading_environment'])
|
||||
mock_algo = mock_algo_class(trading_environment="fake_env")
|
||||
self.em.handle_data(mock_algo, None, datetime.datetime.now())
|
||||
self.em.handle_data(None, None, datetime.datetime.now())
|
||||
|
||||
self.assertEqual(CountingRule.count, 5)
|
||||
|
||||
@@ -188,7 +187,7 @@ class TestEventRule(TestCase):
|
||||
|
||||
def test_not_implemented(self):
|
||||
with self.assertRaises(NotImplementedError):
|
||||
super(Always, Always()).should_trigger('a', env=None)
|
||||
super(Always, Always()).should_trigger('a')
|
||||
|
||||
|
||||
def minutes_for_days(ordered_days=False):
|
||||
@@ -207,7 +206,7 @@ def minutes_for_days(ordered_days=False):
|
||||
Iterating over this yields a single day, iterating over the day yields
|
||||
the minutes for that day.
|
||||
"""
|
||||
env = TradingEnvironment()
|
||||
cal = get_calendar('NYSE')
|
||||
random.seed('deterministic')
|
||||
if ordered_days:
|
||||
# Get a list of 500 trading days, in order. As a performance
|
||||
@@ -223,16 +222,15 @@ def minutes_for_days(ordered_days=False):
|
||||
# Other than AfterOpen and BeforeClose, we don't rely on the the nature
|
||||
# of the clock, so we don't care.
|
||||
def day_picker(day):
|
||||
return random.choice(env.trading_days[:-1])
|
||||
return random.choice(cal.all_trading_days[:-1])
|
||||
|
||||
return ((env.market_minutes_for_day(day_picker(cnt)),)
|
||||
return ((cal.trading_minutes_for_day(day_picker(cnt)),)
|
||||
for cnt in range(500))
|
||||
|
||||
|
||||
class RuleTestCase(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
# On the AfterOpen and BeforeClose tests, we want ensure that the
|
||||
# functions are pure, and that running them with the same input will
|
||||
# provide the same output, regardless of whether the function is run 1
|
||||
@@ -244,9 +242,6 @@ class RuleTestCase(TestCase):
|
||||
cls.after_open = AfterOpen(hours=1, minutes=5)
|
||||
cls.class_ = None # Mark that this is the base class.
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
del cls.env
|
||||
|
||||
def test_completeness(self):
|
||||
"""
|
||||
@@ -280,32 +275,31 @@ class TestStatelessRules(RuleTestCase):
|
||||
|
||||
cls.class_ = StatelessRule
|
||||
|
||||
cls.sept_days = cls.env.days_in_range(
|
||||
cls.nyse_cal = get_calendar('NYSE')
|
||||
|
||||
cls.sept_days = cls.nyse_cal.trading_days_in_range(
|
||||
pd.Timestamp('2014-09-01'),
|
||||
pd.Timestamp('2014-09-30'),
|
||||
)
|
||||
|
||||
cls.sept_week = cls.env.minutes_for_days_in_range(
|
||||
cls.sept_week = cls.nyse_cal.trading_minutes_for_days_in_range(
|
||||
datetime.date(year=2014, month=9, day=21),
|
||||
datetime.date(year=2014, month=9, day=26),
|
||||
)
|
||||
|
||||
@subtest(minutes_for_days(), 'ms')
|
||||
def test_Always(self, ms):
|
||||
should_trigger = partial(Always().should_trigger, env=self.env)
|
||||
should_trigger = Always().should_trigger
|
||||
self.assertTrue(all(map(should_trigger, ms)))
|
||||
|
||||
@subtest(minutes_for_days(), 'ms')
|
||||
def test_Never(self, ms):
|
||||
should_trigger = partial(Never().should_trigger, env=self.env)
|
||||
should_trigger = Never().should_trigger
|
||||
self.assertFalse(any(map(should_trigger, ms)))
|
||||
|
||||
@subtest(minutes_for_days(ordered_days=True), 'ms')
|
||||
def test_AfterOpen(self, ms):
|
||||
should_trigger = partial(
|
||||
self.after_open.should_trigger,
|
||||
env=self.env,
|
||||
)
|
||||
should_trigger = self.after_open.should_trigger
|
||||
for i, m in enumerate(ms):
|
||||
# Should only trigger at the 64th minute
|
||||
if i != 64:
|
||||
@@ -316,10 +310,7 @@ class TestStatelessRules(RuleTestCase):
|
||||
@subtest(minutes_for_days(ordered_days=True), 'ms')
|
||||
def test_BeforeClose(self, ms):
|
||||
ms = list(ms)
|
||||
should_trigger = partial(
|
||||
self.before_close.should_trigger,
|
||||
env=self.env
|
||||
)
|
||||
should_trigger = self.before_close.should_trigger
|
||||
for m in ms:
|
||||
# Should only trigger at the 65th-to-last minute
|
||||
if m != ms[-66]:
|
||||
@@ -329,7 +320,7 @@ class TestStatelessRules(RuleTestCase):
|
||||
|
||||
@subtest(minutes_for_days(), 'ms')
|
||||
def test_NotHalfDay(self, ms):
|
||||
should_trigger = partial(NotHalfDay().should_trigger, env=self.env)
|
||||
should_trigger = NotHalfDay().should_trigger
|
||||
self.assertTrue(should_trigger(FULL_DAY))
|
||||
self.assertFalse(should_trigger(HALF_DAY))
|
||||
|
||||
@@ -340,14 +331,13 @@ class TestStatelessRules(RuleTestCase):
|
||||
"""
|
||||
self.assertTrue(
|
||||
NthTradingDayOfWeek(0).should_trigger(
|
||||
self.env.trading_days[0], self.env
|
||||
self.nyse_cal.all_trading_days[0]
|
||||
)
|
||||
)
|
||||
|
||||
@subtest(param_range(MAX_WEEK_RANGE), 'n')
|
||||
def test_NthTradingDayOfWeek(self, n):
|
||||
should_trigger = partial(NthTradingDayOfWeek(n).should_trigger,
|
||||
env=self.env)
|
||||
should_trigger = NthTradingDayOfWeek(n).should_trigger
|
||||
prev_day = self.sept_week[0].date()
|
||||
n_tdays = 0
|
||||
for m in self.sept_week:
|
||||
@@ -362,17 +352,15 @@ class TestStatelessRules(RuleTestCase):
|
||||
|
||||
@subtest(param_range(MAX_WEEK_RANGE), 'n')
|
||||
def test_NDaysBeforeLastTradingDayOfWeek(self, n):
|
||||
should_trigger = partial(
|
||||
NDaysBeforeLastTradingDayOfWeek(n).should_trigger, env=self.env
|
||||
)
|
||||
should_trigger = NDaysBeforeLastTradingDayOfWeek(n).should_trigger
|
||||
for m in self.sept_week:
|
||||
if should_trigger(m):
|
||||
n_tdays = 0
|
||||
date = m.to_datetime().date()
|
||||
next_date = self.env.next_trading_day(date)
|
||||
next_date = self.nyse_cal.next_trading_day(date)
|
||||
while next_date.weekday() > date.weekday():
|
||||
date = next_date
|
||||
next_date = self.env.next_trading_day(date)
|
||||
next_date = self.nyse_cal.next_trading_day(date)
|
||||
n_tdays += 1
|
||||
|
||||
self.assertEqual(n_tdays, n)
|
||||
@@ -486,10 +474,9 @@ class TestStatelessRules(RuleTestCase):
|
||||
|
||||
@subtest(param_range(MAX_MONTH_RANGE), 'n')
|
||||
def test_NthTradingDayOfMonth(self, n):
|
||||
should_trigger = partial(NthTradingDayOfMonth(n).should_trigger,
|
||||
env=self.env)
|
||||
should_trigger = NthTradingDayOfMonth(n).should_trigger
|
||||
for n_tdays, d in enumerate(self.sept_days):
|
||||
for m in self.env.market_minutes_for_day(d):
|
||||
for m in self.nyse_cal.trading_minutes_for_day(d):
|
||||
if should_trigger(m):
|
||||
self.assertEqual(n_tdays, n)
|
||||
else:
|
||||
@@ -497,11 +484,9 @@ class TestStatelessRules(RuleTestCase):
|
||||
|
||||
@subtest(param_range(MAX_MONTH_RANGE), 'n')
|
||||
def test_NDaysBeforeLastTradingDayOfMonth(self, n):
|
||||
should_trigger = partial(
|
||||
NDaysBeforeLastTradingDayOfMonth(n).should_trigger, env=self.env
|
||||
)
|
||||
should_trigger = NDaysBeforeLastTradingDayOfMonth(n).should_trigger
|
||||
for n_days_before, d in enumerate(reversed(self.sept_days)):
|
||||
for m in self.env.market_minutes_for_day(d):
|
||||
for m in self.nyse_cal.trading_minutes_for_day(d):
|
||||
if should_trigger(m):
|
||||
self.assertEqual(n_days_before, n)
|
||||
else:
|
||||
@@ -513,7 +498,7 @@ class TestStatelessRules(RuleTestCase):
|
||||
rule2 = Never()
|
||||
|
||||
composed = rule1 & rule2
|
||||
should_trigger = partial(composed.should_trigger, env=self.env)
|
||||
should_trigger = composed.should_trigger
|
||||
self.assertIsInstance(composed, ComposedRule)
|
||||
self.assertIs(composed.first, rule1)
|
||||
self.assertIs(composed.second, rule2)
|
||||
@@ -536,14 +521,14 @@ class TestStatefulRules(RuleTestCase):
|
||||
"""
|
||||
count = 0
|
||||
|
||||
def should_trigger(self, dt, env):
|
||||
st = self.rule.should_trigger(dt, env)
|
||||
def should_trigger(self, dt):
|
||||
st = self.rule.should_trigger(dt)
|
||||
if st:
|
||||
self.count += 1
|
||||
return st
|
||||
|
||||
rule = RuleCounter(OncePerDay())
|
||||
for m in ms:
|
||||
rule.should_trigger(m, env=self.env)
|
||||
rule.should_trigger(m)
|
||||
|
||||
self.assertEqual(rule.count, 1)
|
||||
|
||||
Reference in New Issue
Block a user