ENH: Add the ability to specify an exchange on an ExecutionStyle.

Adds the exchange property the interface for ExecutionStyle and adds an
exchange parameter to the interface of all the existing ExceutionStyles.
Subclasses wishing to support the ability to specify an exchange should set the
_exchange attribute in __init__.
This commit is contained in:
Scott Sanderson
2014-04-25 19:02:57 -04:00
parent ebf16720ef
commit f41c37a606
+119 -107
View File
@@ -22,6 +22,125 @@ from six import with_metaclass
import zipline.utils.math_utils as zp_math
class ExecutionStyle(with_metaclass(abc.ABCMeta)):
"""
Abstract base class representing a modification to a standard order.
"""
_exchange = None
@abc.abstractmethod
def get_limit_price(self, is_buy):
"""
Get the limit price for this order.
Returns either None or a numerical value >= 0.
"""
raise NotImplemented
@abc.abstractmethod
def get_stop_price(self, is_buy):
"""
Get the stop price for this order.
Returns either None or a numerical value >= 0.
"""
raise NotImplemented
@property
def exchange(self):
"""
The exchange to which this order should be routed.
"""
return self._exchange
class MarketOrder(ExecutionStyle):
"""
Class encapsulating an order to be placed at the current market price.
"""
def __init__(self, exchange=None):
self._exchange = exchange
def get_limit_price(self, _is_buy):
return None
def get_stop_price(self, _is_buy):
return None
class LimitOrder(ExecutionStyle):
"""
Execution style representing an order to be executed at a price equal to or
better than a specified limit price.
"""
def __init__(self, limit_price, exchange=None):
"""
Store the given price.
"""
if limit_price < 0:
raise ValueError("Can't place a limit with a negative price.")
self.limit_price = limit_price
self._exchange = exchange
def get_limit_price(self, is_buy):
return asymmetric_round_price_to_penny(self.limit_price, is_buy)
def get_stop_price(self, _is_buy):
return None
class StopOrder(ExecutionStyle):
"""
Execution style representing an order to be placed once the market price
reaches a specified stop price.
"""
def __init__(self, stop_price, exchange=None):
"""
Store the given price.
"""
if stop_price < 0:
raise ValueError(
"Can't place a stop order with a negative price."
)
self.stop_price = stop_price
self._exchange = exchange
def get_limit_price(self, _is_buy):
return None
def get_stop_price(self, is_buy):
return asymmetric_round_price_to_penny(self.stop_price, not is_buy)
class StopLimitOrder(ExecutionStyle):
"""
Execution style representing a limit order to be placed with a specified
limit price once the market reaches a specified stop price.
"""
def __init__(self, limit_price, stop_price, exchange=None):
"""
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."
)
self.limit_price = limit_price
self.stop_price = stop_price
self._exchange = exchange
def get_limit_price(self, is_buy):
return asymmetric_round_price_to_penny(self.limit_price, is_buy)
def get_stop_price(self, is_buy):
return asymmetric_round_price_to_penny(self.stop_price, not is_buy)
def asymmetric_round_price_to_penny(price, prefer_round_down,
diff=(0.0095 - .005)):
"""
@@ -50,110 +169,3 @@ def asymmetric_round_price_to_penny(price, prefer_round_down,
if zp_math.tolerant_equals(rounded, 0.0):
return 0.0
return rounded
class ExecutionStyle(with_metaclass(abc.ABCMeta)):
"""
Abstract base class representing a modification to a standard order.
"""
@abc.abstractmethod
def get_limit_price(self, is_buy):
"""
Get the limit price for this order.
Returns either None or a numerical value >= 0.
"""
raise NotImplemented
@abc.abstractmethod
def get_stop_price(self, is_buy):
"""
Get the stop price for this order.
Returns either None or a numerical value >= 0.
"""
raise NotImplemented
class MarketOrder(ExecutionStyle):
"""
Class encapsulating an order to be placed at the current market price.
"""
def __init__(self):
pass
def get_limit_price(self, _is_buy):
return None
def get_stop_price(self, _is_buy):
return None
class LimitOrder(ExecutionStyle):
"""
Execution style representing an order to be executed at a price equal to or
better than a specified limit price.
"""
def __init__(self, limit_price):
"""
Store the given price.
"""
if limit_price < 0:
raise ValueError("Can't place a limit with a negative price.")
self.limit_price = limit_price
def get_limit_price(self, is_buy):
return asymmetric_round_price_to_penny(self.limit_price, is_buy)
def get_stop_price(self, _is_buy):
return None
class StopOrder(ExecutionStyle):
"""
Execution style representing an order to be placed once the market price
reaches a specified stop price.
"""
def __init__(self, stop_price):
"""
Store the given price.
"""
if stop_price < 0:
raise ValueError(
"Can't place a stop order with a negative price."
)
self.stop_price = stop_price
def get_limit_price(self, _is_buy):
return None
def get_stop_price(self, is_buy):
return asymmetric_round_price_to_penny(self.stop_price, not is_buy)
class StopLimitOrder(ExecutionStyle):
"""
Execution style representing a limit order to be placed with a specified
limit price once the market reaches a specified stop price.
"""
def __init__(self, limit_price, stop_price):
"""
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."
)
self.limit_price = limit_price
self.stop_price = stop_price
def get_limit_price(self, is_buy):
return asymmetric_round_price_to_penny(self.limit_price, is_buy)
def get_stop_price(self, is_buy):
return asymmetric_round_price_to_penny(self.stop_price, not is_buy)