def _test_pipeline_output_after_initialize(self): """ Assert that calling pipeline_output after initialize raises correctly. """ def initialize(context): attach_pipeline(Pipeline(), 'test') pipeline_output('test') raise AssertionError("Shouldn't make it past pipeline_output()") def handle_data(context, data): raise AssertionError("Shouldn't make it past initialize!") def before_trading_start(context, data): raise AssertionError("Shouldn't make it past initialize!") algo = TradingAlgorithm( initialize=initialize, handle_data=handle_data, before_trading_start=before_trading_start, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.first_asset_start - self.trading_day, end=self.last_asset_end + self.trading_day, env=self.env, ) with self.assertRaises(PipelineOutputDuringInitialize): algo.run(self.data_portal)
def _test_get_output_nonexistent_pipeline(self): """ Assert that calling add_pipeline after initialize raises appropriately. """ def initialize(context): attach_pipeline(Pipeline(), 'test') def handle_data(context, data): raise AssertionError("Shouldn't make it past before_trading_start") def before_trading_start(context, data): pipeline_output('not_test') raise AssertionError("Shouldn't make it past pipeline_output!") algo = TradingAlgorithm( initialize=initialize, handle_data=handle_data, before_trading_start=before_trading_start, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.first_asset_start - self.trading_day, end=self.last_asset_end + self.trading_day, env=self.env, ) with self.assertRaises(NoSuchPipeline): algo.run(self.data_portal)
def test_get_output_nonexistent_pipeline(self): """ Assert that calling add_pipeline after initialize raises appropriately. """ def initialize(context): attach_pipeline(Pipeline(), 'test') def handle_data(context, data): raise AssertionError("Shouldn't make it past before_trading_start") def before_trading_start(context, data): pipeline_output('not_test') raise AssertionError("Shouldn't make it past pipeline_output!") algo = TradingAlgorithm( initialize=initialize, handle_data=handle_data, before_trading_start=before_trading_start, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.first_asset_start - self.trading_day, end=self.last_asset_end + self.trading_day, env=self.env, ) with self.assertRaises(NoSuchPipeline): algo.run(self.data_portal)
def test_pipeline_output_after_initialize(self): """ Assert that calling pipeline_output after initialize raises correctly. """ def initialize(context): attach_pipeline(Pipeline(), 'test') pipeline_output('test') raise AssertionError("Shouldn't make it past pipeline_output()") def handle_data(context, data): raise AssertionError("Shouldn't make it past initialize!") def before_trading_start(context, data): raise AssertionError("Shouldn't make it past initialize!") algo = TradingAlgorithm( initialize=initialize, handle_data=handle_data, before_trading_start=before_trading_start, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.first_asset_start - self.trading_day, end=self.last_asset_end + self.trading_day, env=self.env, ) with self.assertRaises(PipelineOutputDuringInitialize): algo.run(self.data_portal)
def test_assets_appear_on_correct_days(self, test_name, chunks): """ Assert that assets appear at correct times during a backtest, with correctly-adjusted close price values. """ if chunks == 'all_but_one_day': chunks = ( self.dates.get_loc(self.last_asset_end) - self.dates.get_loc(self.first_asset_start) ) - 1 elif chunks == 'custom_iter': chunks = [] st = np.random.RandomState(12345) remaining = ( self.dates.get_loc(self.last_asset_end) - self.dates.get_loc(self.first_asset_start) ) while remaining > 0: chunk = st.randint(3) chunks.append(chunk) remaining -= chunk def initialize(context): p = attach_pipeline(Pipeline(), 'test', chunks=chunks) p.add(USEquityPricing.close.latest, 'close') def handle_data(context, data): results = pipeline_output('test') date = get_datetime().normalize() for asset in self.assets: # Assets should appear iff they exist today and yesterday. exists_today = self.exists(date, asset) existed_yesterday = self.exists(date - self.trading_day, asset) if exists_today and existed_yesterday: latest = results.loc[asset, 'close'] self.assertEqual(latest, self.expected_close(date, asset)) else: self.assertNotIn(asset, results.index) before_trading_start = handle_data algo = TradingAlgorithm( initialize=initialize, handle_data=handle_data, before_trading_start=before_trading_start, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.first_asset_start, end=self.last_asset_end, env=self.env, ) # Run for a week in the middle of our data. algo.run(self.data_portal)
def _test_assets_appear_on_correct_days(self, test_name, chunks): """ Assert that assets appear at correct times during a backtest, with correctly-adjusted close price values. """ if chunks == 'all_but_one_day': chunks = (self.dates.get_loc(self.last_asset_end) - self.dates.get_loc(self.first_asset_start)) - 1 elif chunks == 'custom_iter': chunks = [] st = np.random.RandomState(12345) remaining = (self.dates.get_loc(self.last_asset_end) - self.dates.get_loc(self.first_asset_start)) while remaining > 0: chunk = st.randint(3) chunks.append(chunk) remaining -= chunk def initialize(context): p = attach_pipeline(Pipeline(), 'test', chunks=chunks) p.add(USEquityPricing.close.latest, 'close') def handle_data(context, data): results = pipeline_output('test') date = get_datetime().normalize() for asset in self.assets: # Assets should appear iff they exist today and yesterday. exists_today = self.exists(date, asset) existed_yesterday = self.exists(date - self.trading_day, asset) if exists_today and existed_yesterday: latest = results.loc[asset, 'close'] self.assertEqual(latest, self.expected_close(date, asset)) else: self.assertNotIn(asset, results.index) before_trading_start = handle_data algo = TradingAlgorithm( initialize=initialize, handle_data=handle_data, before_trading_start=before_trading_start, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.first_asset_start, end=self.last_asset_end, env=self.env, ) # Run for a week in the middle of our data. algo.run(self.data_portal)
def test_pipeline_beyond_daily_bars(self): """ Ensure that we can run an algo with pipeline beyond the max date of the daily bars. """ # For ensuring we call before_trading_start. count = [0] current_day = self.trading_calendar.next_session_label( self.pipeline_loader.raw_price_loader.last_available_dt, ) def initialize(context): pipeline = attach_pipeline(Pipeline(), 'test') vwap = VWAP(window_length=10) pipeline.add(vwap, 'vwap') # Nothing should have prices less than 0. pipeline.set_screen(vwap < 0) def handle_data(context, data): pass def before_trading_start(context, data): context.results = pipeline_output('test') self.assertTrue(context.results.empty) count[0] += 1 algo = TradingAlgorithm( initialize=initialize, handle_data=handle_data, before_trading_start=before_trading_start, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.dates[0], end=current_day, env=self.env, ) algo.run( FakeDataPortal(self.env), overwrite_sim_params=False, ) self.assertTrue(count[0] > 0)
def _test_attach_pipeline_after_initialize(self): """ Assert that calling attach_pipeline after initialize raises correctly. """ def initialize(context): pass def late_attach(context, data): attach_pipeline(Pipeline(), 'test') raise AssertionError("Shouldn't make it past attach_pipeline!") algo = TradingAlgorithm( initialize=initialize, handle_data=late_attach, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.first_asset_start - self.trading_day, end=self.last_asset_end + self.trading_day, env=self.env, ) with self.assertRaises(AttachPipelineAfterInitialize): algo.run(self.data_portal) def barf(context, data): raise AssertionError("Shouldn't make it past before_trading_start") algo = TradingAlgorithm( initialize=initialize, before_trading_start=late_attach, handle_data=barf, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.first_asset_start - self.trading_day, end=self.last_asset_end + self.trading_day, env=self.env, ) with self.assertRaises(AttachPipelineAfterInitialize): algo.run(self.data_portal)
def test_attach_pipeline_after_initialize(self): """ Assert that calling attach_pipeline after initialize raises correctly. """ def initialize(context): pass def late_attach(context, data): attach_pipeline(Pipeline(), 'test') raise AssertionError("Shouldn't make it past attach_pipeline!") algo = TradingAlgorithm( initialize=initialize, handle_data=late_attach, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.first_asset_start - self.trading_day, end=self.last_asset_end + self.trading_day, env=self.env, ) with self.assertRaises(AttachPipelineAfterInitialize): algo.run(self.data_portal) def barf(context, data): raise AssertionError("Shouldn't make it past before_trading_start") algo = TradingAlgorithm( initialize=initialize, before_trading_start=late_attach, handle_data=barf, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.first_asset_start - self.trading_day, end=self.last_asset_end + self.trading_day, env=self.env, ) with self.assertRaises(AttachPipelineAfterInitialize): algo.run(self.data_portal)
def test_empty_pipeline(self): # For ensuring we call before_trading_start. count = [0] def initialize(context): pipeline = attach_pipeline(Pipeline(), 'test') vwap = VWAP(window_length=10) pipeline.add(vwap, 'vwap') # Nothing should have prices less than 0. pipeline.set_screen(vwap < 0) def handle_data(context, data): pass def before_trading_start(context, data): context.results = pipeline_output('test') self.assertTrue(context.results.empty) count[0] += 1 algo = TradingAlgorithm( initialize=initialize, handle_data=handle_data, before_trading_start=before_trading_start, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.dates[0], end=self.dates[-1], env=self.env, ) algo.run( FakeDataPortal(self.env), overwrite_sim_params=False, ) self.assertTrue(count[0] > 0)
def test_handle_adjustment(self, set_screen): AAPL, MSFT, BRK_A = assets = self.assets window_lengths = [1, 2, 5, 10] vwaps = self.compute_expected_vwaps(window_lengths) def vwap_key(length): return "vwap_%d" % length def initialize(context): pipeline = Pipeline() context.vwaps = [] for length in vwaps: name = vwap_key(length) factor = VWAP(window_length=length) context.vwaps.append(factor) pipeline.add(factor, name=name) filter_ = (USEquityPricing.close.latest > 300) pipeline.add(filter_, 'filter') if set_screen: pipeline.set_screen(filter_) attach_pipeline(pipeline, 'test') def handle_data(context, data): today = normalize_date(get_datetime()) results = pipeline_output('test') expect_over_300 = { AAPL: today < self.AAPL_split_date, MSFT: False, BRK_A: True, } for asset in assets: should_pass_filter = expect_over_300[asset] if set_screen and not should_pass_filter: self.assertNotIn(asset, results.index) continue asset_results = results.loc[asset] self.assertEqual(asset_results['filter'], should_pass_filter) for length in vwaps: computed = results.loc[asset, vwap_key(length)] expected = vwaps[length][asset].loc[today] # Only having two places of precision here is a bit # unfortunate. assert_almost_equal(computed, expected, decimal=2) # Do the same checks in before_trading_start before_trading_start = handle_data algo = TradingAlgorithm( initialize=initialize, handle_data=handle_data, before_trading_start=before_trading_start, data_frequency='daily', get_pipeline_loader=lambda column: self.pipeline_loader, start=self.dates[max(window_lengths)], end=self.dates[-1], env=self.env, ) algo.run( FakeDataPortal(self.env), # Yes, I really do want to use the start and end dates I passed to # TradingAlgorithm. overwrite_sim_params=False, )