def test_apply_order_filled_event_to_order_without_accepted(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) filled = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), ) # Act order.apply(filled) # Assert assert order.status == OrderStatus.FILLED assert order.filled_qty == Quantity.from_int(100000) assert order.leaves_qty == Quantity.zero() assert order.avg_px == Decimal("1.00001") assert len(order.execution_ids) == 1 assert not order.is_active assert not order.is_inflight assert not order.is_working assert order.is_completed assert order.ts_last == 0
def test_add_order_state_report(self): # Arrange report = ExecutionMassStatus( client_id=ClientId("IB"), account_id=TestStubs.account_id(), timestamp_ns=0, ) venue_order_id = VenueOrderId("1") order_report = OrderStatusReport( client_order_id=ClientOrderId("O-123456"), venue_order_id=venue_order_id, order_state=OrderState.REJECTED, filled_qty=Quantity.zero(), timestamp_ns=0, ) # Act report.add_order_report(order_report) # Assert assert report.order_reports()[venue_order_id] == order_report assert ( repr(report) == "ExecutionMassStatus(client_id=IB, account_id=SIM-000, timestamp_ns=0, order_reports={VenueOrderId('1'): OrderStatusReport(client_order_id=O-123456, venue_order_id=1, order_state=REJECTED, filled_qty=0, timestamp_ns=0)}, exec_reports={}, position_reports={})" # noqa ) assert ( repr(order_report) == "OrderStatusReport(client_order_id=O-123456, venue_order_id=1, order_state=REJECTED, filled_qty=0, timestamp_ns=0)" # noqa )
def test_add_position_state_report(self): report = ExecutionMassStatus( client_id=ClientId("IB"), account_id=TestStubs.account_id(), timestamp_ns=0, ) position_report = PositionStatusReport( instrument_id=AUDUSD_SIM, position_side=PositionSide.FLAT, qty=Quantity.zero(), timestamp_ns=0, ) # Act report.add_position_report(position_report) # Assert assert report.position_reports()[AUDUSD_SIM] == position_report assert ( repr(report) == "ExecutionMassStatus(client_id=IB, account_id=SIM-000, timestamp_ns=0, order_reports={}, exec_reports={}, position_reports={InstrumentId('AUD/USD.SIM'): PositionStatusReport(instrument_id=AUD/USD.SIM, side=FLAT, qty=0, timestamp_ns=0)})" # noqa ) # noqa assert ( repr(position_report) == "PositionStatusReport(instrument_id=AUD/USD.SIM, side=FLAT, qty=0, timestamp_ns=0)" # noqa ) # noqa
def test_zero_returns_zero_quantity(self): # Arrange, Act qty = Quantity.zero() # Assert assert qty == 0 assert str(qty) == "0" assert qty.precision == 0
async def generate_order_status_report(self, order) -> Optional[OrderStatusReport]: return [ OrderStatusReport( client_order_id=ClientOrderId(), venue_order_id=VenueOrderId(), order_status=OrderStatus(), filled_qty=Quantity.zero(), ts_init=int(pd.Timestamp(order["timestamp"]).to_datetime64()), ) for order in self.client().betting.list_current_orders()["currentOrders"] ]
async def generate_order_status_report(self, order) -> Optional[OrderStatusReport]: return [ OrderStatusReport( client_order_id=ClientOrderId(), venue_order_id=VenueOrderId(), order_state=OrderState(), filled_qty=Quantity.zero(), timestamp_ns=millis_to_nanos(), ) for order in self.client().betting.list_current_orders()["currentOrders"] ]
async def test_reconcile_state_when_order_completed_returns_true_with_warning1( self): # Arrange self.exec_engine.start() 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.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) submit_order = SubmitOrder( self.trader_id, strategy.id, None, order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.risk_engine.execute(submit_order) await asyncio.sleep(0) # Process queue self.exec_engine.process(TestStubs.event_order_submitted(order)) await asyncio.sleep(0) # Process queue self.exec_engine.process(TestStubs.event_order_accepted(order)) await asyncio.sleep(0) # Process queue self.exec_engine.process(TestStubs.event_order_canceled(order)) await asyncio.sleep(0) # Process queue report = OrderStatusReport( client_order_id=order.client_order_id, venue_order_id=VenueOrderId("1"), # <-- from stub event order_status=OrderStatus.CANCELED, filled_qty=Quantity.zero(), ts_init=0, ) # Act result = await self.client.reconcile_state(report, order) # Assert assert result
async def test_reconcile_state_when_expired_reconciles(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(100000), Price.from_str("1.00000"), ) submit_order = SubmitOrder( self.trader_id, strategy.id, None, 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_status=OrderStatus.EXPIRED, filled_qty=Quantity.zero(), ts_init=0, ) self.client.add_order_status_report(report) await asyncio.sleep(0.1) # Allow processing time # Act result = await self.exec_engine.reconcile_state(timeout_secs=10) self.exec_engine.stop() # Assert assert result
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.EXPIRED, filled_qty=Quantity.zero(), timestamp_ns=0, ) self.client.add_order_status_report(report) 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_market_order_with_invalid_tif_raises_value_error(self): # Arrange, Act, Assert with pytest.raises(ValueError): MarketOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity.zero(), TimeInForce.GTD, # <-- invalid UUID4(), 0, )
def test_calculate_with_zero_risk_returns_quantity_zero(self): # Arrange equity = Money(0, USD) # No equity # Act result = self.sizer.calculate( entry=Price.from_str("1.00100"), stop_loss=Price.from_str("1.00100"), equity=equity, risk=Decimal("0.001"), # 0.1% exchange_rate=Decimal("0"), ) # Assert assert result == Quantity.zero()
def test_calculate_single_unit_size_when_risk_too_high(self): # Arrange equity = Money(100000, USD) # Act result = self.sizer.calculate( entry=Price.from_str("3.00000"), stop_loss=Price.from_str("1.00000"), equity=equity, risk=Decimal("0.01"), # 1% unit_batch_size=Decimal(1000), ) # Assert assert result == Quantity.zero()
def test_market_order_with_quantity_zero_raises_value_error(self): # Arrange # Act self.assertRaises( ValueError, MarketOrder, ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity.zero(), TimeInForce.DAY, uuid4(), 0, )
def test_position_long_with_multiple_filled_orders_returns_expected_attributes( self, ): # Arrange order1 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order2 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order3 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(200000), ) fill1 = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), ) fill2 = TestStubs.event_order_filled( order2, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), ) fill3 = TestStubs.event_order_filled( order3, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00010"), ) last = Price.from_str("1.00050") # Act position = Position(instrument=AUDUSD_SIM, fill=fill1) position.apply(fill2) position.apply(fill3) # Assert self.assertEqual(Quantity.zero(), position.quantity) self.assertEqual(PositionSide.FLAT, position.side) self.assertEqual(0, position.opened_timestamp_ns) self.assertEqual(Decimal("1.000005"), position.avg_px_open) self.assertEqual(3, position.event_count) self.assertEqual( [ order1.client_order_id, order2.client_order_id, order3.client_order_id ], position.client_order_ids, ) self.assertEqual(0, position.closed_timestamp_ns) self.assertEqual(Decimal("1.0001"), position.avg_px_close) self.assertFalse(position.is_long) self.assertFalse(position.is_short) self.assertFalse(position.is_open) self.assertTrue(position.is_closed) self.assertEqual(Money(11.00, USD), position.realized_pnl) self.assertEqual(Money(0, USD), position.unrealized_pnl(last)) self.assertEqual(Money(11.00, USD), position.total_pnl(last)) self.assertEqual([Money(8.00, USD)], position.commissions()) self.assertEqual("Position(FLAT AUD/USD.SIM, id=P-123456)", repr(position))
def test_position_filled_with_no_change_returns_expected_attributes(self): # Arrange order1 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order2 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(100000), ) fill1 = TestEventStubs.order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-19700101-000000-000-001-1"), ) position = Position(instrument=AUDUSD_SIM, fill=fill1) fill2 = TestEventStubs.order_filled( order2, instrument=AUDUSD_SIM, position_id=PositionId("P-19700101-000000-000-001-1"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00000"), ) last = Price.from_str("1.00050") # Act position.apply(fill2) # Assert assert position.quantity == Quantity.zero() assert position.side == PositionSide.FLAT assert position.ts_opened == 0 assert position.avg_px_open == Decimal("1.0") assert position.event_count == 2 assert position.client_order_ids == [ order1.client_order_id, order2.client_order_id ] assert position.trade_ids == [ TradeId("E-19700101-000000-000-001-1"), TradeId("E-19700101-000000-000-001-2"), ] assert position.ts_closed == 0 assert position.avg_px_close == Decimal("1.0") assert not position.is_long assert not position.is_short assert not position.is_open assert position.is_closed assert position.realized_points == 0 assert position.realized_return == 0 assert position.realized_pnl == Money(-4.00, USD) assert position.unrealized_pnl(last) == Money(0, USD) assert position.total_pnl(last) == Money(-4.00, USD) assert position.commissions() == [Money(4.00, USD)] assert repr( position ) == "Position(FLAT AUD/USD.SIM, id=P-19700101-000000-000-001-1)"
def test_position_long_with_multiple_filled_orders_returns_expected_attributes( self, ): # Arrange order1 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order2 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order3 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(200000), ) fill1 = TestEventStubs.order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), ) fill2 = TestEventStubs.order_filled( order2, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), ) fill3 = TestEventStubs.order_filled( order3, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00010"), ) last = Price.from_str("1.00050") # Act position = Position(instrument=AUDUSD_SIM, fill=fill1) position.apply(fill2) position.apply(fill3) # Assert assert position.quantity == Quantity.zero() assert position.side == PositionSide.FLAT assert position.ts_opened == 0 assert position.avg_px_open == Decimal("1.000005") assert position.event_count == 3 assert position.client_order_ids == [ order1.client_order_id, order2.client_order_id, order3.client_order_id, ] assert position.ts_closed == 0 assert position.avg_px_close == Decimal("1.0001") assert not position.is_long assert not position.is_short assert not position.is_open assert position.is_closed assert position.realized_pnl == Money(11.00, USD) assert position.unrealized_pnl(last) == Money(0, USD) assert position.total_pnl(last) == Money(11.00, USD) assert position.commissions() == [Money(8.00, USD)] assert repr(position) == "Position(FLAT AUD/USD.SIM, id=P-123456)"
def test_position_filled_with_buy_order_then_sell_order_returns_expected_attributes( self, ): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(150000), ) fill1 = TestEventStubs.order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), ts_filled_ns=1_000_000_000, ) position = Position(instrument=AUDUSD_SIM, fill=fill1) fill2 = OrderFilled( self.trader_id, StrategyId("S-001"), self.account_id, order.instrument_id, order.client_order_id, VenueOrderId("2"), TradeId("E2"), PositionId("T123456"), OrderSide.SELL, OrderType.MARKET, order.quantity, Price.from_str("1.00011"), AUDUSD_SIM.quote_currency, Money(0, USD), LiquiditySide.TAKER, UUID4(), 2_000_000_000, 0, ) last = Price.from_str("1.00050") # Act position.apply(fill2) # Assert assert position.is_opposite_side(fill2.order_side) assert position.quantity == Quantity.zero() assert position.side == PositionSide.FLAT assert position.ts_opened == 1_000_000_000 assert position.duration_ns == 1_000_000_000 assert position.avg_px_open == Decimal("1.00001") assert position.event_count == 2 assert position.ts_closed == 2_000_000_000 assert position.avg_px_close == Decimal("1.00011") assert not position.is_long assert not position.is_short assert not position.is_open assert position.is_closed assert position.realized_points == Decimal("0.00010") assert position.realized_return == Decimal( "0.00009999900000999990000099999000") assert position.realized_pnl == Money(12.00, USD) assert position.unrealized_pnl(last) == Money(0, USD) assert position.total_pnl(last) == Money(12.00, USD) assert position.commissions() == [Money(3.00, USD)] assert repr(position) == "Position(FLAT AUD/USD.SIM, id=P-123456)"
def test_position_filled_with_buy_order_then_sell_order_returns_expected_attributes( self, ): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(150000), ) fill1 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), execution_ns=1_000_000_000, ) position = Position(instrument=AUDUSD_SIM, fill=fill1) fill2 = OrderFilled( self.account_id, order.client_order_id, VenueOrderId("2"), ExecutionId("E2"), PositionId("T123456"), StrategyId("S-001"), order.instrument_id, OrderSide.SELL, order.quantity, Price.from_str("1.00011"), AUDUSD_SIM.quote_currency, Money(0, USD), LiquiditySide.TAKER, 2_000_000_000, uuid4(), 0, ) last = Price.from_str("1.00050") # Act position.apply(fill2) # Assert assert position.is_opposite_side(fill2.order_side) self.assertEqual(Quantity.zero(), position.quantity) self.assertEqual(PositionSide.FLAT, position.side) self.assertEqual(1_000_000_000, position.opened_timestamp_ns) self.assertEqual(1_000_000_000, position.open_duration_ns) self.assertEqual(Decimal("1.00001"), position.avg_px_open) self.assertEqual(2, position.event_count) self.assertEqual(2_000_000_000, position.closed_timestamp_ns) self.assertEqual(Decimal("1.00011"), position.avg_px_close) self.assertFalse(position.is_long) self.assertFalse(position.is_short) self.assertFalse(position.is_open) self.assertTrue(position.is_closed) self.assertEqual(Decimal("0.00010"), position.realized_points) self.assertEqual(Decimal("0.00009999900000999990000099999000"), position.realized_return) self.assertEqual(Money(12.00, USD), position.realized_pnl) self.assertEqual(Money(0, USD), position.unrealized_pnl(last)) self.assertEqual(Money(12.00, USD), position.total_pnl(last)) self.assertEqual([Money(3.00, USD)], position.commissions()) self.assertEqual("Position(FLAT AUD/USD.SIM, id=P-123456)", repr(position))