def test_submit_order_command_to_from_dict_and_str_repr(self): # Arrange uuid = self.uuid_factory.generate() order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) command = SubmitOrder( trader_id=TraderId("TRADER-001"), strategy_id=StrategyId("S-001"), position_id=PositionId("P-001"), order=order, command_id=uuid, ts_init=self.clock.timestamp_ns(), ) # Act, Assert assert SubmitOrder.from_dict(SubmitOrder.to_dict(command)) == command assert ( str(command) == "SubmitOrder(instrument_id=AUD/USD.SIM, client_order_id=O-19700101-000000-000-001-1, position_id=P-001, order=BUY 100_000 AUD/USD.SIM MARKET GTC)" # noqa ) assert ( repr(command) == f"SubmitOrder(client_id=None, trader_id=TRADER-001, strategy_id=S-001, instrument_id=AUD/USD.SIM, client_order_id=O-19700101-000000-000-001-1, position_id=P-001, order=BUY 100_000 AUD/USD.SIM MARKET GTC, command_id={uuid}, ts_init=0)" # noqa )
def setup(self): # Fixture Setup self.venue = Venue("SIM") self.trader_id = TestIdStubs.trader_id() self.account_id = TestIdStubs.account_id() self.order_factory = OrderFactory( trader_id=self.trader_id, strategy_id=StrategyId("S-001"), clock=TestClock(), ) self.order = self.order_factory.market( AUDUSD, OrderSide.BUY, Quantity.from_int(100000), ) self.command = SubmitOrder( self.trader_id, StrategyId("SCALPER-001"), PositionId("P-123456"), self.order, UUID4(), 0, ) self.serializer = MsgPackSerializer()
def test_submit_order_when_risk_bypassed_sends_to_execution_engine(self): # Arrange self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) submit_order = SubmitOrder( trader_id=self.trader_id, strategy_id=strategy.id, position_id=None, order=order, command_id=self.uuid_factory.generate(), ts_init=self.clock.timestamp_ns(), ) # Act self.risk_engine.execute(submit_order) # Assert assert self.exec_engine.command_count == 1 # <-- initial account event assert self.exec_client.calls == ["_start", "submit_order"]
def test_submit_order_with_default_settings_then_sends_to_client(self): # Arrange self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) submit_order = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Act self.risk_engine.execute(submit_order) # Assert assert self.exec_engine.command_count == 1 assert self.exec_client.calls == ["_start", "submit_order"]
def test_submit_order_when_instrument_not_in_cache_then_denies(self): # Arrange self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.market( GBPUSD_SIM.id, # <-- not in the cache OrderSide.BUY, Quantity.from_int(100000), ) submit_order = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Act self.risk_engine.execute(submit_order) # Assert assert self.exec_engine.command_count == 0 # <-- command never reaches engine
async def test_submit_unsupported_order_logs_error(self, mocker): # Arrange mock_send_request = mocker.patch( target= "nautilus_trader.adapters.binance.http.client.BinanceHttpClient.send_request" ) order = self.strategy.order_factory.market_to_limit( instrument_id=ETHUSDT_BINANCE.id, order_side=OrderSide.BUY, quantity=Quantity.from_int(10), ) self.cache.add_order(order, None) submit_order = SubmitOrder( trader_id=self.trader_id, strategy_id=self.strategy.id, position_id=None, order=order, command_id=UUID4(), ts_init=0, ) # Act self.exec_client.submit_order(submit_order) await asyncio.sleep(0.3) # Assert assert mock_send_request.call_args is None
def test_serialize_and_deserialize_submit_order_commands(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), ) command = SubmitOrder( self.trader_id, StrategyId("SCALPER-001"), PositionId("P-123456"), order, UUID4(), 0, ClientId("SIM"), ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command assert deserialized.order == order print(command) print(len(serialized)) print(serialized) print(b64encode(serialized))
def test_submit_order_when_invalid_quantity_less_than_minimum_then_denies(self): # Arrange self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(1), # <- invalid quantity Price.from_str("1.00000"), ) submit_order = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Act self.risk_engine.execute(submit_order) # Assert assert self.exec_engine.command_count == 0 # <-- command never reaches engine
def submit_order_command(order: Order): return SubmitOrder( trader_id=TestIdStubs.trader_id(), strategy_id=TestIdStubs.strategy_id(), position_id=TestIdStubs.position_id(), order=order, command_id=TestIdStubs.uuid(), ts_init=TestComponentStubs.clock().timestamp_ns(), )
def test_update_order_when_already_closed_then_denies(self): # Arrange self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00010"), ) submit = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.risk_engine.execute(submit) self.exec_engine.process(TestEventStubs.order_submitted(order)) self.exec_engine.process(TestEventStubs.order_accepted(order)) self.exec_engine.process(TestEventStubs.order_filled(order, AUDUSD_SIM)) modify = ModifyOrder( self.trader_id, strategy.id, order.instrument_id, order.client_order_id, VenueOrderId("1"), order.quantity, Price.from_str("1.00010"), None, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Act self.risk_engine.execute(modify) # Assert assert self.exec_client.calls == ["_start", "submit_order"] assert self.risk_engine.command_count == 2 assert self.exec_engine.command_count == 1
def test_cancel_order_when_already_pending_cancel_then_denies(self): # Arrange self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) submit = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) cancel = CancelOrder( self.trader_id, strategy.id, order.instrument_id, order.client_order_id, VenueOrderId("1"), self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.risk_engine.execute(submit) self.exec_engine.process(TestEventStubs.order_submitted(order)) self.exec_engine.process(TestEventStubs.order_accepted(order)) self.risk_engine.execute(cancel) self.exec_engine.process(TestEventStubs.order_pending_cancel(order)) # Act self.risk_engine.execute(cancel) # Assert assert self.exec_client.calls == ["_start", "submit_order", "cancel_order"] assert self.risk_engine.command_count == 3 assert self.exec_engine.command_count == 2
def test_modify_order_with_default_settings_then_sends_to_client(self): # Arrange self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00010"), ) submit = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) modify = ModifyOrder( self.trader_id, strategy.id, order.instrument_id, order.client_order_id, VenueOrderId("1"), order.quantity, Price.from_str("1.00010"), None, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.risk_engine.execute(submit) # Act self.risk_engine.execute(modify) # Assert assert self.exec_client.calls == ["_start", "submit_order", "modify_order"] assert self.risk_engine.command_count == 2 assert self.exec_engine.command_count == 2
async def test_trailing_stop_market_order(self, mocker): # Arrange mock_send_request = mocker.patch( target= "nautilus_trader.adapters.binance.http.client.BinanceHttpClient.send_request" ) order = self.strategy.order_factory.trailing_stop_market( instrument_id=ETHUSDT_PERP_BINANCE.id, order_side=OrderSide.SELL, quantity=Quantity.from_int(10), trailing_offset=Decimal(100), offset_type=TrailingOffsetType.BASIS_POINTS, trigger_price=Price.from_str("10000.00"), trigger_type=TriggerType.MARK, reduce_only=True, ) self.cache.add_order(order, None) submit_order = SubmitOrder( trader_id=self.trader_id, strategy_id=self.strategy.id, position_id=None, order=order, command_id=UUID4(), ts_init=0, ) # Act self.exec_client.submit_order(submit_order) await asyncio.sleep(0.3) # Assert request = mock_send_request.call_args[0] assert request[0] == "POST" assert request[1] == "/fapi/v1/order" assert request[2]["symbol"] == "ETHUSDT" # -PERP was stripped assert request[2]["side"] == "SELL" assert request[2]["type"] == "TRAILING_STOP_MARKET" assert request[2]["timeInForce"] == "GTC" assert request[2]["quantity"] == "10" assert request[2]["reduceOnly"] == "true" assert request[2]["newClientOrderId"] is not None assert request[2]["activationPrice"] == "10000.00" assert request[2]["callbackRate"] == "1" assert request[2]["workingType"] == "MARK_PRICE" assert request[2]["recvWindow"] == "5000" assert request[2]["signature"] is not None
async def test_message_qsize_at_max_blocks_on_put_event(self): # Arrange self.msgbus.deregister("RiskEngine.execute", self.risk_engine.execute) self.risk_engine = LiveRiskEngine( loop=self.loop, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, config=LiveRiskEngineConfig(qsize=1), ) strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) submit_order = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) event = TestEventStubs.order_submitted(order) # Act self.risk_engine.execute(submit_order) self.risk_engine.process(event) # Add over max size await asyncio.sleep(0.1) # Assert assert self.risk_engine.qsize() == 1 assert self.risk_engine.event_count == 0
async def test_submit_limit_if_touched_order(self, mocker): # Arrange mock_send_request = mocker.patch( target= "nautilus_trader.adapters.binance.http.client.BinanceHttpClient.send_request" ) order = self.strategy.order_factory.limit_if_touched( instrument_id=ETHUSDT_PERP_BINANCE.id, order_side=OrderSide.SELL, quantity=Quantity.from_int(10), price=Price.from_str("10050.80"), trigger_price=Price.from_str("10099.00"), ) self.cache.add_order(order, None) submit_order = SubmitOrder( trader_id=self.trader_id, strategy_id=self.strategy.id, position_id=None, order=order, command_id=UUID4(), ts_init=0, ) # Act self.exec_client.submit_order(submit_order) await asyncio.sleep(0.3) # Assert request = mock_send_request.call_args[0] assert request[0] == "POST" assert request[1] == "/fapi/v1/order" assert request[2]["symbol"] == "ETHUSDT" # -PERP was stripped assert request[2]["side"] == "SELL" assert request[2]["type"] == "TAKE_PROFIT" assert request[2]["timeInForce"] == "GTC" assert request[2]["quantity"] == "10" assert request[2]["reduceOnly"] == "false" assert request[2]["price"] == "10050.80" assert request[2]["newClientOrderId"] is not None assert request[2]["stopPrice"] == "10099.00" assert request[2]["workingType"] == "CONTRACT_PRICE" assert request[2]["recvWindow"] == "5000" assert request[2]["signature"] is not None
async def test_submit_stop_limit_order(self, mocker): # Arrange mock_send_request = mocker.patch( target= "nautilus_trader.adapters.binance.http.client.BinanceHttpClient.send_request" ) order = self.strategy.order_factory.stop_limit( instrument_id=ETHUSDT_BINANCE.id, order_side=OrderSide.BUY, quantity=Quantity.from_int(10), price=Price.from_str("10050.80"), trigger_price=Price.from_str("10050.00"), ) self.cache.add_order(order, None) submit_order = SubmitOrder( trader_id=self.trader_id, strategy_id=self.strategy.id, position_id=None, order=order, command_id=UUID4(), ts_init=0, ) # Act self.exec_client.submit_order(submit_order) await asyncio.sleep(0.3) # Assert request = mock_send_request.call_args[0] assert request[0] == "POST" assert request[1] == "/api/v3/order" assert request[2]["symbol"] == "ETHUSDT" assert request[2]["side"] == "BUY" assert request[2]["type"] == "STOP_LOSS_LIMIT" assert request[2]["timeInForce"] == "GTC" assert request[2]["quantity"] == "10" assert request[2]["price"] == "10050.80" assert request[2]["newClientOrderId"] is not None assert request[2]["stopPrice"] == "10050.00" assert request[2]["recvWindow"] == "5000" assert request[2]["signature"] is not None
def test_execute_command(self): order = self.strategy.order_factory.market( BTCUSDT_BINANCE.id, OrderSide.BUY, Quantity.from_str("1.00000000"), ) command = SubmitOrder( None, self.trader_id, self.strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) def execute_command(): self.exec_engine.execute(command) self.benchmark.pedantic(execute_command, iterations=100, rounds=100, warmup_rounds=5)
def test_submit_order_when_market_order_and_over_max_notional_then_denies(self): # Arrange self.risk_engine.set_max_notional_per_order(AUDUSD_SIM.id, 1_000_000) # Initialize market quote = TestDataStubs.quote_tick_5decimal(AUDUSD_SIM.id) self.cache.add_quote_tick(quote) self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(10000000), ) submit_order = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Act self.risk_engine.execute(submit_order) # Assert assert self.exec_engine.command_count == 0 # <-- command never reaches engine
async def test_execute_command_places_command_on_queue(self): # Arrange self.risk_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) submit_order = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Act self.risk_engine.execute(submit_order) await asyncio.sleep(0.1) # Assert assert self.risk_engine.qsize() == 0 assert self.risk_engine.command_count == 1 # Tear Down self.risk_engine.stop() await self.risk_engine.get_run_queue_task()
def test_submit_order_when_trading_halted_then_denies_order(self): # Arrange self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) submit_order = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Halt trading self.risk_engine.set_trading_state(TradingState.HALTED) # Act self.risk_engine.execute(submit_order) # Assert assert self.risk_engine.command_count == 1 # <-- command never reaches engine
async def test_submit_market_order(self, mocker): # Arrange mock_send_request = mocker.patch( target= "nautilus_trader.adapters.binance.http.client.BinanceHttpClient.send_request" ) order = self.strategy.order_factory.market( instrument_id=ETHUSDT_PERP_BINANCE.id, order_side=OrderSide.BUY, quantity=Quantity.from_int(1), ) self.cache.add_order(order, None) submit_order = SubmitOrder( trader_id=self.trader_id, strategy_id=self.strategy.id, position_id=None, order=order, command_id=UUID4(), ts_init=0, ) # Act self.exec_client.submit_order(submit_order) await asyncio.sleep(0.3) # Assert request = mock_send_request.call_args[0] assert request[0] == "POST" assert request[1] == "/fapi/v1/order" assert request[2]["symbol"] == "ETHUSDT" # -PERP was stripped assert request[2]["type"] == "MARKET" assert request[2]["side"] == "BUY" assert request[2]["quantity"] == "1" assert request[2]["newClientOrderId"] is not None assert request[2]["recvWindow"] == "5000"
async def test_place_orders_market_on_close(self): instrument = BetfairTestStubs.betting_instrument() market_on_close_order = BetfairTestStubs.market_order( side=OrderSide.BUY, time_in_force=TimeInForce.AT_THE_CLOSE, ) submit_order_command = SubmitOrder( trader_id=TestIdStubs.trader_id(), strategy_id=TestIdStubs.strategy_id(), position_id=PositionId("1"), order=market_on_close_order, command_id=UUID4("be7dffa0-46f2-fce5-d820-c7634d022ca1"), ts_init=0, ) place_orders = order_submit_to_betfair(command=submit_order_command, instrument=instrument) with mock_client_request(response=BetfairResponses. betting_place_order_success()) as req: resp = await self.client.place_orders(**place_orders) assert resp expected = BetfairRequests.betting_place_order_bsp() result = req.call_args.kwargs["json"] assert result == expected
def test_submit_order_when_market_order_and_no_market_then_logs_warning(self): # Arrange self.risk_engine.set_max_notional_per_order(AUDUSD_SIM.id, 1_000_000) self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(10000000), ) submit_order = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Act self.risk_engine.execute(submit_order) # Assert assert self.exec_engine.command_count == 1 # <-- command reaches engine with warning
def test_submit_order_when_reducing_and_sell_order_adds_then_denies(self): # Arrange self.risk_engine.set_max_notional_per_order(AUDUSD_SIM.id, 1_000_000) # Initialize market quote = TestDataStubs.quote_tick_5decimal(AUDUSD_SIM.id) self.cache.add_quote_tick(quote) self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order1 = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(100000), ) submit_order1 = SubmitOrder( self.trader_id, strategy.id, None, order1, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.risk_engine.execute(submit_order1) self.risk_engine.set_trading_state(TradingState.REDUCING) # <-- allow reducing orders only order2 = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(100000), ) submit_order2 = SubmitOrder( self.trader_id, strategy.id, None, order2, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.exec_engine.process(TestEventStubs.order_submitted(order1)) self.exec_engine.process(TestEventStubs.order_accepted(order1)) self.exec_engine.process(TestEventStubs.order_filled(order1, AUDUSD_SIM)) # Act self.risk_engine.execute(submit_order2) # Assert assert self.portfolio.is_net_short(AUDUSD_SIM.id) assert self.exec_engine.command_count == 1 # <-- command never reaches engine
async def test_message_qsize_at_max_blocks_on_put_command(self): # Arrange # Deregister test fixture ExecutionEngine from msgbus) self.msgbus.deregister( endpoint="ExecEngine.execute", handler=self.exec_engine.execute, ) self.msgbus.deregister( endpoint="ExecEngine.process", handler=self.exec_engine.process, ) self.msgbus.deregister( endpoint="ExecEngine.reconcile_report", handler=self.exec_engine.reconcile_report, ) self.msgbus.deregister( endpoint="ExecEngine.reconcile_mass_status", handler=self.exec_engine.reconcile_mass_status, ) self.exec_engine = LiveExecutionEngine( loop=self.loop, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, config=LiveExecEngineConfig(qsize=1), ) strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) submit_order = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Act self.exec_engine.execute(submit_order) self.exec_engine.execute(submit_order) await asyncio.sleep(0.1) # Assert assert self.exec_engine.qsize() == 1 assert self.exec_engine.command_count == 0
def test_submit_order_when_position_already_closed_then_denies(self): # Arrange self.exec_engine.start() strategy = TradingStrategy() strategy.register( trader_id=self.trader_id, portfolio=self.portfolio, msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) order1 = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order2 = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(100000), ) order3 = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) submit_order1 = SubmitOrder( trader_id=self.trader_id, strategy_id=strategy.id, position_id=None, order=order1, command_id=self.uuid_factory.generate(), ts_init=self.clock.timestamp_ns(), ) self.risk_engine.execute(submit_order1) self.exec_engine.process(TestEventStubs.order_submitted(order1)) self.exec_engine.process(TestEventStubs.order_accepted(order1)) self.exec_engine.process(TestEventStubs.order_filled(order1, AUDUSD_SIM)) submit_order2 = SubmitOrder( trader_id=self.trader_id, strategy_id=strategy.id, position_id=PositionId("P-19700101-000000-000-000-1"), order=order2, command_id=self.uuid_factory.generate(), ts_init=self.clock.timestamp_ns(), ) self.risk_engine.execute(submit_order2) self.exec_engine.process(TestEventStubs.order_submitted(order2)) self.exec_engine.process(TestEventStubs.order_accepted(order2)) self.exec_engine.process(TestEventStubs.order_filled(order2, AUDUSD_SIM)) submit_order3 = SubmitOrder( trader_id=self.trader_id, strategy_id=strategy.id, position_id=PositionId("P-19700101-000000-000-000-1"), order=order3, command_id=self.uuid_factory.generate(), ts_init=self.clock.timestamp_ns(), ) # Act self.risk_engine.execute(submit_order3) # Assert assert self.exec_engine.command_count == 2 assert self.exec_client.calls == ["_start", "submit_order", "submit_order"]