class TestMarketOnOpenExecutionStyle(TestCase): MarketOpenEvent.set_trigger_time({ "hour": 13, "minute": 30, "second": 0, "microsecond": 0 }) MarketCloseEvent.set_trigger_time({ "hour": 20, "minute": 0, "second": 0, "microsecond": 0 }) def setUp(self): self.scheduling_time_delay = 1 start_date = str_to_date("2018-02-04") before_close = start_date + MarketCloseEvent.trigger_time( ) - RelativeDelta(minutes=self.scheduling_time_delay) self.timer = SettableTimer(initial_time=before_close) contracts_to_tickers_mapper = SimulatedBloombergContractTickerMapper() msft_contract = Contract("MSFT US Equity", security_type='STK', exchange='TEST') self.msft_ticker = contracts_to_tickers_mapper.contract_to_ticker( msft_contract) self.data_handler = Mock(spec=DataHandler) self.scheduler = Mock(spec=Scheduler) self.commission_model = FixedCommissionModel(commission=0.0) self.monitor = Mock(spec=AbstractMonitor) self.portfolio = Mock(spec=Portfolio) slippage_model = PriceBasedSlippage(0.0, self.data_handler, contracts_to_tickers_mapper) self.exec_handler = SimulatedExecutionHandler( self.data_handler, self.timer, self.scheduler, self.monitor, self.commission_model, contracts_to_tickers_mapper, self.portfolio, slippage_model, RelativeDelta(minutes=self.scheduling_time_delay)) self.order_1 = Order(msft_contract, quantity=10, execution_style=MarketOrder(), time_in_force=TimeInForce.OPG) self.order_2 = Order(msft_contract, quantity=-5, execution_style=MarketOrder(), time_in_force=TimeInForce.OPG) self.order_3 = Order(msft_contract, quantity=-7, execution_style=MarketOrder(), time_in_force=TimeInForce.OPG) self.order_4 = Order(msft_contract, quantity=4, execution_style=MarketOnCloseOrder(), time_in_force=TimeInForce.DAY) def _trigger_single_time_event(self): self.timer.set_current_time(self.timer.now() + RelativeDelta( minutes=self.scheduling_time_delay)) event = ScheduleOrderExecutionEvent() self.exec_handler.on_orders_accept(event) def test_1_order_fill(self): self.exec_handler.assign_order_ids([self.order_1]) self._set_current_price(101) self._trigger_single_time_event() self.exec_handler.on_market_open(...) self.monitor.record_transaction.assert_called_once() self.portfolio.transact_transaction.assert_called_once() actual_orders = self.exec_handler.get_open_orders() expected_orders = [] assert_lists_equal(expected_orders, actual_orders) def test_3_orders_fill(self): self.exec_handler.assign_order_ids( [self.order_1, self.order_2, self.order_3]) self._set_current_price(101) self._trigger_single_time_event() self.exec_handler.on_market_open(...) self.assertEqual(self.monitor.record_transaction.call_count, 3) self.assertEqual(self.portfolio.transact_transaction.call_count, 3) actual_orders = self.exec_handler.get_open_orders() expected_orders = [] assert_lists_equal(expected_orders, actual_orders) def test_3_orders_fill_only_at_open(self): self.exec_handler.assign_order_ids( [self.order_1, self.order_2, self.order_3]) self._set_current_price(101) self._trigger_single_time_event() self.exec_handler.on_market_close(...) self.portfolio.transact_transaction.assert_not_called() self.monitor.record_transaction.assert_not_called() actual_orders = self.exec_handler.get_open_orders() expected_orders = [self.order_1, self.order_2, self.order_3] self.assertCountEqual(expected_orders, actual_orders) def test_fill_open_and_close(self): self.exec_handler.assign_order_ids([self.order_1, self.order_2]) self.exec_handler.assign_order_ids([self.order_2, self.order_3]) self.exec_handler.assign_order_ids([self.order_3, self.order_4]) self.exec_handler.assign_order_ids([self.order_4, self.order_4]) self._set_current_price(101) self._trigger_single_time_event() self.exec_handler.on_market_open(...) self.assertEqual(self.monitor.record_transaction.call_count, 3) self.assertEqual(self.portfolio.transact_transaction.call_count, 3) actual_orders = self.exec_handler.get_open_orders() expected_orders = [self.order_4] assert_lists_equal(expected_orders, actual_orders) self.exec_handler.on_market_close(...) self.assertEqual(self.monitor.record_transaction.call_count, 4) self.assertEqual(self.portfolio.transact_transaction.call_count, 4) actual_orders = self.exec_handler.get_open_orders() expected_orders = [] assert_lists_equal(expected_orders, actual_orders) def test_fill_close_and_open(self): self.exec_handler.assign_order_ids([self.order_1, self.order_2]) self.exec_handler.assign_order_ids([self.order_2, self.order_3]) self.exec_handler.assign_order_ids([self.order_3, self.order_4]) self.exec_handler.assign_order_ids([self.order_4, self.order_4]) self._set_current_price(101) self._trigger_single_time_event() self.exec_handler.on_market_close(...) # Transaction related to order 4 will be executed only once, as only one Order object was passed self.monitor.record_transaction.assert_called_once() self.portfolio.transact_transaction.assert_called_once() actual_orders = self.exec_handler.get_open_orders() expected_orders = [self.order_1, self.order_2, self.order_3] self.assertCountEqual(expected_orders, actual_orders) self.exec_handler.on_market_open(...) self.assertEqual(self.monitor.record_transaction.call_count, 4) self.assertEqual(self.portfolio.transact_transaction.call_count, 4) actual_orders = self.exec_handler.get_open_orders() expected_orders = [] self.assertCountEqual(expected_orders, actual_orders) def test_market_open_transaction(self): order = self.order_1 price = 102 self.exec_handler.assign_order_ids([order]) self._set_current_price(price) self._trigger_single_time_event() self.exec_handler.on_market_open(...) timestamp = self.timer.now() contract = order.contract quantity = order.quantity commission = self.commission_model.calculate_commission(order, price) expected_transaction = Transaction(timestamp, contract, quantity, price, commission) self.monitor.record_transaction.assert_called_once_with( expected_transaction) def test_market_close_transaction(self): order = self.order_4 price = 102 self.exec_handler.assign_order_ids([self.order_1, order]) self._set_current_price(price) self._trigger_single_time_event() self.exec_handler.on_market_close(...) timestamp = self.timer.now() contract = order.contract quantity = order.quantity commission = self.commission_model.calculate_commission(order, price) expected_transaction = Transaction(timestamp, contract, quantity, price, commission) self.monitor.record_transaction.assert_called_once_with( expected_transaction) def test_market_close_does_not_trade(self): price = None self.exec_handler.assign_order_ids([self.order_1, self.order_4]) self._set_current_price(price) self._trigger_single_time_event() self.exec_handler.on_market_close(...) self.portfolio.transact_transaction.assert_not_called() self.monitor.record_transaction.assert_not_called() def test_market_open_does_not_trade(self): price = None self.exec_handler.assign_order_ids([self.order_1, self.order_4]) self._set_current_price(price) self._trigger_single_time_event() self.exec_handler.on_market_open(...) self.portfolio.transact_transaction.assert_not_called() self.monitor.record_transaction.assert_not_called() def _set_last_available_price(self, price): self.data_handler.get_last_available_price.side_effect = lambda t: QFSeries( data=[price], index=pd.Index([self.msft_ticker])) def _set_current_price(self, price): self.data_handler.get_current_price.side_effect = lambda t: QFSeries( data=[price], index=pd.Index([self.msft_ticker]))
class TestMarketOnOpenExecutionStyle(TestCase): MSFT_TICKER_STR = "MSFT US Equity" def setUp(self): self.start_date = str_to_date("2018-02-04") self.msft_contract = Contract(self.MSFT_TICKER_STR, security_type='SEK', exchange='TEST') self.msft_ticker = BloombergTicker(self.MSFT_TICKER_STR) self.contracts_to_tickers_mapper = DummyBloombergContractTickerMapper() self.timer = SettableTimer(initial_time=self.start_date) self.data_handler = mock(strict=True) self.scheduler = mock() self.commission_model = FixedCommissionModel(commission=0.0) self.monitor = _MonitorMock() self.spied_monitor = spy(self.monitor) self.portfolio = mock() slippage_model = PriceBasedSlippage(0.0) self.exec_hanlder = SimulatedExecutionHandler( self.data_handler, self.timer, self.scheduler, self.spied_monitor, self.commission_model, self.contracts_to_tickers_mapper, self.portfolio, slippage_model) self._set_last_msft_price(100.0) self.order_1 = Order(self.msft_contract, quantity=10, execution_style=MarketOrder(), time_in_force=TimeInForce.OPG) self.order_2 = Order(self.msft_contract, quantity=-5, execution_style=MarketOrder(), time_in_force=TimeInForce.OPG) self.order_3 = Order(self.msft_contract, quantity=-7, execution_style=MarketOrder(), time_in_force=TimeInForce.OPG) self.order_4 = Order(self.msft_contract, quantity=4, execution_style=MarketOnCloseOrder(), time_in_force=TimeInForce.DAY) def test_1_order_fill(self): self.exec_hanlder.accept_orders([self.order_1]) self._set_price_for_now(101) self.exec_hanlder.on_market_open(...) verify(self.spied_monitor, times=1).record_transaction(...) verify(self.portfolio, times=1).transact_transaction(...) actual_orders = self.exec_hanlder.get_open_orders() expected_orders = [] assert_lists_equal(expected_orders, actual_orders) def test_3_orders_fill(self): self.exec_hanlder.accept_orders( [self.order_1, self.order_2, self.order_3]) self._set_price_for_now(101) self.exec_hanlder.on_market_open(...) verify(self.spied_monitor, times=3).record_transaction(...) verify(self.portfolio, times=3).transact_transaction(...) actual_orders = self.exec_hanlder.get_open_orders() expected_orders = [] assert_lists_equal(expected_orders, actual_orders) def test_3_orders_fill_only_at_open(self): self.exec_hanlder.accept_orders( [self.order_1, self.order_2, self.order_3]) self._set_price_for_now(101) self.exec_hanlder.on_market_close(...) verifyZeroInteractions(self.portfolio, self.spied_monitor) actual_orders = self.exec_hanlder.get_open_orders() expected_orders = [self.order_1, self.order_2, self.order_3] assert_lists_equal(expected_orders, actual_orders) def test_fill_open_and_close(self): self.exec_hanlder.accept_orders([self.order_1, self.order_2]) self.exec_hanlder.accept_orders([self.order_2, self.order_3]) self.exec_hanlder.accept_orders([self.order_3, self.order_4]) self.exec_hanlder.accept_orders([self.order_4, self.order_4]) self._set_price_for_now(101) self.exec_hanlder.on_market_open(...) verify(self.spied_monitor, times=5).record_transaction(...) verify(self.portfolio, times=5).transact_transaction(...) actual_orders = self.exec_hanlder.get_open_orders() expected_orders = [self.order_4, self.order_4, self.order_4] assert_lists_equal(expected_orders, actual_orders) self.exec_hanlder.on_market_close(...) verify(self.spied_monitor, times=8).record_transaction(...) verify(self.portfolio, times=8).transact_transaction(...) actual_orders = self.exec_hanlder.get_open_orders() expected_orders = [] assert_lists_equal(expected_orders, actual_orders) def test_fill_close_and_open(self): self.exec_hanlder.accept_orders([self.order_1, self.order_2]) self.exec_hanlder.accept_orders([self.order_2, self.order_3]) self.exec_hanlder.accept_orders([self.order_3, self.order_4]) self.exec_hanlder.accept_orders([self.order_4, self.order_4]) self._set_price_for_now(101) self.exec_hanlder.on_market_close(...) verify(self.spied_monitor, times=3).record_transaction(...) verify(self.portfolio, times=3).transact_transaction(...) actual_orders = self.exec_hanlder.get_open_orders() expected_orders = [ self.order_1, self.order_2, self.order_2, self.order_3, self.order_3 ] assert_lists_equal(expected_orders, actual_orders) self.exec_hanlder.on_market_open(...) verify(self.spied_monitor, times=8).record_transaction(...) verify(self.portfolio, times=8).transact_transaction(...) actual_orders = self.exec_hanlder.get_open_orders() expected_orders = [] assert_lists_equal(expected_orders, actual_orders) def test_market_open_transaction(self): order = self.order_1 price = 102 self.exec_hanlder.accept_orders([order]) self._set_price_for_now(price) self.exec_hanlder.on_market_open(...) timestamp = self.timer.now() contract = order.contract quantity = order.quantity commission = self.commission_model.calculate_commission(order, price) expected_transaction = Transaction(timestamp, contract, quantity, price, commission) captor = _ArgCaptor() verify(self.spied_monitor, times=1).record_transaction(captor) self.assertEqual(expected_transaction, captor.get_value()) def test_market_close_transaction(self): order = self.order_4 price = 102 self.exec_hanlder.accept_orders([self.order_1, order]) self._set_price_for_now(price) self.exec_hanlder.on_market_close(...) timestamp = self.timer.now() contract = order.contract quantity = order.quantity commission = self.commission_model.calculate_commission(order, price) expected_transaction = Transaction(timestamp, contract, quantity, price, commission) captor = _ArgCaptor() verify(self.spied_monitor, times=1).record_transaction(captor) self.assertEqual(expected_transaction, captor.get_value()) def test_market_close_does_not_trade(self): price = None self.exec_hanlder.accept_orders([self.order_1, self.order_4]) self._set_price_for_now(price) self.exec_hanlder.on_market_close(...) verifyZeroInteractions(self.portfolio, self.spied_monitor) def test_market_open_does_not_trade(self): price = None self.exec_hanlder.accept_orders([self.order_1, self.order_4]) self._set_price_for_now(price) self.exec_hanlder.on_market_open(...) verifyZeroInteractions(self.portfolio, self.spied_monitor) def _set_last_msft_price(self, price): when(self.data_handler).get_last_available_price( [self.msft_ticker]).thenReturn( pd.Series(data=[price], index=pd.Index([self.msft_ticker]), name=self.start_date)) def _set_price_for_now(self, price): when(self.data_handler).get_current_price( [self.msft_ticker]).thenReturn( pd.Series(data=[price], index=pd.Index([self.msft_ticker])))