From 99f6ecab3feabb9d2de27e41ef15975b955d8cf1 Mon Sep 17 00:00:00 2001 From: Andrew Liang Date: Wed, 28 Sep 2016 15:21:36 -0400 Subject: [PATCH] MAINT: Deprecate `set_do_not_order_list` In favor of a new method `set_restrictions` which takes a Restrictions object. Calls to `set_do_not_order_list` should raise a deprecation warning and create an equivalent Restrictions object, with which `set_restrictions` will be called. For convenience, create a RestrictionsSet from which the "restrictions" version of a security list can be accessed --- tests/test_algorithm.py | 44 ++++++++++++++++++++++++---------- tests/test_security_list.py | 30 ++++++++++++++++++----- zipline/algorithm.py | 42 +++++++++++++++++++++++++++----- zipline/test_algorithms.py | 6 +++++ zipline/utils/security_list.py | 5 ++++ 5 files changed, 103 insertions(+), 24 deletions(-) diff --git a/tests/test_algorithm.py b/tests/test_algorithm.py index 32d5e8bc..a448f714 100644 --- a/tests/test_algorithm.py +++ b/tests/test_algorithm.py @@ -79,6 +79,7 @@ from zipline.finance.trading import SimulationParameters from zipline.finance.restrictions import ( Restriction, HistoricalRestrictions, + StaticRestrictions, RESTRICTION_STATES, ) from zipline.testing import ( @@ -127,6 +128,7 @@ from zipline.test_algorithms import ( SetMaxOrderCountAlgorithm, SetMaxOrderSizeAlgorithm, SetDoNotOrderListAlgorithm, + SetAssetRestrictionsAlgorithm, SetMaxLeverageAlgorithm, api_algo, api_get_environment_algo, @@ -2793,14 +2795,14 @@ class TestTradingControls(WithSimParams, WithDataPortal, ZiplineTestCase): env=self.env) self.check_algo_fails(algo, handle_data, 0) - def test_set_do_not_order_list(self): + def test_set_asset_restrictions(self): def handle_data(algo, data): algo.could_trade = data.can_trade(algo.sid(self.sid)) algo.order(algo.sid(self.sid), 100) algo.order_count += 1 - # set the restricted list to be one sid for the entire simulation, + # Set HistoricalRestrictions for one sid for the entire simulation, # and fail. rlm = HistoricalRestrictions([ Restriction( @@ -2808,20 +2810,20 @@ class TestTradingControls(WithSimParams, WithDataPortal, ZiplineTestCase): self.sim_params.start_session, RESTRICTION_STATES.FROZEN) ]) - algo = SetDoNotOrderListAlgorithm( + algo = SetAssetRestrictionsAlgorithm( sid=self.sid, - restricted_list=rlm, + restrictions=rlm, sim_params=self.sim_params, env=self.env, ) self.check_algo_fails(algo, handle_data, 0) self.assertFalse(algo.could_trade) - # if the restricted list is a static list, then use a shim. - rlm = [self.sid] - algo = SetDoNotOrderListAlgorithm( + # Set StaticRestrictions for one sid and fail. + rlm = StaticRestrictions([self.sid]) + algo = SetAssetRestrictionsAlgorithm( sid=self.sid, - restricted_list=rlm, + restrictions=rlm, sim_params=self.sim_params, env=self.env, ) @@ -2829,9 +2831,9 @@ class TestTradingControls(WithSimParams, WithDataPortal, ZiplineTestCase): self.assertFalse(algo.could_trade) # just log an error on the violation if we choose not to fail. - algo = SetDoNotOrderListAlgorithm( + algo = SetAssetRestrictionsAlgorithm( sid=self.sid, - restricted_list=rlm, + restrictions=rlm, sim_params=self.sim_params, env=self.env, on_error='log' @@ -2851,14 +2853,32 @@ class TestTradingControls(WithSimParams, WithDataPortal, ZiplineTestCase): self.sim_params.start_session, RESTRICTION_STATES.FROZEN) for sid in [134, 135, 136] ]) + algo = SetAssetRestrictionsAlgorithm( + sid=self.sid, + restrictions=rlm, + sim_params=self.sim_params, + env=self.env, + ) + self.check_algo_succeeds(algo, handle_data) + self.assertTrue(algo.could_trade) + + def test_set_do_not_order_list(self): + + def handle_data(algo, data): + algo.could_trade = data.can_trade(algo.sid(self.sid)) + algo.order(algo.sid(self.sid), 100) + algo.order_count += 1 + + rlm = [self.sid] algo = SetDoNotOrderListAlgorithm( sid=self.sid, restricted_list=rlm, sim_params=self.sim_params, env=self.env, ) - self.check_algo_succeeds(algo, handle_data) - self.assertTrue(algo.could_trade) + + self.check_algo_fails(algo, handle_data, 0) + self.assertFalse(algo.could_trade) def test_set_max_order_size(self): diff --git a/tests/test_security_list.py b/tests/test_security_list.py index 6dd975c9..b381adc3 100644 --- a/tests/test_security_list.py +++ b/tests/test_security_list.py @@ -2,6 +2,7 @@ from datetime import timedelta import pandas as pd from testfixtures import TempDirectory +from nose_parameterized import parameterized from zipline.algorithm import TradingAlgorithm from zipline.errors import TradingControlViolation @@ -29,7 +30,7 @@ LEVERAGED_ETFS = load_from_directory('leveraged_etf_list') class RestrictedAlgoWithCheck(TradingAlgorithm): def initialize(self, symbol): self.rl = SecurityListSet(self.get_datetime, self.asset_finder) - self.set_do_not_order_list(self.rl.leveraged_etf_list) + self.set_asset_restrictions(self.rl.restrict_leveraged_etfs) self.order_count = 0 self.sid = self.symbol(symbol) @@ -43,6 +44,18 @@ class RestrictedAlgoWithCheck(TradingAlgorithm): class RestrictedAlgoWithoutCheck(TradingAlgorithm): + def initialize(self, symbol): + self.rl = SecurityListSet(self.get_datetime, self.asset_finder) + self.set_asset_restrictions(self.rl.restrict_leveraged_etfs) + self.order_count = 0 + self.sid = self.symbol(symbol) + + def handle_data(self, data): + self.order(self.sid, 100) + self.order_count += 1 + + +class RestrictedAlgoWithoutCheckSetDoNotOrderList(TradingAlgorithm): def initialize(self, symbol): self.rl = SecurityListSet(self.get_datetime, self.asset_finder) self.set_do_not_order_list(self.rl.leveraged_etf_list) @@ -57,7 +70,7 @@ class RestrictedAlgoWithoutCheck(TradingAlgorithm): class IterateRLAlgo(TradingAlgorithm): def initialize(self, symbol): self.rl = SecurityListSet(self.get_datetime, self.asset_finder) - self.set_do_not_order_list(self.rl.leveraged_etf_list) + self.set_asset_restrictions(self.rl.restrict_leveraged_etfs) self.order_count = 0 self.sid = self.symbol(symbol) self.found = False @@ -213,10 +226,15 @@ class SecurityListTestCase(WithLogger, WithTradingCalendars, ZiplineTestCase): env=self.env) algo.run(self.data_portal) - def test_algo_with_rl_violation(self): - algo = RestrictedAlgoWithoutCheck(symbol='BZQ', - sim_params=self.sim_params, - env=self.env) + @parameterized.expand([ + ('using_set_do_not_order_list', + RestrictedAlgoWithoutCheckSetDoNotOrderList), + ('using_set_restrictions', RestrictedAlgoWithoutCheck), + ]) + def test_algo_with_rl_violation(self, name, algo_class): + algo = algo_class(symbol='BZQ', + sim_params=self.sim_params, + env=self.env) with self.assertRaises(TradingControlViolation) as ctx: algo.run(self.data_portal) diff --git a/zipline/algorithm.py b/zipline/algorithm.py index d5dc429f..324f247a 100644 --- a/zipline/algorithm.py +++ b/zipline/algorithm.py @@ -2173,15 +2173,45 @@ class TradingAlgorithm(object): restricted_list : container[Asset], SecurityList The assets that cannot be ordered. """ + if isinstance(restricted_list, SecurityList): + warnings.warn( + "`set_do_not_order_list(security_lists.leveraged_etf_list)` " + "is deprecated. Use `set_asset_restrictions(" + "security_lists.restrict_leveraged_etfs)` instead.", + category=ZiplineDeprecationWarning, + stacklevel=2 + ) + restrictions = SecurityListRestrictions(restricted_list) + else: + warnings.warn( + "`set_do_not_order_list(container_of_assets)` is deprecated. " + "Create a zipline.finance.restrictions.StaticRestrictions " + "object with a container of assets and use " + "`set_asset_restrictions(StaticRestrictions(" + "container_of_assets))` instead.", + category=ZiplineDeprecationWarning, + stacklevel=2 + ) + restrictions = StaticRestrictions(restricted_list) - if isinstance(restricted_list, (list, tuple, set)): - restricted_list = StaticRestrictions(restricted_list) - elif isinstance(restricted_list, SecurityList): - restricted_list = SecurityListRestrictions(restricted_list) + self.set_asset_restrictions(restrictions, on_error) - control = RestrictedListOrder(on_error, restricted_list) + @api_method + @expect_types( + restrictions=Restrictions, + on_error=str, + ) + def set_asset_restrictions(self, restrictions, on_error='fail'): + """Set a restriction on which assets can be ordered. + + Parameters + ---------- + restricted_list : container[Asset], SecurityList, Restrictions + The assets that cannot be ordered. + """ + control = RestrictedListOrder(on_error, restrictions) self.register_trading_control(control) - self.restrictions = restricted_list + self.restrictions = restrictions @api_method def set_long_only(self, on_error='fail'): diff --git a/zipline/test_algorithms.py b/zipline/test_algorithms.py index 052dd821..41121195 100644 --- a/zipline/test_algorithms.py +++ b/zipline/test_algorithms.py @@ -510,6 +510,12 @@ class SetDoNotOrderListAlgorithm(TradingAlgorithm): self.set_do_not_order_list(restricted_list, on_error) +class SetAssetRestrictionsAlgorithm(TradingAlgorithm): + def initialize(self, sid=None, restrictions=None, on_error='fail'): + self.order_count = 0 + self.set_asset_restrictions(restrictions, on_error) + + class SetMaxOrderCountAlgorithm(TradingAlgorithm): def initialize(self, count): self.order_count = 0 diff --git a/zipline/utils/security_list.py b/zipline/utils/security_list.py index 8532d3fb..e871dedd 100644 --- a/zipline/utils/security_list.py +++ b/zipline/utils/security_list.py @@ -8,6 +8,7 @@ import pytz import zipline from zipline.errors import SymbolNotFound +from zipline.finance.restrictions import SecurityListRestrictions from zipline.zipline_warnings import ZiplineDeprecationWarning @@ -114,6 +115,10 @@ class SecurityListSet(object): ) return self._leveraged_etf + @property + def restrict_leveraged_etfs(self): + return SecurityListRestrictions(self.leveraged_etf_list) + def load_from_directory(list_name): """