mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-03 22:22:34 +08:00
Merge pull request #385 from quantopian/exception-on-nan-order-value
BUG: StopLimit better bad value exception handling
This commit is contained in:
@@ -31,6 +31,10 @@ from zipline.utils.test_utils import(
|
||||
teardown_logger,
|
||||
)
|
||||
|
||||
from zipline.errors import(
|
||||
BadOrderParameters
|
||||
)
|
||||
|
||||
|
||||
class ExecutionStyleTestCase(TestCase):
|
||||
"""
|
||||
@@ -58,7 +62,19 @@ class ExecutionStyleTestCase(TestCase):
|
||||
for delta in range(1, 10)
|
||||
]
|
||||
|
||||
INVALID_PRICES = [(-1,), (-1.0,), (0 - epsilon,)]
|
||||
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)
|
||||
@@ -72,14 +88,14 @@ class ExecutionStyleTestCase(TestCase):
|
||||
Test that execution styles throw appropriate exceptions upon receipt
|
||||
of an invalid price field.
|
||||
"""
|
||||
with self.assertRaises(ValueError):
|
||||
with self.assertRaises(BadOrderParameters):
|
||||
LimitOrder(price)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
with self.assertRaises(BadOrderParameters):
|
||||
StopOrder(price)
|
||||
|
||||
for lmt, stp in [(price, 1), (1, price), (price, price)]:
|
||||
with self.assertRaises(ValueError):
|
||||
with self.assertRaises(BadOrderParameters):
|
||||
StopLimitOrder(lmt, stp)
|
||||
|
||||
def test_market_order_prices(self):
|
||||
|
||||
@@ -137,6 +137,14 @@ class UnsupportedOrderParameters(ZiplineError):
|
||||
msg = "{msg}"
|
||||
|
||||
|
||||
class BadOrderParameters(ZiplineError):
|
||||
"""
|
||||
Raised if any impossible parameters (nan, negative limit/stop)
|
||||
are passed to an order call.
|
||||
"""
|
||||
msg = "{msg}"
|
||||
|
||||
|
||||
class OrderDuringInitialize(ZiplineError):
|
||||
"""
|
||||
Raised if order is called during initialize()
|
||||
|
||||
@@ -21,6 +21,10 @@ from six import with_metaclass
|
||||
|
||||
import zipline.utils.math_utils as zp_math
|
||||
|
||||
from numpy import isfinite
|
||||
|
||||
from zipline.errors import BadOrderParameters
|
||||
|
||||
|
||||
class ExecutionStyle(with_metaclass(abc.ABCMeta)):
|
||||
"""
|
||||
@@ -77,8 +81,9 @@ class LimitOrder(ExecutionStyle):
|
||||
"""
|
||||
Store the given price.
|
||||
"""
|
||||
if limit_price < 0:
|
||||
raise ValueError("Can't place a limit with a negative price.")
|
||||
|
||||
check_stoplimit_prices(limit_price, 'limit')
|
||||
|
||||
self.limit_price = limit_price
|
||||
self._exchange = exchange
|
||||
|
||||
@@ -98,10 +103,9 @@ class StopOrder(ExecutionStyle):
|
||||
"""
|
||||
Store the given price.
|
||||
"""
|
||||
if stop_price < 0:
|
||||
raise ValueError(
|
||||
"Can't place a stop order with a negative price."
|
||||
)
|
||||
|
||||
check_stoplimit_prices(stop_price, 'stop')
|
||||
|
||||
self.stop_price = stop_price
|
||||
self._exchange = exchange
|
||||
|
||||
@@ -121,14 +125,10 @@ class StopLimitOrder(ExecutionStyle):
|
||||
"""
|
||||
Store the given prices
|
||||
"""
|
||||
if limit_price < 0:
|
||||
raise ValueError(
|
||||
"Can't place a limit with a negative price."
|
||||
)
|
||||
if stop_price < 0:
|
||||
raise ValueError(
|
||||
"Can't place a stop order with a negative price."
|
||||
)
|
||||
|
||||
check_stoplimit_prices(limit_price, 'limit')
|
||||
|
||||
check_stoplimit_prices(stop_price, 'stop')
|
||||
|
||||
self.limit_price = limit_price
|
||||
self.stop_price = stop_price
|
||||
@@ -169,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)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user