ENH: Provide a process_order method to override for custom slippage.

To make implementing a custom slippage model more straightforward,
provide a simulate method that will setup the calling of
`process_order`, which individual slippage models override to
do the unique slippage handling, where the simulate method handles
the boilerplate of checking order triggers, etc.
This commit is contained in:
Eddie Hebert
2013-06-13 19:01:00 -04:00
parent e727bfbd03
commit d41aff9a99
+36 -53
View File
@@ -119,10 +119,38 @@ class SlippageModel(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def simulate(self, event, current_orders, **kwargs):
@property
def volume_for_bar(self):
return self._volume_for_bar
@abc.abstractproperty
def process_order(self, event, order):
pass
def simulate(self, event, current_orders):
self._volume_for_bar = 0
txns = []
for order in current_orders:
open_amount = order.amount - order.filled
if zp_math.tolerant_equals(open_amount, 0):
continue
order.check_triggers(event)
if not order.triggered:
continue
txn = self.process_order(event, order)
if txn:
txns.append(txn)
self._volume_for_bar += math.copysign(txn.amount, 1)
return txns
def __call__(self, event, current_orders, **kwargs):
return self.simulate(event, current_orders, **kwargs)
@@ -146,9 +174,12 @@ class VolumeShareSlippage(SlippageModel):
price_impact=self.price_impact)
def process_order(self, event, order):
max_volume = self.volume_limit * event.volume
# price impact accounts for the total volume of transactions
# created against the current minute bar
remaining_volume = self.max_volume - self.total_volume
remaining_volume = max_volume - self.volume_for_bar
if (
remaining_volume <= 0
or
@@ -162,9 +193,9 @@ class VolumeShareSlippage(SlippageModel):
cur_volume = min(remaining_volume, abs(order.open_amount))
# tally the current amount into our total amount ordered.
# total amount will be used to calculate price impact
self.total_volume = self.total_volume + cur_volume
total_volume = self.volume_for_bar + cur_volume
volume_share = min(self.total_volume / event.volume,
volume_share = min(total_volume / event.volume,
self.volume_limit)
simulated_impact = (volume_share) ** 2 \
@@ -180,30 +211,6 @@ class VolumeShareSlippage(SlippageModel):
math.copysign(cur_volume, order.direction)
)
def simulate(self, event, current_orders):
self.max_volume = self.volume_limit * event.volume
self.total_volume = 0
txns = []
for order in current_orders:
open_amount = order.amount - order.filled
if zp_math.tolerant_equals(open_amount, 0):
continue
order.check_triggers(event)
if not order.triggered:
continue
txn = self.process_order(event, order)
if txn:
txns.append(txn)
return txns
class FixedSlippage(SlippageModel):
@@ -222,27 +229,3 @@ class FixedSlippage(SlippageModel):
event.price + (self.spread / 2.0 * order.direction),
order.amount,
)
def simulate(self, event, orders):
txns = []
for order in orders:
# TODO: what if we have 2 orders, one for 100 shares long,
# and one for 100 shares short
# such as in a hedging scenario?
order.check_triggers(event)
if not order.triggered:
continue
if zp_math.tolerant_equals(order.amount, 0):
continue
txn = self.process_order(event, order)
if txn:
# mark the date of the order to match the transaction
order.dt = event.dt
txns.append(txn)
return txns