diff --git a/tests/test_finance.py b/tests/test_finance.py index 5d9eabca..3dd32c8b 100644 --- a/tests/test_finance.py +++ b/tests/test_finance.py @@ -253,7 +253,7 @@ class FinanceTestCase(TestCase): oo = blotter.open_orders self.assertEqual(len(oo), 1) self.assertTrue(sid in oo) - order_list = oo[sid] + order_list = oo[sid][:] # make copy self.assertEqual(order_count, len(order_list)) for i in range(order_count): diff --git a/zipline/finance/blotter.py b/zipline/finance/blotter.py index a3d2a5c3..807e8495 100644 --- a/zipline/finance/blotter.py +++ b/zipline/finance/blotter.py @@ -20,6 +20,7 @@ from logbook import Logger from collections import defaultdict from six import text_type +from six.moves import filter import zipline.errors import zipline.protocol as zp @@ -199,25 +200,25 @@ class Blotter(object): return orders = self.open_orders[trade_event.sid] - orders = sorted(orders, key=lambda o: o.dt) # Only use orders for the current day or before current_orders = filter( lambda o: o.dt <= trade_event.dt, orders) + processed_orders = [] for txn, order in self.process_transactions(trade_event, current_orders): + processed_orders.append(order) yield txn, order - # update the open orders for the trade_event's sid - updated_orders = \ - [order for order - in self.open_orders[trade_event.sid] - if order.open] + # remove closed orders. we should only have to check + # processed orders + not_open = lambda order: not order.open + closed_orders = filter(not_open, processed_orders) + for order in closed_orders: + orders.remove(order) - if updated_orders: - self.open_orders[trade_event.sid] = updated_orders - else: + if len(orders) == 0: del self.open_orders[trade_event.sid] def process_transactions(self, trade_event, current_orders): diff --git a/zipline/finance/slippage.py b/zipline/finance/slippage.py index 7ee191a4..cedcab21 100644 --- a/zipline/finance/slippage.py +++ b/zipline/finance/slippage.py @@ -150,6 +150,10 @@ def create_transaction(event, order, price, amount): return transaction +class LiquidityExceeded(Exception): + pass + + class SlippageModel(with_metaclass(abc.ABCMeta)): @property @@ -173,7 +177,10 @@ class SlippageModel(with_metaclass(abc.ABCMeta)): if not order.triggered: continue - txn = self.process_order(event, order) + try: + txn = self.process_order(event, order) + except LiquidityExceeded: + break if txn: self._volume_for_bar += abs(txn.amount) @@ -210,7 +217,7 @@ class VolumeShareSlippage(SlippageModel): remaining_volume = max_volume - self.volume_for_bar if remaining_volume < 1: # we can't fill any more transactions - return + raise LiquidityExceeded() # the current order amount will be the min of the # volume available in the bar or the open amount.