diff --git a/tests/test_execution_styles.py b/tests/test_execution_styles.py index 3ae60de5..5f567886 100644 --- a/tests/test_execution_styles.py +++ b/tests/test_execution_styles.py @@ -62,7 +62,19 @@ class ExecutionStyleTestCase(TestCase): for delta in range(1, 10) ] - INVALID_PRICES = [(-1,), (-1.0,), (0 - epsilon,), (float('nan'),)] + class ArbitraryObject(): + def __str__(self): + return """This should yield a bad order error when + passed as a stop or limit price.""" + + INVALID_PRICES = [ + (-1,), + (-1.0,), + (0 - epsilon,), + (float('nan'),), + (float('inf'),), + (ArbitraryObject(),), + ] def setUp(self): setup_logger(self) diff --git a/zipline/finance/execution.py b/zipline/finance/execution.py index 23ce52bb..4423e60b 100644 --- a/zipline/finance/execution.py +++ b/zipline/finance/execution.py @@ -21,7 +21,7 @@ from six import with_metaclass import zipline.utils.math_utils as zp_math -from math import isnan +from numpy import isfinite from zipline.errors import BadOrderParameters @@ -82,16 +82,8 @@ class LimitOrder(ExecutionStyle): Store the given price. """ - if isnan(limit_price): - raise BadOrderParameters( - msg="""Attempted to place an order with a limit price - of NaN.""" - ) + check_stoplimit_prices(limit_price, 'limit') - if limit_price < 0: - raise BadOrderParameters( - msg="Can't place a limit with a negative price." - ) self.limit_price = limit_price self._exchange = exchange @@ -112,16 +104,8 @@ class StopOrder(ExecutionStyle): Store the given price. """ - if isnan(stop_price): - raise BadOrderParameters( - msg="""Attempted to place an order with a stop price - of NaN.""" - ) + check_stoplimit_prices(stop_price, 'stop') - if stop_price < 0: - raise BadOrderParameters( - msg="Can't place a stop order with a negative price." - ) self.stop_price = stop_price self._exchange = exchange @@ -142,25 +126,9 @@ class StopLimitOrder(ExecutionStyle): Store the given prices """ - if isnan(limit_price): - raise BadOrderParameters( - msg="""Attempted to place an order with a limit price - of NaN.""" - ) - if isnan(stop_price): - raise BadOrderParameters( - msg="""Attempted to place an order with a stop price - of NaN.""" - ) + check_stoplimit_prices(limit_price, 'limit') - if limit_price < 0: - raise BadOrderParameters( - msg="Can't place a limit with a negative price." - ) - if stop_price < 0: - raise BadOrderParameters( - msg="Can't place a stop order with a negative price." - ) + check_stoplimit_prices(stop_price, 'stop') self.limit_price = limit_price self.stop_price = stop_price @@ -201,3 +169,28 @@ def asymmetric_round_price_to_penny(price, prefer_round_down, if zp_math.tolerant_equals(rounded, 0.0): return 0.0 return rounded + + +def check_stoplimit_prices(price, label): + """ + Check to make sure the stop/limit prices are reasonable and raise + a BadOrderParameters exception if not. + """ + try: + if not isfinite(price): + raise BadOrderParameters( + msg="""Attempted to place an order with a {} price + of {}.""".format(label, price) + ) + # This catches arbitrary objects + except TypeError: + raise BadOrderParameters( + msg="""Attempted to place an order with a {} price + of {}.""".format(label, type(price)) + ) + + if price < 0: + raise BadOrderParameters( + msg="""Can't place a {} order + with a negative price.""".format(label) + )