def test_handle_position_opening_with_position_id_none(self): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) submit_order = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.utc_now(), ) self.exec_engine.execute(submit_order) # Act self.exec_engine.process(TestStubs.event_order_submitted(order)) self.exec_engine.process(TestStubs.event_order_accepted(order)) self.exec_engine.process(TestStubs.event_order_filled(order, AUDUSD_SIM, PositionId.null())) expected_id = PositionId("P-000-AUD/USD.SIM-1") # Generated inside engine # Assert self.assertTrue(self.cache.position_exists(expected_id)) self.assertTrue(self.cache.is_position_open(expected_id)) self.assertFalse(self.cache.is_position_closed(expected_id)) self.assertEqual(Position, type(self.cache.position(expected_id))) self.assertIn(expected_id, self.cache.position_ids()) self.assertNotIn(expected_id, self.cache.position_closed_ids(strategy_id=strategy.id)) self.assertNotIn(expected_id, self.cache.position_closed_ids()) self.assertIn(expected_id, self.cache.position_open_ids(strategy_id=strategy.id)) self.assertIn(expected_id, self.cache.position_open_ids()) self.assertEqual(1, self.cache.positions_total_count()) self.assertEqual(1, self.cache.positions_open_count()) self.assertEqual(0, self.cache.positions_closed_count())
def test_position_identifier(self): # Arrange # Act position_id0 = PositionId.null() # Assert self.assertEqual("P-NULL", position_id0.value)
def test_submit_order_when_not_connected_logs_and_does_not_send(self): # Arrange strategy = TradingStrategy("000") order = self.order_factory.market( ETHUSDT_BINANCE.symbol, OrderSide.BUY, Quantity(100), ) command = SubmitOrder( BINANCE, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.utc_now(), ) # Act self.exec_client.submit_order(command) # Assert self.assertEqual(OrderState.INITIALIZED, order.state)
def test_submit_order_when_not_connected_logs_and_does_not_send(self): # Arrange strategy = TradingStrategy("000") order = self.order_factory.market( ETHUSDT_BINANCE.id, OrderSide.BUY, Quantity(100), ) command = SubmitOrder( order.instrument_id.venue.client_id, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Act self.exec_client.submit_order(command) # Assert assert order.state == OrderState.INITIALIZED
def test_unrealized_pnl_when_insufficient_data_for_xrate_returns_none( self): # Arrange state = AccountState( account_id=AccountId("BITMEX", "01234"), account_type=AccountType.MARGIN, base_currency=BTC, reported=True, balances=[ AccountBalance( BTC, Money(10.00000000, BTC), Money(0.00000000, BTC), Money(10.00000000, BTC), ), AccountBalance( ETH, Money(20.00000000, ETH), Money(0.00000000, ETH), Money(20.00000000, ETH), ), ], info={}, event_id=uuid4(), updated_ns=0, timestamp_ns=0, ) self.exec_engine.process(state) order = self.order_factory.market( ETHUSD_BITMEX.id, OrderSide.BUY, Quantity.from_int(100), ) self.exec_engine.cache.add_order(order, PositionId.null()) self.exec_engine.process(TestStubs.event_order_submitted(order)) self.exec_engine.process(TestStubs.event_order_accepted(order)) fill = TestStubs.event_order_filled( order=order, instrument=ETHUSD_BITMEX, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("376.05"), ) self.exec_engine.process(fill) position = Position(instrument=ETHUSD_BITMEX, fill=fill) self.portfolio.update_position( TestStubs.event_position_opened(position)) # Act result = self.portfolio.unrealized_pnls(BITMEX) # # Assert self.assertEqual({}, result)
def test_position_identifier(self): # Arrange # Act position_id0 = PositionId.null() # Assert assert "NULL" == position_id0.value
def test_submit_order_with_default_settings_sends_to_client(self): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000), ) submit_order = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.utc_now(), ) # Act self.risk_engine.execute(submit_order) # Assert assert self.exec_client.calls == ['connect', 'submit_order']
async def run_test(): # Arrange self.engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.engine.register_strategy(strategy) order = strategy.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) submit_order = SubmitOrder( AUDUSD_SIM.id, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.engine.execute(submit_order) self.engine.process(TestStubs.event_order_submitted(order)) self.engine.process(TestStubs.event_order_accepted(order)) report = OrderStatusReport( client_order_id=order.client_order_id, venue_order_id=VenueOrderId("1"), # <-- from stub event order_state=OrderState.EXPIRED, filled_qty=Quantity(0), timestamp_ns=0, ) self.client.add_order_status_report(report) await asyncio.sleep(0.01) # Act result = await self.engine.reconcile_state() self.engine.stop() # Assert assert result
def test_update_order_with_default_settings_sends_to_client(self): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER-000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) 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, PositionId.null(), order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) update = UpdateOrder( self.trader_id, strategy.id, order.instrument_id, order.client_order_id, order.venue_order_id, 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(update) # Assert assert self.exec_client.calls == [ "connect", "submit_order", "update_order" ] assert self.risk_engine.command_count == 2 assert self.exec_engine.command_count == 2
def test_cancel_order_with_default_settings_sends_to_client(self): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000), ) submit = SubmitOrder( order.instrument_id.venue.client_id, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) cancel = CancelOrder( order.instrument_id.venue.client_id, self.trader_id, self.account_id, order.instrument_id, order.client_order_id, order.venue_order_id, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.risk_engine.execute(submit) # Act self.risk_engine.execute(cancel) # Assert assert self.exec_client.calls == [ "connect", "submit_order", "cancel_order" ]
def event_order_filled( order, instrument, position_id=None, strategy_id=None, fill_price=None, fill_qty=None, liquidity_side=LiquiditySide.TAKER, ) -> OrderFilled: if position_id is None: position_id = PositionId.null() if strategy_id is None: strategy_id = StrategyId.null() if fill_price is None: fill_price = Price("1.00000") if fill_qty is None: fill_qty = order.quantity commission = instrument.calculate_commission( quantity=order.quantity, avg_price=fill_price, liquidity_side=liquidity_side, ) return OrderFilled( account_id=TestStubs.account_id(), cl_ord_id=order.cl_ord_id, order_id=order.id, execution_id=ExecutionId(order.cl_ord_id.value.replace("O", "E")), position_id=position_id, strategy_id=strategy_id, symbol=order.symbol, order_side=order.side, fill_qty=fill_qty, cum_qty=Quantity(order.filled_qty + fill_qty), leaves_qty=Quantity( max(0, order.quantity - order.filled_qty - fill_qty)), fill_price=order.price if fill_price is None else fill_price, currency=instrument.quote_currency, is_inverse=instrument.is_inverse, commission=commission, liquidity_side=liquidity_side, execution_time=UNIX_EPOCH, event_id=uuid4(), event_timestamp=UNIX_EPOCH, )
def test_message_qsize_at_max_blocks_on_put_event(self): # Arrange self.risk_engine = LiveRiskEngine( loop=self.loop, exec_engine=self.exec_engine, portfolio=self.portfolio, clock=self.clock, logger=self.logger, config={"qsize": 1}, ) strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000), ) submit_order = SubmitOrder( order.instrument_id, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) event = TestStubs.event_order_submitted(order) # Act self.risk_engine.execute(submit_order) self.risk_engine.process(event) # Add over max size # Assert assert self.risk_engine.qsize() == 1 assert self.risk_engine.event_count == 0
def test_message_qsize_at_max_blocks_on_put_event(self): # Arrange self.exec_engine = LiveExecutionEngine(loop=self.loop, database=self.database, portfolio=self.portfolio, clock=self.clock, logger=self.logger, config={"qsize": 1}) strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) submit_order = SubmitOrder( Venue("SIM"), self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.utc_now(), ) event = TestStubs.event_order_submitted(order) # Act self.exec_engine.execute(submit_order) self.exec_engine.process(event) # Add over max size # Assert self.assertEqual(1, self.exec_engine.qsize()) self.assertEqual(0, self.exec_engine.command_count)
def test_message_qsize_at_max_blocks_on_put_command(self): # Arrange self.exec_engine = LiveExecutionEngine( loop=self.loop, portfolio=self.portfolio, cache=self.cache, clock=self.clock, logger=self.logger, config={"qsize": 1}, ) self.exec_engine.register_risk_engine(self.risk_engine) strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER-000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) submit_order = SubmitOrder( self.trader_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Act self.exec_engine.execute(submit_order) self.exec_engine.execute(submit_order) # Assert assert self.exec_engine.qsize() == 1 assert self.exec_engine.command_count == 0
def test_submit_order_raises_exception(self): order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(100000), Price.from_str("1.00000"), ) command = SubmitOrder( self.trader_id, order.strategy_id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.assertRaises(NotImplementedError, self.client.submit_order, command)
def test_submit_order_raises_exception(self): order = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.SELL, Quantity(100000), Price("1.00000"), ) command = SubmitOrder( self.venue, self.trader_id, self.account_id, StrategyId("SCALPER", "001"), PositionId.null(), order, self.uuid_factory.generate(), self.clock.utc_now(), ) self.assertRaises(NotImplementedError, self.client.submit_order, command)
def test_execute_command(self): order = self.strategy.order_factory.market( BTCUSDT_BINANCE.id, OrderSide.BUY, Quantity.from_str("1.00000000"), ) command = SubmitOrder( self.trader_id, self.strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) def execute_command(): self.exec_engine.execute(command) self.benchmark.pedantic(execute_command, iterations=10_000, rounds=1)
async def run_test(): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) submit_order = SubmitOrder( Venue("SIM"), self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.utc_now(), ) # Act self.exec_engine.execute(submit_order) await asyncio.sleep(0.1) # Assert self.assertEqual(0, self.exec_engine.qsize()) self.assertEqual(1, self.exec_engine.command_count) # Tear Down self.exec_engine.stop()
async def run_test(): # Arrange self.risk_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000), ) submit_order = SubmitOrder( order.instrument_id, self.trader_id, self.account_id, strategy.id, PositionId.null(), 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()
def test_execute_command(self): order = self.strategy.order_factory.market( BTCUSDT_BINANCE.symbol, OrderSide.BUY, Quantity("1.00000000"), ) command = SubmitOrder( order.symbol.venue, self.trader_id, self.account_id, self.strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.utc_now(), ) def execute_command(): self.exec_engine.execute(command) PerformanceHarness.profile_function(execute_command, 10000, 1)
def test_submit_order_when_block_all_orders_true_then_denies_order(self): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000), ) submit_order = SubmitOrder( order.instrument_id.venue.client_id, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.risk_engine.set_block_all_orders() # Act self.exec_engine.execute(submit_order) # Assert assert self.exec_client.calls == ["connect"] assert self.exec_engine.event_count == 1
def test_submit_order(self): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) submit_order = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.utc_now(), ) # Act self.exec_engine.execute(submit_order) # Assert self.assertIn(submit_order, self.exec_client.commands) self.assertTrue(self.cache.order_exists(order.cl_ord_id))
async def run_test(): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER-000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order = strategy.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) submit_order = SubmitOrder( self.trader_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.exec_engine.execute(submit_order) self.exec_engine.process(TestStubs.event_order_submitted(order)) self.exec_engine.process(TestStubs.event_order_accepted(order)) report = OrderStatusReport( client_order_id=order.client_order_id, venue_order_id=VenueOrderId("1"), # <-- from stub event order_state=OrderState.PARTIALLY_FILLED, filled_qty=Quantity.from_int(70000), timestamp_ns=0, ) trade1 = ExecutionReport( client_order_id=order.client_order_id, venue_order_id=VenueOrderId("1"), execution_id=ExecutionId("1"), last_qty=Quantity.from_int(50000), last_px=Price.from_str("1.00000"), commission=Money(5.00, USD), liquidity_side=LiquiditySide.MAKER, ts_filled_ns=0, timestamp_ns=0, ) trade2 = ExecutionReport( client_order_id=order.client_order_id, venue_order_id=VenueOrderId("1"), execution_id=ExecutionId("2"), last_qty=Quantity.from_int(20000), last_px=Price.from_str("1.00000"), commission=Money(2.00, USD), liquidity_side=LiquiditySide.MAKER, ts_filled_ns=0, timestamp_ns=0, ) self.client.add_order_status_report(report) self.client.add_trades_list(VenueOrderId("1"), [trade1, trade2]) await asyncio.sleep(0.01) # Act result = await self.exec_engine.reconcile_state(timeout_secs=10) self.exec_engine.stop() # Assert assert result
def test_flip_position_on_opposite_filled_same_position_buy(self): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order1 = strategy.order_factory.market( AUDUSD_SIM.symbol, OrderSide.SELL, Quantity(100000), ) order2 = strategy.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(150000), ) submit_order1 = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy.id, PositionId.null(), order1, self.uuid_factory.generate(), self.clock.utc_now(), ) position_id = PositionId("P-000-AUD/USD.SIM-1") self.exec_engine.execute(submit_order1) self.exec_engine.process(TestStubs.event_order_submitted(order1)) self.exec_engine.process(TestStubs.event_order_accepted(order1)) self.exec_engine.process( TestStubs.event_order_filled(order1, AUDUSD_SIM, position_id)) submit_order2 = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy.id, position_id, order2, self.uuid_factory.generate(), self.clock.utc_now(), ) # Act self.exec_engine.execute(submit_order2) self.exec_engine.process(TestStubs.event_order_submitted(order2)) self.exec_engine.process(TestStubs.event_order_accepted(order2)) self.exec_engine.process( TestStubs.event_order_filled(order2, AUDUSD_SIM, position_id)) position_id_flipped = PositionId("P-000-AUD/USD.SIM-1F") # Assert position_flipped = self.cache.position(position_id_flipped) self.assertEqual(50000, position_flipped.relative_quantity) self.assertTrue(self.cache.position_exists(position_id)) self.assertTrue(self.cache.position_exists(position_id_flipped)) self.assertTrue(self.cache.is_position_closed(position_id)) self.assertTrue(self.cache.is_position_open(position_id_flipped)) self.assertIn(position_id, self.cache.position_ids()) self.assertIn(position_id, self.cache.position_ids(strategy_id=strategy.id)) self.assertIn(position_id_flipped, self.cache.position_ids()) self.assertIn(position_id_flipped, self.cache.position_ids(strategy_id=strategy.id)) self.assertEqual(2, self.cache.positions_total_count()) self.assertEqual(1, self.cache.positions_open_count()) self.assertEqual(1, self.cache.positions_closed_count())
def test_multiple_strategy_positions_one_active_one_closed(self): # Arrange self.exec_engine.start() strategy1 = TradingStrategy(order_id_tag="001") strategy1.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) strategy2 = TradingStrategy(order_id_tag="002") strategy2.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy1) self.exec_engine.register_strategy(strategy2) order1 = strategy1.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) order2 = strategy1.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.SELL, Quantity(100000), Price("1.00000"), ) order3 = strategy2.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) submit_order1 = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy1.id, PositionId.null(), order1, self.uuid_factory.generate(), self.clock.utc_now(), ) position_id1 = PositionId('P-1') submit_order2 = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy1.id, position_id1, order2, self.uuid_factory.generate(), self.clock.utc_now(), ) submit_order3 = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy2.id, PositionId.null(), order3, self.uuid_factory.generate(), self.clock.utc_now(), ) position_id2 = PositionId('P-2') # Act self.exec_engine.execute(submit_order1) self.exec_engine.process(TestStubs.event_order_submitted(order1)) self.exec_engine.process(TestStubs.event_order_accepted(order1)) self.exec_engine.process( TestStubs.event_order_filled(order1, AUDUSD_SIM, position_id1)) self.exec_engine.execute(submit_order2) self.exec_engine.process(TestStubs.event_order_submitted(order2)) self.exec_engine.process(TestStubs.event_order_accepted(order2)) self.exec_engine.process( TestStubs.event_order_filled(order2, AUDUSD_SIM, position_id1)) self.exec_engine.execute(submit_order3) self.exec_engine.process(TestStubs.event_order_submitted(order3)) self.exec_engine.process(TestStubs.event_order_accepted(order3)) self.exec_engine.process( TestStubs.event_order_filled(order3, AUDUSD_SIM, position_id2)) # Assert # Already tested .is_position_active and .is_position_closed above self.assertTrue(self.cache.position_exists(position_id1)) self.assertTrue(self.cache.position_exists(position_id2)) self.assertIn(position_id1, self.cache.position_ids(strategy_id=strategy1.id)) self.assertIn(position_id2, self.cache.position_ids(strategy_id=strategy2.id)) self.assertIn(position_id1, self.cache.position_ids()) self.assertIn(position_id2, self.cache.position_ids()) self.assertEqual( 0, len(self.cache.positions_open(strategy_id=strategy1.id))) self.assertEqual( 1, len(self.cache.positions_open(strategy_id=strategy2.id))) self.assertEqual(1, len(self.cache.positions_open())) self.assertEqual(1, len(self.cache.positions_closed())) self.assertEqual(2, len(self.cache.positions())) self.assertNotIn( position_id1, self.cache.position_open_ids(strategy_id=strategy1.id)) self.assertIn(position_id2, self.cache.position_open_ids(strategy_id=strategy2.id)) self.assertNotIn(position_id1, self.cache.position_open_ids()) self.assertIn(position_id2, self.cache.position_open_ids()) self.assertIn(position_id1, self.cache.position_closed_ids(strategy_id=strategy1.id)) self.assertNotIn( position_id2, self.cache.position_closed_ids(strategy_id=strategy2.id)) self.assertIn(position_id1, self.cache.position_closed_ids()) self.assertNotIn(position_id2, self.cache.position_closed_ids()) self.assertEqual(2, self.cache.positions_total_count()) self.assertEqual(1, self.cache.positions_open_count()) self.assertEqual(1, self.cache.positions_closed_count())
def test_close_position_on_order_fill(self): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order1 = strategy.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) order2 = strategy.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.SELL, Quantity(100000), Price("1.00000"), ) submit_order1 = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy.id, PositionId.null(), order1, self.uuid_factory.generate(), self.clock.utc_now(), ) position_id = PositionId("P-1") self.exec_engine.execute(submit_order1) self.exec_engine.process(TestStubs.event_order_submitted(order1)) self.exec_engine.process(TestStubs.event_order_accepted(order1)) self.exec_engine.process( TestStubs.event_order_filled(order1, AUDUSD_SIM, position_id)) submit_order2 = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy.id, position_id, order2, self.uuid_factory.generate(), self.clock.utc_now(), ) # Act self.exec_engine.execute(submit_order2) self.exec_engine.process(TestStubs.event_order_submitted(order2)) self.exec_engine.process(TestStubs.event_order_accepted(order2)) self.exec_engine.process( TestStubs.event_order_filled(order2, AUDUSD_SIM, position_id)) # # Assert self.assertTrue(self.cache.position_exists(position_id)) self.assertFalse(self.cache.is_position_open(position_id)) self.assertTrue(self.cache.is_position_closed(position_id)) self.assertEqual(position_id, self.cache.position(position_id).id) self.assertEqual(position_id, self.cache.positions(strategy_id=strategy.id)[0].id) self.assertEqual(position_id, self.cache.positions()[0].id) self.assertEqual( 0, len(self.cache.positions_open(strategy_id=strategy.id))) self.assertEqual(0, len(self.cache.positions_open())) self.assertEqual( position_id, self.cache.positions_closed(strategy_id=strategy.id)[0].id) self.assertEqual(position_id, self.cache.positions_closed()[0].id) self.assertNotIn(position_id, self.cache.position_open_ids(strategy_id=strategy.id)) self.assertNotIn(position_id, self.cache.position_open_ids()) self.assertEqual(1, self.cache.positions_total_count()) self.assertEqual(0, self.cache.positions_open_count()) self.assertEqual(1, self.cache.positions_closed_count())
def test_add_to_existing_position_on_order_fill(self): # Arrange self.exec_engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.exec_engine.register_strategy(strategy) order1 = strategy.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) order2 = strategy.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) submit_order1 = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy.id, PositionId.null(), order1, self.uuid_factory.generate(), self.clock.utc_now(), ) self.exec_engine.execute(submit_order1) self.exec_engine.process(TestStubs.event_order_submitted(order1)) self.exec_engine.process(TestStubs.event_order_accepted(order1)) self.exec_engine.process( TestStubs.event_order_filled(order1, AUDUSD_SIM)) expected_position_id = PositionId( "O-19700101-000000-000-001-1") # Stubbed from order id? submit_order2 = SubmitOrder( self.venue, self.trader_id, self.account_id, strategy.id, expected_position_id, order2, self.uuid_factory.generate(), self.clock.utc_now(), ) # Act self.exec_engine.execute(submit_order2) self.exec_engine.process(TestStubs.event_order_submitted(order2)) self.exec_engine.process(TestStubs.event_order_accepted(order2)) self.exec_engine.process( TestStubs.event_order_filled(order2, AUDUSD_SIM, expected_position_id)) # Assert self.assertTrue( self.cache.position_exists( TestStubs.event_order_filled( order1, AUDUSD_SIM, ).position_id)) self.assertTrue(self.cache.is_position_open(expected_position_id)) self.assertFalse(self.cache.is_position_closed(expected_position_id)) self.assertEqual(Position, type(self.cache.position(expected_position_id))) self.assertEqual( 0, len(self.cache.positions_closed(strategy_id=strategy.id))) self.assertEqual(0, len(self.cache.positions_closed())) self.assertEqual( 1, len(self.cache.positions_open(strategy_id=strategy.id))) self.assertEqual(1, len(self.cache.positions_open())) self.assertEqual(1, self.cache.positions_total_count()) self.assertEqual(1, self.cache.positions_open_count()) self.assertEqual(0, self.cache.positions_closed_count())
def test_update_positions(self): # Arrange state = AccountState( account_id=AccountId("BINANCE", "01234"), account_type=AccountType.CASH, base_currency=None, # Multi-currency account reported=True, balances=[ AccountBalance( BTC, Money(10.00000000, BTC), Money(0.00000000, BTC), Money(10.00000000, BTC), ), AccountBalance( ETH, Money(20.00000000, ETH), Money(0.00000000, ETH), Money(20.00000000, ETH), ), ], info={}, event_id=uuid4(), updated_ns=0, timestamp_ns=0, ) self.exec_engine.process(state) # Create a closed position order1 = self.order_factory.market( BTCUSDT_BINANCE.id, OrderSide.BUY, Quantity.from_str("10.50000000"), ) order2 = self.order_factory.market( BTCUSDT_BINANCE.id, OrderSide.SELL, Quantity.from_str("10.50000000"), ) self.exec_engine.cache.add_order(order1, PositionId.null()) self.exec_engine.cache.add_order(order2, PositionId.null()) # Push states to ACCEPTED order1.apply(TestStubs.event_order_submitted(order1)) self.exec_engine.cache.update_order(order1) order1.apply(TestStubs.event_order_accepted(order1)) self.exec_engine.cache.update_order(order1) fill1 = TestStubs.event_order_filled( order1, instrument=BTCUSDT_BINANCE, position_id=PositionId("P-1"), strategy_id=StrategyId("S-1"), last_px=Price.from_str("25000.00"), ) fill2 = TestStubs.event_order_filled( order2, instrument=BTCUSDT_BINANCE, position_id=PositionId("P-1"), strategy_id=StrategyId("S-1"), last_px=Price.from_str("25000.00"), ) position1 = Position(instrument=BTCUSDT_BINANCE, fill=fill1) position1.apply(fill2) order3 = self.order_factory.market( BTCUSDT_BINANCE.id, OrderSide.BUY, Quantity.from_str("10.00000000"), ) fill3 = TestStubs.event_order_filled( order3, instrument=BTCUSDT_BINANCE, position_id=PositionId("P-2"), strategy_id=StrategyId("S-1"), last_px=Price.from_str("25000.00"), ) position2 = Position(instrument=BTCUSDT_BINANCE, fill=fill3) # Update the last quote last = QuoteTick( BTCUSDT_BINANCE.id, Price.from_str("25001.00"), Price.from_str("25002.00"), Quantity.from_int(1), Quantity.from_int(1), 0, 0, ) # Act self.cache.add_position(position1) self.cache.add_position(position2) self.portfolio.initialize_positions() self.portfolio.update_tick(last) # Assert self.assertTrue(self.portfolio.is_net_long(BTCUSDT_BINANCE.id))
def test_opening_several_positions_updates_portfolio(self): # Arrange state = AccountState( account_id=AccountId("SIM", "01234"), account_type=AccountType.MARGIN, base_currency=USD, reported=True, balances=[ AccountBalance( USD, Money(1_000_000, USD), Money(0, USD), Money(1_000_000, USD), ), ], info={}, event_id=uuid4(), updated_ns=0, timestamp_ns=0, ) self.exec_engine.process(state) last_audusd = QuoteTick( AUDUSD_SIM.id, Price.from_str("0.80501"), Price.from_str("0.80505"), Quantity.from_int(1), Quantity.from_int(1), 0, 0, ) last_gbpusd = QuoteTick( GBPUSD_SIM.id, Price.from_str("1.30315"), Price.from_str("1.30317"), Quantity.from_int(1), Quantity.from_int(1), 0, 0, ) self.cache.add_quote_tick(last_audusd) self.cache.add_quote_tick(last_gbpusd) self.portfolio.update_tick(last_audusd) self.portfolio.update_tick(last_gbpusd) order1 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order2 = self.order_factory.market( GBPUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) self.exec_engine.cache.add_order(order1, PositionId.null()) self.exec_engine.cache.add_order(order2, PositionId.null()) fill1 = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-1"), strategy_id=StrategyId("S-1"), last_px=Price.from_str("1.00000"), ) fill2 = TestStubs.event_order_filled( order2, instrument=GBPUSD_SIM, position_id=PositionId("P-2"), strategy_id=StrategyId("S-1"), last_px=Price.from_str("1.00000"), ) self.exec_engine.cache.update_order(order1) self.exec_engine.cache.update_order(order2) position1 = Position(instrument=AUDUSD_SIM, fill=fill1) position2 = Position(instrument=GBPUSD_SIM, fill=fill2) position_opened1 = TestStubs.event_position_opened(position1) position_opened2 = TestStubs.event_position_opened(position2) # Act self.cache.add_position(position1) self.cache.add_position(position2) self.portfolio.update_position(position_opened1) self.portfolio.update_position(position_opened2) # Assert self.assertEqual( {USD: Money(210816.00, USD)}, self.portfolio.net_exposures(SIM), ) self.assertEqual( {USD: Money(10816.00, USD)}, self.portfolio.unrealized_pnls(SIM), ) self.assertEqual({USD: Money(3912.06, USD)}, self.portfolio.maint_margins(SIM)), self.assertEqual( Money(80501.00, USD), self.portfolio.net_exposure(AUDUSD_SIM.id), ) self.assertEqual( Money(130315.00, USD), self.portfolio.net_exposure(GBPUSD_SIM.id), ) self.assertEqual( Money(-19499.00, USD), self.portfolio.unrealized_pnl(AUDUSD_SIM.id), ) self.assertEqual( Money(30315.00, USD), self.portfolio.unrealized_pnl(GBPUSD_SIM.id), ) self.assertEqual(Decimal(100000), self.portfolio.net_position(AUDUSD_SIM.id)) self.assertEqual(Decimal(100000), self.portfolio.net_position(GBPUSD_SIM.id)) self.assertTrue(self.portfolio.is_net_long(AUDUSD_SIM.id)) self.assertFalse(self.portfolio.is_net_short(AUDUSD_SIM.id)) self.assertFalse(self.portfolio.is_flat(AUDUSD_SIM.id)) self.assertFalse(self.portfolio.is_completely_flat())
async def run_test(): # Arrange self.engine.start() strategy = TradingStrategy(order_id_tag="001") strategy.register_trader( TraderId("TESTER", "000"), self.clock, self.logger, ) self.engine.register_strategy(strategy) order = strategy.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) submit_order = SubmitOrder( AUDUSD_SIM.id, self.trader_id, self.account_id, strategy.id, PositionId.null(), order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.engine.execute(submit_order) self.engine.process(TestStubs.event_order_submitted(order)) self.engine.process(TestStubs.event_order_accepted(order)) report = OrderStatusReport( client_order_id=order.client_order_id, venue_order_id=VenueOrderId("1"), # <-- from stub event order_state=OrderState.FILLED, filled_qty=Quantity(100000), timestamp_ns=0, ) trade1 = ExecutionReport( execution_id=ExecutionId("1"), client_order_id=order.client_order_id, venue_order_id=VenueOrderId("1"), last_qty=Decimal(50000), last_px=Decimal("1.00000"), commission_amount=Decimal("5.0"), commission_currency="USD", liquidity_side=LiquiditySide.MAKER, execution_ns=0, timestamp_ns=0, ) trade2 = ExecutionReport( execution_id=ExecutionId("2"), client_order_id=order.client_order_id, venue_order_id=VenueOrderId("1"), last_qty=Decimal(50000), last_px=Decimal("1.00000"), commission_amount=Decimal("2.0"), commission_currency="USD", liquidity_side=LiquiditySide.MAKER, execution_ns=0, timestamp_ns=0, ) self.client.add_order_status_report(report) self.client.add_trades_list(VenueOrderId("1"), [trade1, trade2]) await asyncio.sleep(0.01) # Act result = await self.engine.reconcile_state() self.engine.stop() # Assert assert result