class OrderPerformanceTests(unittest.TestCase): def setUp(self): # Fixture Setup self.generator = ClientOrderIdGenerator(IdTag("001"), IdTag("001"), LiveClock()) self.order_factory = OrderFactory( trader_id=TraderId("TESTER", "000"), strategy_id=StrategyId("S", "001"), clock=TestClock(), ) def create_market_order(self): self.order_factory.market( AUDUSD_SIM, OrderSide.BUY, Quantity(100000), ) def create_limit_order(self): self.order_factory.limit( AUDUSD_SIM, OrderSide.BUY, Quantity(100000), Price("0.80010"), ) def test_order_id_generator(self): PerformanceHarness.profile_function(self.generator.generate, 100000, 1) # ~0.0ms / ~2.9μs / 2894ns minimum of 100,000 runs @ 1 iteration each run. def test_market_order_creation(self): PerformanceHarness.profile_function(self.create_market_order, 10000, 1) # ~0.0ms / ~13.8μs / 13801ns minimum of 10,000 runs @ 1 iteration each run. def test_limit_order_creation(self): PerformanceHarness.profile_function(self.create_limit_order, 10000, 1)
class ExecutionClientTests(unittest.TestCase): def setUp(self): # Fixture Setup self.clock = TestClock() self.uuid_factory = UUIDFactory() self.logger = Logger(self.clock) self.trader_id = TraderId("TESTER-000") self.account_id = TestStubs.account_id() self.cache = TestStubs.cache() self.portfolio = Portfolio( cache=self.cache, clock=self.clock, logger=self.logger, ) self.exec_engine = ExecutionEngine( portfolio=self.portfolio, cache=self.cache, clock=self.clock, logger=self.logger, ) self.venue = Venue("SIM") self.client = ExecutionClient( client_id=ClientId(self.venue.value), venue_type=VenueType.ECN, account_id=TestStubs.account_id(), account_type=AccountType.MARGIN, base_currency=USD, engine=self.exec_engine, clock=self.clock, logger=self.logger, ) self.order_factory = OrderFactory( trader_id=TraderId("TESTER-000"), strategy_id=StrategyId("S-001"), clock=TestClock(), ) def test_venue_when_brokerage_returns_client_id_value_as_venue(self): assert self.client.venue == self.venue def test_venue_when_brokerage_multi_venue_returns_none(self): # Arrange client = ExecutionClient( client_id=ClientId("IB"), venue_type=VenueType.BROKERAGE_MULTI_VENUE, account_id=AccountId("IB", "U1258001"), account_type=AccountType.MARGIN, base_currency=USD, engine=self.exec_engine, clock=self.clock, logger=self.logger, ) # Act, Assert assert client.venue is None def test_connect_when_not_implemented_raises_exception(self): self.assertRaises(NotImplementedError, self.client.connect) def test_disconnect_when_not_implemented_raises_exception(self): self.assertRaises(NotImplementedError, self.client.disconnect) def test_reset_when_not_implemented_raises_exception(self): self.assertRaises(NotImplementedError, self.client.reset) def test_dispose_when_not_implemented_raises_exception(self): self.assertRaises(NotImplementedError, self.client.dispose) 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_bracket_order_raises_not_implemented_error(self): entry_order = self.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("0.99995"), ) # Act bracket_order = self.order_factory.bracket( entry_order, Price.from_str("0.99990"), Price.from_str("1.00010"), ) command = SubmitBracketOrder( self.trader_id, entry_order.strategy_id, bracket_order, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) self.assertRaises(NotImplementedError, self.client.submit_bracket_order, command) def test_update_order_raises_not_implemented_error(self): # Arrange # Act command = UpdateOrder( self.trader_id, StrategyId("SCALPER-001"), AUDUSD_SIM.id, ClientOrderId("O-123456789"), VenueOrderId("001"), Quantity.from_int(120000), Price.from_str("1.00000"), None, self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Assert self.assertRaises(NotImplementedError, self.client.update_order, command) def test_cancel_order_raises_not_implemented_error(self): # Arrange # Act command = CancelOrder( self.trader_id, StrategyId("SCALPER-001"), AUDUSD_SIM.id, ClientOrderId("O-123456789"), VenueOrderId("001"), self.uuid_factory.generate(), self.clock.timestamp_ns(), ) # Assert self.assertRaises(NotImplementedError, self.client.cancel_order, command)
class OrderTests(unittest.TestCase): def setUp(self): # Fixture Setup self.account_id = TestStubs.account_id() self.order_factory = OrderFactory( strategy_id=StrategyId("S", "001"), id_tag_trader=IdTag("001"), id_tag_strategy=IdTag("001"), clock=TestClock(), uuid_factory=TestUUIDFactory(), ) def test_get_opposite_side_returns_expected_sides(self): # Arrange # Act result1 = opposite_side(OrderSide.BUY) result2 = opposite_side(OrderSide.SELL) # Assert self.assertEqual(OrderSide.SELL, result1) self.assertEqual(OrderSide.BUY, result2) def test_get_flatten_side_with_long_or_short_position_side_returns_expected_sides(self): # Arrange # Act result1 = flatten_side(PositionSide.LONG) result2 = flatten_side(PositionSide.SHORT) # Assert self.assertEqual(OrderSide.SELL, result1) self.assertEqual(OrderSide.BUY, result2) def test_market_order_with_quantity_zero_raises_exception(self): # Arrange # Act self.assertRaises( ValueError, MarketOrder, ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_FXCM, OrderSide.BUY, Quantity(), TimeInForce.DAY, uuid4(), UNIX_EPOCH, ) def test_market_order_with_invalid_tif_raises_exception(self): # Arrange # Act self.assertRaises( ValueError, MarketOrder, ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_FXCM, OrderSide.BUY, Quantity(100), TimeInForce.GTD, uuid4(), UNIX_EPOCH, ) def test_stop_order_with_gtd_and_expire_time_none_raises_exception(self): # Arrange # Act self.assertRaises( TypeError, StopMarketOrder, ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), price=Price("1.00000"), init_id=uuid4(), timestamp=UNIX_EPOCH, time_in_force=TimeInForce.GTD, expire_time=None, ) def test_reset_order_factory(self): # Arrange self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) # Act self.order_factory.reset() order2 = self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) self.assertEqual(ClientOrderId("O-19700101-000000-001-001-1"), order2.cl_ord_id) def test_limit_order_can_create_expected_decimal_price(self): # Arrange # Act order1 = self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) order2 = self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) order3 = self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) order4 = self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00001"), ) # Assert self.assertEqual(Price("1.00000"), order1.price) self.assertEqual(Price("1.00000"), order2.price) self.assertEqual(Price("1.00000"), order3.price) self.assertEqual(Price("1.00001"), order4.price) def test_initialize_buy_market_order(self): # Arrange # Act order = self.order_factory.market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), ) # Assert self.assertEqual(OrderType.MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state()) self.assertEqual(1, order.event_count()) self.assertTrue(isinstance(order.last_event(), OrderInitialized)) self.assertFalse(order.is_working()) self.assertFalse(order.is_completed()) self.assertTrue(order.is_buy()) self.assertFalse(order.is_sell()) self.assertEqual(None, order.filled_timestamp) self.assertEqual(UNIX_EPOCH, order.last_event().timestamp) def test_initialize_sell_market_order(self): # Arrange # Act order = self.order_factory.market( AUDUSD_FXCM, OrderSide.SELL, Quantity(100000),) # Assert self.assertEqual(OrderType.MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state()) self.assertEqual(1, order.event_count()) self.assertTrue(isinstance(order.last_event(), OrderInitialized)) self.assertFalse(order.is_working()) self.assertFalse(order.is_completed()) self.assertFalse(order.is_buy()) self.assertTrue(order.is_sell()) self.assertEqual(None, order.filled_timestamp) # def test_order_str_and_repr(self): # # Arrange # # Act # order = self.order_factory.market( # AUDUSD_FXCM, # OrderSide.BUY, # Quantity(100000), # ) # Assert TODO: String formatting # self.assertEqual("MarketOrder(cl_ord_id=O-19700101-000000-001-001-1, state=INITIALIZED, BUY 100K AUD/USD.FXCM MARKET DAY)", str(order)) # noqa # self.assertTrue(repr(order).startswith("<MarketOrder(cl_ord_id=O-19700101-000000-001-001-1, state=INITIALIZED, BUY 100K AUD/USD.FXCM MARKET DAY) object at")) # noqa def test_initialize_limit_order(self): # Arrange # Act order = self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) # Assert self.assertEqual(OrderType.LIMIT, order.type) self.assertEqual(OrderState.INITIALIZED, order.state()) self.assertEqual(TimeInForce.DAY, order.time_in_force) self.assertFalse(order.is_completed()) def test_initialize_limit_order_with_expire_time(self): # Arrange # Act order = self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000"), TimeInForce.GTD, UNIX_EPOCH, ) # Assert self.assertEqual(AUDUSD_FXCM, order.symbol) self.assertEqual(OrderType.LIMIT, order.type) self.assertEqual(Price("1.00000"), order.price) self.assertEqual(OrderState.INITIALIZED, order.state()) self.assertEqual(TimeInForce.GTD, order.time_in_force) self.assertEqual(UNIX_EPOCH, order.expire_time) self.assertFalse(order.is_completed()) def test_initialize_stop_order(self): # Arrange # Act order = self.order_factory.stop( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) # Assert self.assertEqual(OrderType.STOP_MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state()) self.assertEqual(TimeInForce.DAY, order.time_in_force) self.assertFalse(order.is_completed()) def test_initialize_bracket_order_market_with_no_take_profit(self): # Arrange entry_order = self.order_factory.market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) # Act bracket_order = self.order_factory.bracket(entry_order, Price("0.99990")) # Assert self.assertEqual(AUDUSD_FXCM, bracket_order.stop_loss.symbol) self.assertFalse(bracket_order.has_take_profit) self.assertEqual(ClientOrderId("O-19700101-000000-001-001-1"), bracket_order.entry.cl_ord_id) self.assertEqual(ClientOrderId("O-19700101-000000-001-001-2"), bracket_order.stop_loss.cl_ord_id) self.assertEqual(OrderSide.SELL, bracket_order.stop_loss.side) self.assertEqual(Quantity(100000), bracket_order.entry.quantity) self.assertEqual(Quantity(100000), bracket_order.stop_loss.quantity) self.assertEqual(Price("0.99990"), bracket_order.stop_loss.price) self.assertEqual(TimeInForce.GTC, bracket_order.stop_loss.time_in_force) self.assertEqual(None, bracket_order.stop_loss.expire_time) self.assertEqual(BracketOrderId("BO-19700101-000000-001-001-1"), bracket_order.id) self.assertEqual(UNIX_EPOCH, bracket_order.timestamp) def test_can_initialize_bracket_order_stop_with_take_profit(self): # Arrange entry_order = self.order_factory.stop( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("0.99995"), ) # Act bracket_order = self.order_factory.bracket( entry_order, Price("0.99990"), Price("1.00010"), ) # Assert self.assertEqual(AUDUSD_FXCM, bracket_order.stop_loss.symbol) self.assertTrue(bracket_order.has_take_profit) self.assertEqual(AUDUSD_FXCM, bracket_order.take_profit.symbol) self.assertEqual(ClientOrderId("O-19700101-000000-001-001-1"), bracket_order.entry.cl_ord_id) self.assertEqual(ClientOrderId("O-19700101-000000-001-001-2"), bracket_order.stop_loss.cl_ord_id) self.assertEqual(ClientOrderId("O-19700101-000000-001-001-3"), bracket_order.take_profit.cl_ord_id) self.assertEqual(OrderSide.SELL, bracket_order.stop_loss.side) self.assertEqual(OrderSide.SELL, bracket_order.take_profit.side) self.assertEqual(Quantity(100000), bracket_order.stop_loss.quantity) self.assertEqual(Quantity(100000), bracket_order.take_profit.quantity) self.assertEqual(Price("0.99990"), bracket_order.stop_loss.price) self.assertEqual(Price("1.00010"), bracket_order.take_profit.price) self.assertEqual(TimeInForce.GTC, bracket_order.stop_loss.time_in_force) self.assertEqual(TimeInForce.GTC, bracket_order.take_profit.time_in_force) self.assertEqual(None, bracket_order.entry.expire_time) self.assertEqual(None, bracket_order.stop_loss.expire_time) self.assertEqual(None, bracket_order.take_profit.expire_time) self.assertEqual(BracketOrderId("BO-19700101-000000-001-001-1"), bracket_order.id) self.assertEqual(UNIX_EPOCH, bracket_order.timestamp) # def test_bracket_order_str_and_repr(self): # # Arrange # # Act # entry_order = self.order_factory.market( # AUDUSD_FXCM, # OrderSide.BUY, # Quantity(100000), # ) # # bracket_order = self.order_factory.bracket( # entry_order, # Price("0.99990"), # Price("1.00010"), # ) # Assert # TODO: Fix string formatting # self.assertEqual("BracketOrder(id=BO-19700101-000000-001-001-1, EntryMarketOrder(cl_ord_id=O-19700101-000000-001-001-1, state=INITIALIZED, BUY 100K AUD/USD.FXCM MARKET DAY), SL=0.99990, TP=1.00010)", str(bracket_order)) # noqa # self.assertTrue(repr(bracket_order).startswith("<BracketOrder(id=BO-19700101-000000-001-001-1, EntryMarketOrder(cl_ord_id=O-19700101-000000-001-001-1, state=INITIALIZED, BUY 100K AUD/USD.FXCM MARKET DAY), SL=0.99990, TP=1.00010) object at")) # noqa # self.assertTrue(repr(bracket_order).endswith(">")) def test_can_apply_order_submitted_event_to_order(self): # Arrange order = self.order_factory.market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), ) submitted = TestStubs.event_order_submitted(order) # Act order.apply(submitted) # Assert self.assertEqual(OrderState.SUBMITTED, order.state()) self.assertEqual(2, order.event_count()) self.assertEqual(submitted, order.last_event()) self.assertFalse(order.is_completed()) def test_can_apply_order_accepted_event_to_order(self): # Arrange order = self.order_factory.market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) submitted = TestStubs.event_order_submitted(order) accepted = TestStubs.event_order_accepted(order) order.apply(submitted) # Act order.apply(accepted) # Assert self.assertEqual(OrderState.ACCEPTED, order.state()) self.assertFalse(order.is_completed()) def test_can_apply_order_rejected_event_to_order(self): # Arrange order = self.order_factory.market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) submitted = TestStubs.event_order_submitted(order) rejected = TestStubs.event_order_rejected(order) order.apply(submitted) # Act order.apply(rejected) # Assert self.assertEqual(OrderState.REJECTED, order.state()) self.assertTrue(order.is_completed()) def test_can_apply_order_working_event_to_stop_order(self): # Arrange order = self.order_factory.stop( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) submitted = TestStubs.event_order_submitted(order) accepted = TestStubs.event_order_accepted(order) working = TestStubs.event_order_working(order) order.apply(submitted) order.apply(accepted) # Act order.apply(working) # Assert # print(order) self.assertEqual(OrderState.WORKING, order.state()) self.assertEqual(OrderId("1"), order.id) self.assertFalse(order.is_completed()) self.assertTrue(order.is_working()) self.assertEqual(None, order.filled_timestamp) def test_can_apply_order_expired_event_to_stop_order(self): # Arrange order = self.order_factory.stop( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("0.99990"), TimeInForce.GTD, UNIX_EPOCH) submitted = TestStubs.event_order_submitted(order) accepted = TestStubs.event_order_accepted(order) working = TestStubs.event_order_working(order) expired = TestStubs.event_order_expired(order) order.apply(submitted) order.apply(accepted) order.apply(working) # Act order.apply(expired) # Assert self.assertEqual(OrderState.EXPIRED, order.state()) self.assertTrue(order.is_completed()) def test_can_apply_order_cancelled_event_to_order(self): # Arrange order = self.order_factory.market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) submitted = TestStubs.event_order_submitted(order) accepted = TestStubs.event_order_accepted(order) cancelled = TestStubs.event_order_cancelled(order) order.apply(submitted) order.apply(accepted) # Act order.apply(cancelled) # Assert self.assertEqual(OrderState.CANCELLED, order.state()) self.assertTrue(order.is_completed()) def test_can_apply_order_modified_event_to_stop_order(self): # Arrange order = self.order_factory.stop( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000")) submitted = TestStubs.event_order_submitted(order) accepted = TestStubs.event_order_accepted(order) working = TestStubs.event_order_working(order) modified = OrderModified( self.account_id, order.cl_ord_id, OrderId("1"), Quantity(120000), Price("1.00001"), UNIX_EPOCH, uuid4(), UNIX_EPOCH) order.apply(submitted) order.apply(accepted) order.apply(working) # Act order.apply(modified) # Assert self.assertEqual(OrderState.WORKING, order.state()) self.assertEqual(OrderId("1"), order.id) self.assertEqual(Quantity(120000), order.quantity) self.assertEqual(Price("1.00001"), order.price) self.assertTrue(order.is_working()) self.assertFalse(order.is_completed()) self.assertEqual(5, order.event_count()) def test_can_apply_order_filled_event_to_market_order(self): # Arrange order = self.order_factory.market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) submitted = TestStubs.event_order_submitted(order) accepted = TestStubs.event_order_accepted(order) filled = TestStubs.event_order_filled( order, PositionId("P-123456"), StrategyId("S", "001"), Price("1.00001")) order.apply(submitted) order.apply(accepted) # Act order.apply(filled) # Assert self.assertEqual(OrderState.FILLED, order.state()) self.assertEqual(Quantity(100000), order.filled_qty) self.assertEqual(Price("1.00001"), order.avg_price) self.assertTrue(order.is_completed()) self.assertEqual(UNIX_EPOCH, order.filled_timestamp) def test_can_apply_order_filled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000")) submitted = TestStubs.event_order_submitted(order) accepted = TestStubs.event_order_accepted(order) working = TestStubs.event_order_working(order) filled = OrderFilled( self.account_id, order.cl_ord_id, OrderId("1"), ExecutionId("E-1"), PositionId("P-1"), StrategyId("S", "NULL"), order.symbol, order.side, order.quantity, Quantity(), Price("1.00001"), Money(0, USD), LiquiditySide.MAKER, USD, USD, UNIX_EPOCH, uuid4(), UNIX_EPOCH, ) order.apply(submitted) order.apply(accepted) order.apply(working) # Act order.apply(filled) # Assert self.assertEqual(OrderState.FILLED, order.state()) self.assertEqual(Quantity(100000), order.filled_qty) self.assertEqual(Price("1.00000"), order.price) self.assertEqual(Price("1.00001"), order.avg_price) self.assertEqual(Decimal("0.00001"), order.slippage) self.assertTrue(order.is_completed()) self.assertEqual(UNIX_EPOCH, order.filled_timestamp) def test_can_apply_order_partially_filled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price("1.00000")) submitted = TestStubs.event_order_submitted(order) accepted = TestStubs.event_order_accepted(order) working = TestStubs.event_order_working(order) partially = OrderFilled( self.account_id, order.cl_ord_id, OrderId("1"), ExecutionId("E-1"), PositionId("P-1"), StrategyId("S", "NULL"), order.symbol, order.side, Quantity(50000), Quantity(50000), Price("0.999999"), Money(0, USD), LiquiditySide.MAKER, USD, USD, UNIX_EPOCH, uuid4(), UNIX_EPOCH) order.apply(submitted) order.apply(accepted) order.apply(working) # Act order.apply(partially) # Assert self.assertEqual(OrderState.PARTIALLY_FILLED, order.state()) self.assertEqual(Quantity(50000), order.filled_qty) self.assertEqual(Price("1.00000"), order.price) self.assertEqual(Price("0.999999"), order.avg_price) self.assertEqual(Decimal("-0.000001"), order.slippage) self.assertFalse(order.is_completed()) self.assertEqual(UNIX_EPOCH, order.filled_timestamp)
class BinanceOrderRequestBuilderTests(unittest.TestCase): def setUp(self): # Fixture Setup self.order_factory = OrderFactory( trader_id=TraderId("TESTER", "000"), strategy_id=StrategyId("S", "001"), clock=TestClock(), ) def test_order_with_gtd_tif_raises_value_error(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("1.0"), price=Price("50000"), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH + timedelta(minutes=1), post_only=True, ) self.assertRaises(ValueError, BinanceOrderRequestBuilder.build_py, order) def test_order_with_day_tif_raises_value_error(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("1.0"), price=Price("50000"), time_in_force=TimeInForce.DAY, post_only=True, ) self.assertRaises(ValueError, BinanceOrderRequestBuilder.build_py, order) def test_market_order(self): # Arrange order = self.order_factory.market( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("0.10000000"), ) # Act result = BinanceOrderRequestBuilder.build_py(order) # Assert expected = { 'newClientOrderId': 'O-19700101-000000-000-001-1', 'recvWindow': 10000, 'type': 'MARKET', } self.assertEqual(expected, result) def test_limit_buy_post_only_order(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("1.0"), price=Price("50000"), post_only=True, ) # Act result = BinanceOrderRequestBuilder.build_py(order) # Assert expected = { 'newClientOrderId': 'O-19700101-000000-000-001-1', 'recvWindow': 10000, 'type': 'LIMIT_MAKER', } self.assertEqual(expected, result) def test_limit_hidden_order_raises_value_error(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("1.0"), price=Price("50000"), time_in_force=TimeInForce.GTC, post_only=False, hidden=True, ) self.assertRaises(ValueError, BinanceOrderRequestBuilder.build_py, order) def test_limit_buy_ioc(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("1.0"), price=Price("50000"), time_in_force=TimeInForce.IOC, post_only=False, ) # Act result = BinanceOrderRequestBuilder.build_py(order) # Assert expected = { 'newClientOrderId': 'O-19700101-000000-000-001-1', 'recvWindow': 10000, 'timeInForce': 'IOC', 'type': 'LIMIT', } self.assertEqual(expected, result) def test_limit_sell_fok_order(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.SELL, quantity=Quantity("1.0"), price=Price("50000"), time_in_force=TimeInForce.FOK, post_only=False, ) # Act result = BinanceOrderRequestBuilder.build_py(order) # Assert expected = { 'newClientOrderId': 'O-19700101-000000-000-001-1', 'recvWindow': 10000, 'timeInForce': 'FOK', 'type': 'LIMIT', } self.assertEqual(expected, result) def test_stop_market_buy_order(self): # Arrange order = self.order_factory.stop_market( symbol=BTCUSDT, order_side=OrderSide.SELL, quantity=Quantity("1.0"), price=Price("100000"), time_in_force=TimeInForce.GTC, ) # Act result = BinanceOrderRequestBuilder.build_py(order) # Assert expected = { 'newClientOrderId': 'O-19700101-000000-000-001-1', 'recvWindow': 10000, 'stopPrice': '100000', 'type': 'TAKE_PROFIT', } self.assertEqual(expected, result)
class TestReportProvider: def setup(self): # Fixture Setup self.account_id = TestStubs.account_id() self.order_factory = OrderFactory( trader_id=TraderId("TESTER-000"), strategy_id=StrategyId("S-001"), clock=TestClock(), ) def test_generate_accounts_report_with_initial_account_state_returns_expected( self): # Arrange state = AccountState( account_id=AccountId("BITMEX", "1513111"), account_type=AccountType.MARGIN, base_currency=BTC, reported=True, balances=[ AccountBalance( currency=BTC, total=Money(10.00000000, BTC), free=Money(10.00000000, BTC), locked=Money(0.00000000, BTC), ) ], info={}, event_id=UUID4(), ts_event=0, ts_init=0, ) account = MarginAccount(state) # Act report = ReportProvider.generate_account_report(account) # Assert assert len(report) == 1 def test_generate_orders_report_with_no_order_returns_emtpy_dataframe( self): # Arrange, Act report = ReportProvider.generate_orders_report([]) # Assert assert report.empty def test_generate_orders_fills_report_with_no_order_returns_emtpy_dataframe( self): # Arrange, Act report = ReportProvider.generate_order_fills_report([]) # Assert assert report.empty def test_generate_positions_report_with_no_positions_returns_emtpy_dataframe( self): # Arrange, Act report = ReportProvider.generate_positions_report([]) # Assert assert report.empty def test_generate_orders_report(self): # Arrange order1 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(1500000), Price.from_str("0.80010"), ) order1.apply(TestStubs.event_order_submitted(order1)) order1.apply(TestStubs.event_order_accepted(order1)) order2 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(1500000), Price.from_str("0.80000"), ) order2.apply(TestStubs.event_order_submitted(order2)) order2.apply(TestStubs.event_order_accepted(order2)) event = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-1"), last_px=Price.from_str("0.80011"), ) order1.apply(event) orders = [order1, order2] # Act report = ReportProvider.generate_orders_report(orders) # Assert assert len(report) == 2 assert report.index.name == "client_order_id" assert report.index[0] == order1.client_order_id.value assert report.iloc[0]["instrument_id"] == "AUD/USD.SIM" assert report.iloc[0]["side"] == "BUY" assert report.iloc[0]["type"] == "LIMIT" assert report.iloc[0]["quantity"] == "1500000" assert report.iloc[0]["avg_px"] == "0.80011" assert report.iloc[0]["slippage"] == "0.00001" assert report.iloc[1]["avg_px"] is None def test_generate_order_fills_report(self): # Arrange order1 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(1500000), Price.from_str("0.80010"), ) order1.apply(TestStubs.event_order_submitted(order1)) order1.apply(TestStubs.event_order_accepted(order1)) order2 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(1500000), Price.from_str("0.80000"), ) order2.apply(TestStubs.event_order_submitted(order2)) order2.apply(TestStubs.event_order_accepted(order2)) filled = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-1"), strategy_id=StrategyId("S-1"), last_px=Price.from_str("0.80011"), ) order1.apply(filled) orders = [order1, order2] # Act report = ReportProvider.generate_order_fills_report(orders) # Assert assert len(report) == 1 assert report.index.name == "client_order_id" assert report.index[0] == order1.client_order_id.value assert report.iloc[0]["instrument_id"] == "AUD/USD.SIM" assert report.iloc[0]["side"] == "BUY" assert report.iloc[0]["type"] == "LIMIT" assert report.iloc[0]["quantity"] == "1500000" assert report.iloc[0]["avg_px"] == "0.80011" assert report.iloc[0]["slippage"] == "0.00001" def test_generate_positions_report(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 = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00010"), ) fill2 = TestStubs.event_order_filled( order2, instrument=AUDUSD_SIM, position_id=PositionId("P-123457"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00010"), ) position1 = Position(instrument=AUDUSD_SIM, fill=fill1) position1.apply(fill2) position2 = Position(instrument=AUDUSD_SIM, fill=fill1) position2.apply(fill2) positions = [position1, position2] # Act report = ReportProvider.generate_positions_report(positions) # Assert assert len(report) == 2 assert report.index.name == "position_id" assert report.index[0] == position1.id.value assert report.iloc[0]["instrument_id"] == "AUD/USD.SIM" assert report.iloc[0]["entry"] == "BUY" assert report.iloc[0]["side"] == "FLAT" assert report.iloc[0]["peak_qty"] == "100000" assert report.iloc[0]["avg_px_open"] == "1.00010" assert report.iloc[0]["avg_px_close"] == "1.00010" assert report.iloc[0]["ts_opened"] == UNIX_EPOCH assert report.iloc[0]["ts_closed"] == UNIX_EPOCH assert report.iloc[0]["realized_points"] == "0.00000" assert report.iloc[0]["realized_return"] == "0.00000"
class TestMsgPackCommandSerializer: def setup(self): # Fixture Setup self.venue = Venue("SIM") self.trader_id = TestStubs.trader_id() self.account_id = TestStubs.account_id() self.serializer = MsgPackCommandSerializer() self.order_factory = OrderFactory( trader_id=self.trader_id, strategy_id=StrategyId("S-001"), clock=TestClock(), ) 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, ) # 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_serialize_and_deserialize_submit_bracket_order_no_take_profit_commands( self, ): # Arrange entry_order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), ) bracket_order = self.order_factory.bracket( entry_order, stop_loss=Price(0.99900, precision=5), take_profit=Price(1.00100, precision=5), ) command = SubmitBracketOrder( self.trader_id, StrategyId("SCALPER-001"), bracket_order, uuid4(), 0, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command assert deserialized.bracket_order == bracket_order print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_submit_bracket_order_with_take_profit_commands( self, ): # Arrange entry_order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), Price(1.00000, precision=5), ) bracket_order = self.order_factory.bracket( entry_order, stop_loss=Price(0.99900, precision=5), take_profit=Price(1.00010, precision=5), ) command = SubmitBracketOrder( self.trader_id, StrategyId("SCALPER-001"), bracket_order, uuid4(), 0, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command assert deserialized.bracket_order == bracket_order print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_amend_order_commands(self): # Arrange command = UpdateOrder( self.trader_id, StrategyId("SCALPER-001"), AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("001"), Quantity(100000, precision=0), Price(1.00001, precision=5), None, uuid4(), 0, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_cancel_order_commands(self): # Arrange command = CancelOrder( self.trader_id, StrategyId("SCALPER-001"), AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("001"), uuid4(), 0, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command print(b64encode(serialized)) print(command)
class ExecutionClientTests(unittest.TestCase): def setUp(self): # Fixture Setup self.clock = TestClock() self.uuid_factory = UUIDFactory() self.logger = TestLogger(self.clock) self.trader_id = TraderId("TESTER", "000") self.account_id = TestStubs.account_id() portfolio = Portfolio( clock=self.clock, logger=self.logger, ) portfolio.register_cache(DataCache(self.logger)) database = BypassExecutionDatabase(trader_id=self.trader_id, logger=self.logger) self.exec_engine = ExecutionEngine( database=database, portfolio=portfolio, clock=self.clock, logger=self.logger, ) self.venue = Venue("SIM") self.client = ExecutionClient( venue=self.venue, account_id=self.account_id, engine=self.exec_engine, clock=self.clock, logger=self.logger, ) self.order_factory = OrderFactory( trader_id=TraderId("TESTER", "000"), strategy_id=StrategyId("S", "001"), clock=TestClock(), ) def test_connect_when_not_implemented_raises_exception(self): self.assertRaises(NotImplementedError, self.client.connect) def test_disconnect_when_not_implemented_raises_exception(self): self.assertRaises(NotImplementedError, self.client.disconnect) def test_reset_when_not_implemented_raises_exception(self): self.assertRaises(NotImplementedError, self.client.reset) def test_dispose_when_not_implemented_raises_exception(self): self.assertRaises(NotImplementedError, self.client.dispose) 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_submit_bracket_order_raises_not_implemented_error(self): entry_order = self.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("0.99995"), ) # Act bracket_order = self.order_factory.bracket( entry_order, Price("0.99990"), Price("1.00010"), ) command = SubmitBracketOrder( self.venue, self.trader_id, self.account_id, StrategyId("SCALPER", "001"), bracket_order, self.uuid_factory.generate(), self.clock.utc_now(), ) self.assertRaises(NotImplementedError, self.client.submit_bracket_order, command) def test_amend_order_raises_not_implemented_error(self): # Arrange # Act command = AmendOrder( self.venue, self.trader_id, self.account_id, ClientOrderId("O-123456789"), Quantity(120000), Price("1.00000"), self.uuid_factory.generate(), self.clock.utc_now(), ) # Assert self.assertRaises(NotImplementedError, self.client.amend_order, command) def test_cancel_order_raises_not_implemented_error(self): # Arrange # Act command = CancelOrder( self.venue, self.trader_id, self.account_id, ClientOrderId("O-123456789"), OrderId("001"), self.uuid_factory.generate(), self.clock.utc_now(), ) # Assert self.assertRaises(NotImplementedError, self.client.cancel_order, command) def test_handle_event_sends_to_execution_engine(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) fill = TestStubs.event_order_filled( order, AUDUSD_SIM, PositionId("P-123456"), StrategyId("S", "001"), Price("1.00001"), ) # Act self.client._handle_event_py(fill) # Accessing protected method # Assert self.assertEqual(1, self.exec_engine.event_count)
class MsgPackCommandSerializerTests(unittest.TestCase): def setUp(self): # Fixture Setup self.venue = Venue("SIM") self.trader_id = TestStubs.trader_id() self.account_id = TestStubs.account_id() self.serializer = MsgPackCommandSerializer() self.order_factory = OrderFactory( trader_id=self.trader_id, strategy_id=StrategyId("S", "001"), clock=TestClock(), ) def test_serialize_and_deserialize_submit_order_commands(self): # Arrange order = self.order_factory.market(AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000)) command = SubmitOrder( self.venue, self.trader_id, self.account_id, StrategyId("SCALPER", "01"), PositionId("P-123456"), order, uuid4(), UNIX_EPOCH, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(command, deserialized) self.assertEqual(order, deserialized.order) print(command) print(len(serialized)) print(serialized) print(b64encode(serialized)) def test_serialize_and_deserialize_submit_bracket_order_no_take_profit_commands( self): # Arrange entry_order = self.order_factory.market(AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000)) bracket_order = self.order_factory.bracket( entry_order, stop_loss=Price("0.99900"), ) command = SubmitBracketOrder( self.venue, self.trader_id, self.account_id, StrategyId("SCALPER", "01"), bracket_order, uuid4(), UNIX_EPOCH, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(command, deserialized) self.assertEqual(bracket_order, deserialized.bracket_order) print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_submit_bracket_order_with_take_profit_commands( self): # Arrange entry_order = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) bracket_order = self.order_factory.bracket( entry_order, stop_loss=Price("0.99900"), take_profit=Price("1.00010"), ) command = SubmitBracketOrder( self.venue, self.trader_id, self.account_id, StrategyId("SCALPER", "01"), bracket_order, uuid4(), UNIX_EPOCH, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(command, deserialized) self.assertEqual(bracket_order, deserialized.bracket_order) print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_modify_order_commands(self): # Arrange command = ModifyOrder( self.venue, self.trader_id, self.account_id, ClientOrderId("O-123456"), Quantity(100000), Price("1.00001"), uuid4(), UNIX_EPOCH, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(command, deserialized) print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_cancel_order_commands(self): # Arrange command = CancelOrder( self.venue, self.trader_id, self.account_id, ClientOrderId("O-123456"), uuid4(), UNIX_EPOCH, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(command, deserialized) print(b64encode(serialized)) print(command)
class TestMsgPackSerializer: def setup(self): # Fixture Setup self.trader_id = TestStubs.trader_id() self.strategy_id = TestStubs.strategy_id() self.account_id = TestStubs.account_id() self.venue = Venue("SIM") self.unpacker = OrderUnpacker() self.order_factory = OrderFactory( trader_id=self.trader_id, strategy_id=self.strategy_id, clock=TestClock(), ) self.serializer = MsgPackSerializer() def test_serialize_unknown_object_raises_runtime_error(self): # Arrange, Act with pytest.raises(RuntimeError): self.serializer.serialize({"type": "UNKNOWN"}) def test_deserialize_unknown_object_raises_runtime_error(self): # Arrange, Act with pytest.raises(RuntimeError): self.serializer.deserialize(msgpack.packb({"type": "UNKNOWN"})) def test_serialize_and_deserialize_fx_instrument(self): # Arrange, Act serialized = self.serializer.serialize(AUDUSD_SIM) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == AUDUSD_SIM print(b64encode(serialized)) print(deserialized) def test_serialize_and_deserialize_crypto_swap_instrument(self): # Arrange, Act serialized = self.serializer.serialize(ETHUSDT_BINANCE) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == ETHUSDT_BINANCE print(b64encode(serialized)) print(deserialized) def test_serialize_and_deserialize_crypto_instrument(self): # Arrange, Act serialized = self.serializer.serialize(ETHUSDT_BINANCE) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == ETHUSDT_BINANCE print(b64encode(serialized)) print(deserialized) def test_pack_and_unpack_market_orders(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_limit_orders(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), Price(1.00000, precision=5), TimeInForce.DAY, display_qty=Quantity(50000, precision=0), ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_limit_orders_with_expire_time(self): # Arrange order = LimitOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_stop_market_orders_with_expire_time(self): # Arrange order = StopMarketOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_stop_limit_orders(self): # Arrange order = StopLimitOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), trigger=Price(1.00010, precision=5), time_in_force=TimeInForce.GTC, expire_time=None, init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_stop_limit_orders_with_expire_time(self): # Arrange order = StopLimitOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), trigger=Price(1.00010, precision=5), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order 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, ) # 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_serialize_and_deserialize_submit_order_list_commands(self, ): # Arrange bracket = self.order_factory.bracket_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), stop_loss=Price(0.99900, precision=5), take_profit=Price(1.00010, precision=5), ) command = SubmitOrderList( trader_id=self.trader_id, strategy_id=StrategyId("SCALPER-001"), order_list=bracket, command_id=UUID4(), ts_init=0, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command assert deserialized.list == bracket print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_amend_order_commands(self): # Arrange command = ModifyOrder( self.trader_id, StrategyId("SCALPER-001"), AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("001"), Quantity(100000, precision=0), Price(1.00001, precision=5), None, UUID4(), 0, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_cancel_order_commands(self): # Arrange command = CancelOrder( self.trader_id, StrategyId("SCALPER-001"), AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("001"), UUID4(), 0, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_component_state_changed_events(self): # Arrange event = ComponentStateChanged( trader_id=TestStubs.trader_id(), component_id=ComponentId("MyActor-001"), component_type="MyActor", state=ComponentState.RUNNING, config={"do_something": True}, event_id=UUID4(), ts_event=0, ts_init=0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_account_state_with_base_currency_events( self): # Arrange event = AccountState( account_id=AccountId("SIM", "000"), account_type=AccountType.MARGIN, base_currency=USD, reported=True, balances=[ AccountBalance(USD, Money(1525000, USD), Money(0, USD), Money(1525000, USD)) ], info={}, event_id=UUID4(), ts_event=0, ts_init=1_000_000_000, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_account_state_without_base_currency_events( self): # Arrange event = AccountState( account_id=AccountId("SIM", "000"), account_type=AccountType.MARGIN, base_currency=None, reported=True, balances=[ AccountBalance( USDT, Money(10000, USDT), Money(0, USDT), Money(10000, USDT), ) ], info={}, event_id=UUID4(), ts_event=0, ts_init=1_000_000_000, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_market_order_initialized_events(self): # Arrange event = OrderInitialized( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.SELL, OrderType.MARKET, Quantity(100000, precision=0), TimeInForce.FOK, reduce_only=True, options={}, order_list_id=OrderListId("1"), parent_order_id=ClientOrderId("O-123455"), child_order_ids=[ ClientOrderId("O-123457"), ClientOrderId("O-123458") ], contingency=ContingencyType.OTO, contingency_ids=[ ClientOrderId("O-123457"), ClientOrderId("O-123458") ], tags="ENTRY", event_id=UUID4(), ts_init=0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_limit_order_initialized_events(self): # Arrange options = { "ExpireTime": None, "Price": "1.0010", "PostOnly": True, "Hidden": False, } event = OrderInitialized( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.SELL, OrderType.LIMIT, Quantity(100000, precision=0), TimeInForce.DAY, reduce_only=False, options=options, order_list_id=OrderListId("1"), parent_order_id=ClientOrderId("O-123455"), child_order_ids=[ ClientOrderId("O-123457"), ClientOrderId("O-123458") ], contingency=ContingencyType.OTO, contingency_ids=[ ClientOrderId("O-123457"), ClientOrderId("O-123458") ], tags=None, event_id=UUID4(), ts_init=0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event assert deserialized.options == options def test_serialize_and_deserialize_stop_market_order_initialized_events( self): # Arrange options = { "ExpireTime": None, "Price": "1.0005", } event = OrderInitialized( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.SELL, OrderType.STOP_MARKET, Quantity(100000, precision=0), TimeInForce.DAY, reduce_only=True, options=options, order_list_id=OrderListId("1"), parent_order_id=ClientOrderId("O-123455"), child_order_ids=[ ClientOrderId("O-123457"), ClientOrderId("O-123458") ], contingency=ContingencyType.OTO, contingency_ids=[ ClientOrderId("O-123457"), ClientOrderId("O-123458") ], tags=None, event_id=UUID4(), ts_init=0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event assert deserialized.options == options def test_serialize_and_deserialize_stop_limit_order_initialized_events( self): # Arrange options = { "ExpireTime": None, "Price": "1.0005", "Trigger": "1.0010", "PostOnly": True, "Hidden": False, } event = OrderInitialized( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.SELL, OrderType.STOP_LIMIT, Quantity(100000, precision=0), TimeInForce.DAY, reduce_only=True, options=options, order_list_id=OrderListId("1"), parent_order_id=ClientOrderId("O-123455"), child_order_ids=[ ClientOrderId("O-123457"), ClientOrderId("O-123458") ], contingency=ContingencyType.OTO, contingency_ids=[ ClientOrderId("O-123457"), ClientOrderId("O-123458") ], tags="entry,bulk", event_id=UUID4(), ts_init=0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event assert deserialized.options == options assert deserialized.tags == "entry,bulk" def test_serialize_and_deserialize_order_denied_events(self): # Arrange event = OrderDenied( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), "Exceeds MAX_NOTIONAL_PER_ORDER", UUID4(), 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_submitted_events(self): # Arrange event = OrderSubmitted( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_accepted_events(self): # Arrange event = OrderAccepted( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("B-123456"), UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_rejected_events(self): # Arrange event = OrderRejected( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), "ORDER_ID_INVALID", UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_pending_cancel_events(self): # Arrange event = OrderPendingCancel( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("1"), UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_pending_replace_events(self): # Arrange event = OrderPendingUpdate( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("1"), UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_canceled_events(self): # Arrange event = OrderCanceled( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("1"), UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_update_reject_events(self): # Arrange event = OrderModifyRejected( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("1"), "ORDER_DOES_NOT_EXIST", UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_cancel_reject_events(self): # Arrange event = OrderCancelRejected( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("1"), "ORDER_DOES_NOT_EXIST", UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_amended_events(self): # Arrange event = OrderUpdated( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("1"), Quantity(100000, precision=0), Price(0.80010, precision=5), Price(0.80050, precision=5), UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_expired_events(self): # Arrange event = OrderExpired( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("1"), UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_triggered_events(self): # Arrange event = OrderTriggered( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("1"), UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_partially_filled_events(self): # Arrange event = OrderFilled( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("1"), ExecutionId("E123456"), PositionId("T123456"), OrderSide.SELL, OrderType.MARKET, Quantity(50000, precision=0), Price(1.00000, precision=5), AUDUSD_SIM.quote_currency, Money(0, USD), LiquiditySide.MAKER, UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_order_filled_events(self): # Arrange event = OrderFilled( self.trader_id, self.strategy_id, self.account_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("1"), ExecutionId("E123456"), PositionId("T123456"), OrderSide.SELL, OrderType.MARKET, Quantity(100000, precision=0), Price(1.00000, precision=5), AUDUSD_SIM.quote_currency, Money(0, USD), LiquiditySide.TAKER, UUID4(), 0, 0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_position_opened_events(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) fill = 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"), ) position = Position(instrument=AUDUSD_SIM, fill=fill) uuid = UUID4() event = PositionOpened.create(position, fill, uuid, 0) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_position_changed_events(self): # Arrange order1 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) fill1 = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), ) order2 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(50000), ) 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.00011"), ) position = Position(instrument=AUDUSD_SIM, fill=fill1) position.apply(fill2) uuid = UUID4() event = PositionChanged.create(position, fill2, uuid, 0) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_position_closed_events(self): # Arrange order1 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) fill1 = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), ) order2 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(100000), ) 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.00011"), ) position = Position(instrument=AUDUSD_SIM, fill=fill1) position.apply(fill2) uuid = UUID4() event = PositionClosed.create(position, fill2, uuid, 0) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event
class ReportProviderTests(unittest.TestCase): def setUp(self): # Fixture Setup self.account_id = TestStubs.account_id() self.order_factory = OrderFactory( trader_id=TraderId("TESTER-000"), strategy_id=StrategyId("S-001"), clock=TestClock(), ) def test_generate_accounts_report_with_initial_account_state_returns_expected(self): # Arrange state = AccountState( account_id=AccountId("BITMEX", "1513111"), account_type=AccountType.MARGIN, base_currency=BTC, reported=True, balances=[ AccountBalance( currency=BTC, total=Money(10.00000000, BTC), free=Money(10.00000000, BTC), locked=Money(0.00000000, BTC), ) ], info={}, event_id=uuid4(), ts_updated_ns=0, timestamp_ns=0, ) account = Account(state) report_provider = ReportProvider() # Act report = report_provider.generate_account_report(account) # Assert self.assertEqual(1, len(report)) def test_generate_orders_report_with_no_order_returns_emtpy_dataframe(self): # Arrange report_provider = ReportProvider() # Act report = report_provider.generate_orders_report([]) # Assert self.assertTrue(report.empty) def test_generate_orders_fills_report_with_no_order_returns_emtpy_dataframe(self): # Arrange report_provider = ReportProvider() # Act report = report_provider.generate_order_fills_report([]) # Assert self.assertTrue(report.empty) def test_generate_positions_report_with_no_positions_returns_emtpy_dataframe(self): # Arrange report_provider = ReportProvider() # Act report = report_provider.generate_positions_report([]) # Assert self.assertTrue(report.empty) def test_generate_orders_report(self): # Arrange report_provider = ReportProvider() order1 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(1500000), Price.from_str("0.80010"), ) order1.apply(TestStubs.event_order_submitted(order1)) order1.apply(TestStubs.event_order_accepted(order1)) order2 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(1500000), Price.from_str("0.80000"), ) order2.apply(TestStubs.event_order_submitted(order2)) order2.apply(TestStubs.event_order_accepted(order2)) event = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-1"), last_px=Price.from_str("0.80011"), ) order1.apply(event) orders = [order1, order2] # Act report = report_provider.generate_orders_report(orders) # Assert self.assertEqual(2, len(report)) self.assertEqual("client_order_id", report.index.name) self.assertEqual(order1.client_order_id.value, report.index[0]) self.assertEqual("AUD/USD.SIM", report.iloc[0]["instrument_id"]) self.assertEqual("BUY", report.iloc[0]["side"]) self.assertEqual("LIMIT", report.iloc[0]["type"]) self.assertEqual(1500000, report.iloc[0]["qty"]) self.assertEqual(0.80011, report.iloc[0]["avg_px"]) self.assertEqual(0.00001, report.iloc[0]["slippage"]) self.assertEqual("None", report.iloc[1]["avg_px"]) def test_generate_order_fills_report(self): # Arrange report_provider = ReportProvider() order1 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(1500000), Price.from_str("0.80010"), ) order1.apply(TestStubs.event_order_submitted(order1)) order1.apply(TestStubs.event_order_accepted(order1)) order2 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(1500000), Price.from_str("0.80000"), ) order2.apply(TestStubs.event_order_submitted(order2)) order2.apply(TestStubs.event_order_accepted(order2)) filled = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-1"), strategy_id=StrategyId("S-1"), last_px=Price.from_str("0.80011"), ) order1.apply(filled) orders = [order1, order2] # Act report = report_provider.generate_order_fills_report(orders) # Assert self.assertEqual(1, len(report)) self.assertEqual("client_order_id", report.index.name) self.assertEqual(order1.client_order_id.value, report.index[0]) self.assertEqual("AUD/USD.SIM", report.iloc[0]["instrument_id"]) self.assertEqual("BUY", report.iloc[0]["side"]) self.assertEqual("LIMIT", report.iloc[0]["type"]) self.assertEqual(1500000, report.iloc[0]["qty"]) self.assertEqual(0.80011, report.iloc[0]["avg_px"]) self.assertEqual(0.00001, report.iloc[0]["slippage"]) def test_generate_positions_report(self): # Arrange report_provider = ReportProvider() 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 = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00010"), ) fill2 = TestStubs.event_order_filled( order2, instrument=AUDUSD_SIM, position_id=PositionId("P-123457"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00010"), ) position1 = Position(instrument=AUDUSD_SIM, fill=fill1) position1.apply(fill2) position2 = Position(instrument=AUDUSD_SIM, fill=fill1) position2.apply(fill2) positions = [position1, position2] # Act report = report_provider.generate_positions_report(positions) # Assert self.assertEqual(2, len(report)) self.assertEqual("position_id", report.index.name) self.assertEqual(position1.id.value, report.index[0]) self.assertEqual("AUD/USD.SIM", report.iloc[0]["instrument_id"]) self.assertEqual("BUY", report.iloc[0]["entry"]) self.assertEqual(100000, report.iloc[0]["peak_qty"]) self.assertEqual(1.0001, report.iloc[0]["avg_px_open"]) self.assertEqual(1.0001, report.iloc[0]["avg_px_close"]) self.assertEqual(UNIX_EPOCH, report.iloc[0]["opened_time"]) self.assertEqual(UNIX_EPOCH, report.iloc[0]["closed_time"]) self.assertEqual(0, report.iloc[0]["realized_points"]) self.assertEqual(0, report.iloc[0]["realized_return"])
class ReportProviderTests(unittest.TestCase): def setUp(self): # Fixture Setup self.account_id = TestStubs.account_id() self.order_factory = OrderFactory( strategy_id=StrategyId("S", "001"), id_tag_trader=IdTag("001"), id_tag_strategy=IdTag("001"), clock=TestClock()) def test_generate_orders_report(self): # Arrange report_provider = ReportProvider() order1 = self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(1500000), Price("0.80010")) order1.apply(TestStubs.event_order_submitted(order1)) order1.apply(TestStubs.event_order_accepted(order1)) order1.apply(TestStubs.event_order_working(order1)) order2 = self.order_factory.limit( AUDUSD_FXCM, OrderSide.SELL, Quantity(1500000), Price("0.80000")) order2.apply(TestStubs.event_order_submitted(order2)) order2.apply(TestStubs.event_order_accepted(order2)) order2.apply(TestStubs.event_order_working(order2)) event = TestStubs.event_order_filled( order1, position_id=PositionId("P-1"), fill_price=Price("0.80011"), ) order1.apply(event) orders = [order1, order2] # Act report = report_provider.generate_orders_report(orders) # Assert self.assertEqual(2, len(report)) self.assertEqual("cl_ord_id", report.index.name) self.assertEqual(order1.cl_ord_id.value, report.index[0]) self.assertEqual("AUD/USD", report.iloc[0]["symbol"]) self.assertEqual("BUY", report.iloc[0]["side"]) self.assertEqual("LIMIT", report.iloc[0]["type"]) self.assertEqual(1500000, report.iloc[0]["quantity"]) self.assertEqual(Decimal("0.80011"), report.iloc[0]["avg_price"]) self.assertEqual(0.00001, report.iloc[0]["slippage"]) self.assertEqual("None", report.iloc[1]["avg_price"]) def test_generate_order_fills_report(self): # Arrange report_provider = ReportProvider() order1 = self.order_factory.limit( AUDUSD_FXCM, OrderSide.BUY, Quantity(1500000), Price("0.80010"), ) order1.apply(TestStubs.event_order_submitted(order1)) order1.apply(TestStubs.event_order_accepted(order1)) order1.apply(TestStubs.event_order_working(order1)) order2 = self.order_factory.limit( AUDUSD_FXCM, OrderSide.SELL, Quantity(1500000), Price("0.80000"), ) submitted2 = TestStubs.event_order_submitted(order2) accepted2 = TestStubs.event_order_accepted(order2) working2 = TestStubs.event_order_working(order2) order2.apply(submitted2) order2.apply(accepted2) order2.apply(working2) filled = TestStubs.event_order_filled(order1, PositionId("P-1"), StrategyId("S", "1"), Price("0.80011")) order1.apply(filled) orders = [order1, order2] # Act report = report_provider.generate_order_fills_report(orders) # Assert self.assertEqual(1, len(report)) self.assertEqual("cl_ord_id", report.index.name) self.assertEqual(order1.cl_ord_id.value, report.index[0]) self.assertEqual("AUD/USD", report.iloc[0]["symbol"]) self.assertEqual("BUY", report.iloc[0]["side"]) self.assertEqual("LIMIT", report.iloc[0]["type"]) self.assertEqual(1500000, report.iloc[0]["quantity"]) self.assertEqual(Decimal("0.80011"), report.iloc[0]["avg_price"]) self.assertEqual(0.00001, report.iloc[0]["slippage"]) def test_generate_trades_report(self): # Arrange report_provider = ReportProvider() position1 = TestStubs.position_which_is_closed(PositionId("P-1")) position2 = TestStubs.position_which_is_closed(PositionId("P-2")) positions = [position1, position2] # Act report = report_provider.generate_positions_report(positions) # Assert self.assertEqual(2, len(report)) self.assertEqual("position_id", report.index.name) self.assertEqual(position1.id.value, report.index[0]) self.assertEqual("AUD/USD", report.iloc[0]["symbol"]) self.assertEqual("SELL", report.iloc[0]["entry"]) self.assertEqual(100000, report.iloc[0]["peak_quantity"]) self.assertEqual(1.0001, report.iloc[0]["avg_open_price"]) self.assertEqual(1.0001, report.iloc[0]["avg_close_price"]) self.assertEqual(UNIX_EPOCH + timedelta(minutes=5), report.iloc[0]["opened_time"]) self.assertEqual(UNIX_EPOCH + timedelta(minutes=5), report.iloc[0]["closed_time"]) self.assertEqual(0.0, report.iloc[0]["realized_points"]) self.assertEqual(0.0, report.iloc[0]["realized_return"])
class BitmexOrderBuilderTests(unittest.TestCase): def setUp(self): # Fixture Setup self.order_factory = OrderFactory( trader_id=TraderId("TESTER", "000"), strategy_id=StrategyId("S", "001"), clock=TestClock(), ) self.builder = BitmexOrderBuilder() def test_order_with_gtd_tif_raises_value_error(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("1.0"), price=Price("50000"), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH + timedelta(minutes=1), post_only=True, ) self.assertRaises(ValueError, self.builder.build_py, order) def test_market_order(self): # Arrange order = self.order_factory.market( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("0.10000000"), ) # Act result = self.builder.build_py(order) # Assert expected_args = ['BTC/USDT', 'Market', 'Buy', '0.10000000'] expected_custom_params = { 'clOrdID': 'O-19700101-000000-000-001-1', 'timeInForce': 'GoodTillCancel' } self.assertEqual((expected_args, expected_custom_params), result) def test_limit_buy_post_only_reduce_only_order(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("1.0"), price=Price("50000"), post_only=True, reduce_only=True, ) # Act result = self.builder.build_py(order) # Assert expected_args = ['BTC/USDT', 'Limit', 'Buy', '1.0', '50000'] expected_custom_params = { 'clOrdID': 'O-19700101-000000-000-001-1', 'execInst': 'ParticipateDoNotInitiate,ReduceOnly', 'timeInForce': 'GoodTillCancel' } self.assertTrue(order.is_post_only) self.assertEqual((expected_args, expected_custom_params), result) def test_limit_sell_hidden_reduce_only_order(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("1.0"), price=Price("50000"), post_only=False, reduce_only=True, hidden=True, ) # Act result = self.builder.build_py(order) # Assert expected_args = ['BTC/USDT', 'Limit', 'Buy', '1.0', '50000'] expected_custom_params = { 'clOrdID': 'O-19700101-000000-000-001-1', 'displayQty': 0, 'execInst': 'ReduceOnly', 'timeInForce': 'GoodTillCancel' } self.assertEqual((expected_args, expected_custom_params), result) def test_limit_sell_hidden(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("1.0"), price=Price("50000"), time_in_force=TimeInForce.IOC, post_only=False, hidden=True, ) # Act result = self.builder.build_py(order) # Assert expected_args = ['BTC/USDT', 'Limit', 'Buy', '1.0', '50000'] expected_custom_params = { 'clOrdID': 'O-19700101-000000-000-001-1', 'displayQty': 0, 'timeInForce': 'ImmediateOrCancel' } self.assertFalse(order.is_post_only) self.assertEqual((expected_args, expected_custom_params), result) def test_limit_buy_ioc(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.BUY, quantity=Quantity("1.0"), price=Price("50000"), time_in_force=TimeInForce.IOC, post_only=False, ) # Act result = self.builder.build_py(order) # Assert expected_args = ['BTC/USDT', 'Limit', 'Buy', '1.0', '50000'] expected_custom_params = { 'clOrdID': 'O-19700101-000000-000-001-1', 'timeInForce': 'ImmediateOrCancel' } self.assertFalse(order.is_post_only) self.assertEqual((expected_args, expected_custom_params), result) def test_limit_sell_fok_order(self): # Arrange order = self.order_factory.limit( symbol=BTCUSDT, order_side=OrderSide.SELL, quantity=Quantity("1.0"), price=Price("50000"), time_in_force=TimeInForce.FOK, post_only=False, ) # Act result = self.builder.build_py(order) # Assert expected_args = ['BTC/USDT', 'Limit', 'Sell', '1.0', '50000'] expected_custom_params = { 'clOrdID': 'O-19700101-000000-000-001-1', 'timeInForce': 'FillOrKill' } self.assertFalse(order.is_post_only) self.assertEqual((expected_args, expected_custom_params), result) def test_stop_market_buy_order(self): # Arrange order = self.order_factory.stop_market( symbol=BTCUSDT, order_side=OrderSide.SELL, quantity=Quantity("1.0"), price=Price("100000"), time_in_force=TimeInForce.GTC, ) # Act result = self.builder.build_py(order) # Assert expected_args = ['BTC/USDT', 'StopMarket', 'Sell', '1.0'] expected_custom_params = { 'clOrdID': 'O-19700101-000000-000-001-1', 'stopPx': '100000', 'timeInForce': 'GoodTillCancel' } self.assertEqual((expected_args, expected_custom_params), result) def test_stop_market_sell_reduce_only_order(self): # Arrange order = self.order_factory.stop_market( symbol=BTCUSDT, order_side=OrderSide.SELL, quantity=Quantity("1.0"), price=Price("100000"), time_in_force=TimeInForce.GTC, ) # Act result = self.builder.build_py(order) # Assert expected_args = ['BTC/USDT', 'StopMarket', 'Sell', '1.0'] expected_custom_params = { 'clOrdID': 'O-19700101-000000-000-001-1', 'stopPx': '100000', 'timeInForce': 'GoodTillCancel' } self.assertEqual((expected_args, expected_custom_params), result)
class ReportProviderTests(unittest.TestCase): def setUp(self): # Fixture Setup self.account_id = TestStubs.account_id() self.order_factory = OrderFactory(id_tag_trader=IdTag('001'), id_tag_strategy=IdTag('001'), clock=TestClock()) def test_generate_orders_report(self): # Arrange report_provider = ReportProvider() order1 = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(1500000), Price(0.80010, 5)) order2 = self.order_factory.limit(AUDUSD_FXCM, OrderSide.SELL, Quantity(1500000), Price(0.80000, 5)) event = OrderFilled(self.account_id, order1.id, ExecutionId('SOME_EXEC_ID_1'), PositionIdBroker('SOME_EXEC_TICKET_1'), order1.symbol, order1.side, order1.quantity, Price(0.80011, 5), Currency.AUD, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) order1.apply(event) orders = {order1.id: order1, order2.id: order2} # Act report = report_provider.generate_orders_report(orders) # Assert self.assertEqual(2, len(report)) self.assertEqual('order_id', report.index.name) self.assertEqual(order1.id.value, report.index[0]) self.assertEqual('AUDUSD', report.iloc[0]['symbol']) self.assertEqual('BUY', report.iloc[0]['side']) self.assertEqual('LIMIT', report.iloc[0]['type']) self.assertEqual(1500000, report.iloc[0]['quantity']) self.assertEqual(0.80011, report.iloc[0]['avg_price']) self.assertEqual(0.00001, report.iloc[0]['slippage']) self.assertEqual('None', report.iloc[1]['avg_price']) def test_generate_order_fills_report(self): # Arrange report_provider = ReportProvider() order1 = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(1500000), Price(0.80010, 5)) order2 = self.order_factory.limit(AUDUSD_FXCM, OrderSide.SELL, Quantity(1500000), Price(0.80000, 5)) event = OrderFilled(self.account_id, order1.id, ExecutionId('SOME_EXEC_ID_1'), PositionIdBroker('SOME_EXEC_TICKET_1'), order1.symbol, order1.side, order1.quantity, Price(0.80011, 5), Currency.AUD, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) order1.apply(event) orders = {order1.id: order1, order2.id: order2} # Act report = report_provider.generate_order_fills_report(orders) # Assert # print(report.iloc[0]) self.assertEqual(1, len(report)) self.assertEqual('order_id', report.index.name) self.assertEqual(order1.id.value, report.index[0]) self.assertEqual('AUDUSD', report.iloc[0]['symbol']) self.assertEqual('BUY', report.iloc[0]['side']) self.assertEqual('LIMIT', report.iloc[0]['type']) self.assertEqual(1500000, report.iloc[0]['quantity']) self.assertAlmostEqual(0.80011, report.iloc[0]['avg_price']) self.assertEqual(0.00001, report.iloc[0]['slippage']) def test_generate_trades_report(self): # Arrange report_provider = ReportProvider() position1 = TestStubs.position_which_is_closed(number=1) position2 = TestStubs.position_which_is_closed(number=2) positions = {position1.id: position1, position2.id: position2} # Act report = report_provider.generate_positions_report(positions) # Assert # print(report.iloc[0]) self.assertEqual(2, len(report)) self.assertEqual('position_id', report.index.name) self.assertEqual(position1.id.value, report.index[0]) self.assertEqual('AUDUSD', report.iloc[0]['symbol']) self.assertEqual('BUY', report.iloc[0]['direction']) self.assertEqual(100000, report.iloc[0]['peak_quantity']) self.assertEqual(1.00000, report.iloc[0]['avg_open_price']) self.assertEqual(1.0001, report.iloc[0]['avg_close_price']) self.assertEqual(UNIX_EPOCH, report.iloc[0]['opened_time']) self.assertEqual(UNIX_EPOCH + timedelta(minutes=5), report.iloc[0]['closed_time']) self.assertEqual(9.999999999998899e-05, report.iloc[0]['realized_points']) self.assertEqual(9.999999999998899e-05, report.iloc[0]['realized_return'])
class TestMsgPackOrderSerializer: def setup(self): # Fixture Setup self.serializer = MsgPackOrderSerializer() self.order_factory = OrderFactory( trader_id=TraderId("TESTER-000"), strategy_id=StrategyId("S-001"), clock=TestClock(), ) def test_serialize_and_deserialize_market_orders(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == order print(b64encode(serialized)) print(order) def test_serialize_and_deserialize_limit_orders(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), Price(1.00000, precision=5), TimeInForce.DAY, ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == order print(b64encode(serialized)) print(order) def test_serialize_and_deserialize_limit_orders_with_expire_time(self): # Arrange order = LimitOrder( ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=uuid4(), timestamp_ns=0, ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == order print(b64encode(serialized)) print(order) def test_serialize_and_deserialize_stop_market_orders_with_expire_time( self): # Arrange order = StopMarketOrder( ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=uuid4(), timestamp_ns=0, ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == order print(b64encode(serialized)) print(order) def test_serialize_and_deserialize_stop_limit_orders(self): # Arrange order = StopLimitOrder( ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), trigger=Price(1.00010, precision=5), time_in_force=TimeInForce.GTC, expire_time=None, init_id=uuid4(), timestamp_ns=0, ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == order print(b64encode(serialized)) print(order) def test_serialize_and_deserialize_stop_limit_orders_with_expire_time( self): # Arrange order = StopLimitOrder( ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), trigger=Price(1.00010, precision=5), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=uuid4(), timestamp_ns=0, ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == order print(b64encode(serialized)) print(order)
class TestMsgPackSerializer: def setup(self): # Fixture Setup self.trader_id = TestIdStubs.trader_id() self.strategy_id = TestIdStubs.strategy_id() self.account_id = TestIdStubs.account_id() self.venue = Venue("SIM") self.unpacker = OrderUnpacker() self.order_factory = OrderFactory( trader_id=self.trader_id, strategy_id=self.strategy_id, clock=TestClock(), ) self.serializer = MsgPackSerializer() def test_serialize_unknown_object_raises_runtime_error(self): # Arrange, Act with pytest.raises(RuntimeError): self.serializer.serialize({"type": "UNKNOWN"}) def test_deserialize_unknown_object_raises_runtime_error(self): # Arrange, Act with pytest.raises(RuntimeError): self.serializer.deserialize(msgpack.packb({"type": "UNKNOWN"})) def test_serialize_and_deserialize_fx_instrument(self): # Arrange, Act serialized = self.serializer.serialize(AUDUSD_SIM) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == AUDUSD_SIM print(b64encode(serialized)) print(deserialized) def test_serialize_and_deserialize_crypto_perpetual_instrument(self): # Arrange, Act serialized = self.serializer.serialize(ETHUSDT_BINANCE) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == ETHUSDT_BINANCE print(b64encode(serialized)) print(deserialized) def test_serialize_and_deserialize_crypto_future_instrument(self): # Arrange, Act serialized = self.serializer.serialize(BTCUSDT_220325) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == BTCUSDT_220325 print(b64encode(serialized)) print(deserialized) def test_pack_and_unpack_market_orders(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_limit_orders(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), Price(1.00000, precision=5), TimeInForce.DAY, display_qty=Quantity(50000, precision=0), ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_limit_orders_with_expiration(self): # Arrange order = LimitOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH + timedelta(minutes=1), init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_stop_market_orders(self): # Arrange order = StopMarketOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), trigger_price=Price(1.00000, precision=5), trigger_type=TriggerType.DEFAULT, time_in_force=TimeInForce.GTC, expire_time=None, init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_stop_market_orders_with_expiration(self): # Arrange order = StopMarketOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), trigger_price=Price(1.00000, precision=5), trigger_type=TriggerType.DEFAULT, time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH + timedelta(minutes=1), init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_stop_limit_orders(self): # Arrange order = StopLimitOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), trigger_price=Price(1.00010, precision=5), trigger_type=TriggerType.BID_ASK, time_in_force=TimeInForce.GTC, expire_time=None, init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_market_to_limit__orders(self): # Arrange order = MarketToLimitOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), time_in_force=TimeInForce.GTD, # <-- invalid expire_time=UNIX_EPOCH + timedelta(minutes=1), init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_market_if_touched_orders(self): # Arrange order = MarketIfTouchedOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), trigger_price=Price(1.00000, precision=5), trigger_type=TriggerType.DEFAULT, time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH + timedelta(minutes=1), init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_limit_if_touched_orders(self): # Arrange order = LimitIfTouchedOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), trigger_price=Price(1.00010, precision=5), trigger_type=TriggerType.BID_ASK, time_in_force=TimeInForce.GTC, expire_time=None, init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_stop_limit_orders_with_expiration(self): # Arrange order = StopLimitOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), trigger_price=Price(1.00010, precision=5), trigger_type=TriggerType.LAST, time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH + timedelta(minutes=1), init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_trailing_stop_market_orders_with_expiration(self): # Arrange order = TrailingStopMarketOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), trigger_price=Price(1.00000, precision=5), trigger_type=TriggerType.DEFAULT, trailing_offset=Decimal("0.00010"), offset_type=TrailingOffsetType.PRICE, time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH + timedelta(minutes=1), init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_trailing_stop_market_orders_no_initial_prices(self): # Arrange order = TrailingStopMarketOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), trigger_price=None, trigger_type=TriggerType.DEFAULT, trailing_offset=Decimal("0.00010"), offset_type=TrailingOffsetType.PRICE, time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH + timedelta(minutes=1), init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_trailing_stop_limit_orders_with_expiration(self): # Arrange order = TrailingStopLimitOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), trigger_price=Price(1.00010, precision=5), trigger_type=TriggerType.MARK, limit_offset=Decimal("50"), trailing_offset=Decimal("50"), offset_type=TrailingOffsetType.TICKS, time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH + timedelta(minutes=1), init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_trailing_stop_limit_orders_with_no_initial_prices(self): # Arrange order = TrailingStopLimitOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity(100000, precision=0), price=None, trigger_price=None, trigger_type=TriggerType.MARK, limit_offset=Decimal("50"), trailing_offset=Decimal("50"), offset_type=TrailingOffsetType.TICKS, time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH + timedelta(minutes=1), init_id=UUID4(), ts_init=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order 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_serialize_and_deserialize_submit_order_list_commands( self, ): # Arrange bracket = self.order_factory.bracket_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), stop_loss=Price(0.99900, precision=5), take_profit=Price(1.00010, precision=5), ) command = SubmitOrderList( client_id=ClientId("SIM"), trader_id=self.trader_id, strategy_id=StrategyId("SCALPER-001"), order_list=bracket, command_id=UUID4(), ts_init=0, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command assert deserialized.list == bracket print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_modify_order_commands(self): # Arrange command = ModifyOrder( self.trader_id, StrategyId("SCALPER-001"), AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("001"), Quantity(100000, precision=0), Price(1.00001, precision=5), None, UUID4(), 0, ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_cancel_order_commands(self): # Arrange command = CancelOrder( self.trader_id, StrategyId("SCALPER-001"), AUDUSD_SIM.id, ClientOrderId("O-123456"), VenueOrderId("001"), UUID4(), 0, ClientId("SIM-001"), ) # Act serialized = self.serializer.serialize(command) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == command print(b64encode(serialized)) print(command) def test_serialize_and_deserialize_component_state_changed_events(self): # Arrange event = ComponentStateChanged( trader_id=TestIdStubs.trader_id(), component_id=ComponentId("MyActor-001"), component_type="MyActor", state=ComponentState.RUNNING, config={"do_something": True}, event_id=UUID4(), ts_event=0, ts_init=0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_account_state_with_base_currency_events(self): # Arrange event = AccountState( account_id=AccountId("SIM", "000"), account_type=AccountType.MARGIN, base_currency=USD, reported=True, balances=[ AccountBalance( Money(1525000, USD), Money(25000, USD), Money(1500000, USD), ), ], margins=[ MarginBalance( Money(5000, USD), Money(20000, USD), AUDUSD_SIM.id, ), ], info={}, event_id=UUID4(), ts_event=0, ts_init=1_000_000_000, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_account_state_without_base_currency_events(self): # Arrange event = AccountState( account_id=AccountId("SIM", "000"), account_type=AccountType.MARGIN, base_currency=None, reported=True, balances=[ AccountBalance( Money(10000, USDT), Money(0, USDT), Money(10000, USDT), ), ], margins=[], info={}, event_id=UUID4(), ts_event=0, ts_init=1_000_000_000, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_market_order_initialized_events(self): # Arrange event = OrderInitialized( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.SELL, OrderType.MARKET, Quantity(100000, precision=0), TimeInForce.FOK, post_only=False, reduce_only=True, options={}, order_list_id=OrderListId("1"), contingency_type=ContingencyType.OTO, linked_order_ids=[ClientOrderId("O-123457"), ClientOrderId("O-123458")], parent_order_id=ClientOrderId("O-123455"), tags="ENTRY", event_id=UUID4(), ts_init=0, ) # Act serialized = self.serializer.serialize(event) deserialized = self.serializer.deserialize(serialized) # Assert assert deserialized == event def test_serialize_and_deserialize_limit_order_initialized_events(self): # Arrange options = { "expire_time_ns": 1_000_000_000, "price": "1.0010", }
class MsgPackOrderSerializerTests(unittest.TestCase): def setUp(self): # Fixture Setup self.serializer = MsgPackOrderSerializer() self.order_factory = OrderFactory( trader_id=TraderId("TESTER", "000"), strategy_id=StrategyId("S", "001"), clock=TestClock(), ) def test_serialize_and_deserialize_market_orders(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(order, deserialized) print(b64encode(serialized)) print(order) def test_serialize_and_deserialize_limit_orders(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), TimeInForce.DAY, expire_time=None, ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(order, deserialized) print(b64encode(serialized)) print(order) def test_serialize_and_deserialize_limit_orders_with_expire_time(self): # Arrange order = LimitOrder( ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), price=Price("1.00000"), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=uuid4(), timestamp=UNIX_EPOCH, ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(order, deserialized) print(b64encode(serialized)) print(order) def test_serialize_and_deserialize_stop_orders_with_expire_time(self): # Arrange order = StopMarketOrder( ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), price=Price("1.00000"), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=uuid4(), timestamp=UNIX_EPOCH, ) # Act serialized = self.serializer.serialize(order) deserialized = self.serializer.deserialize(serialized) # Assert self.assertEqual(order, deserialized) print(b64encode(serialized)) print(order)
class OrderTests(unittest.TestCase): def setUp(self): # Fixture Setup self.account_id = TestStubs.account_id() self.order_factory = OrderFactory( trader_id=TraderId("TESTER-000"), strategy_id=StrategyId("S-001"), clock=TestClock(), ) def test_opposite_side_given_invalid_value_raises_value_error(self): # Arrange # Act # Assert self.assertRaises(ValueError, Order.opposite_side, 0) def test_flatten_side_given_invalid_value_or_flat_raises_value_error(self): # Arrange # Act self.assertRaises(ValueError, Order.flatten_side, 0) self.assertRaises(ValueError, Order.flatten_side, PositionSide.FLAT) @parameterized.expand([ [OrderSide.BUY, OrderSide.SELL], [OrderSide.SELL, OrderSide.BUY], ]) def test_opposite_side_returns_expected_sides(self, side, expected): # Arrange # Act result = Order.opposite_side(side) # Assert self.assertEqual(expected, result) @parameterized.expand([ [PositionSide.LONG, OrderSide.SELL], [PositionSide.SHORT, OrderSide.BUY], ]) def test_flatten_side_returns_expected_sides(self, side, expected): # Arrange # Act result = Order.flatten_side(side) # Assert self.assertEqual(expected, result) 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_market_order_with_invalid_tif_raises_value_error(self): # Arrange # Act self.assertRaises( ValueError, MarketOrder, ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100), TimeInForce.GTD, uuid4(), 0, ) def test_stop_market_order_with_gtd_and_expire_time_none_raises_type_error( self): # Arrange # Act self.assertRaises( TypeError, StopMarketOrder, ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), price=Price.from_str("1.00000"), init_id=uuid4(), timestamp_ns=0, time_in_force=TimeInForce.GTD, expire_time=None, ) def test_stop_limit_buy_order_with_gtd_and_expire_time_none_raises_type_error( self): # Arrange # Act self.assertRaises( TypeError, StopLimitOrder, ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), price=Price.from_str("1.00001"), trigger=Price.from_str("1.00000"), init_id=uuid4(), timestamp_ns=0, time_in_force=TimeInForce.GTD, expire_time=None, ) def test_reset_order_factory(self): # Arrange self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) # Act self.order_factory.reset() order2 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) self.assertEqual(ClientOrderId("O-19700101-000000-000-001-1"), order2.client_order_id) def test_limit_order_can_create_expected_decimal_price(self): # Arrange # Act order1 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) order2 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00001"), ) # Assert self.assertEqual(Price.from_str("1.00000"), order1.price) self.assertEqual(Price.from_str("1.00001"), order2.price) def test_initialize_buy_market_order(self): # Arrange # Act order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) # Assert self.assertEqual(AUDUSD_SIM.id.symbol, order.symbol) self.assertEqual(AUDUSD_SIM.id.venue, order.venue) self.assertEqual(OrderType.MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(1, order.event_count) self.assertTrue(isinstance(order.last_event, OrderInitialized)) self.assertFalse(order.is_working) self.assertFalse(order.is_completed) self.assertTrue(order.is_buy) self.assertFalse(order.is_sell) self.assertFalse(order.is_passive) self.assertTrue(order.is_aggressive) self.assertEqual(0, order.execution_ns) self.assertEqual(0, order.last_event.timestamp_ns) self.assertEqual(OrderInitialized, type(order.init_event)) self.assertTrue(order == order) self.assertFalse(order != order) def test_initialize_sell_market_order(self): # Arrange # Act order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(100000), ) # Assert self.assertEqual(OrderType.MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(1, order.event_count) self.assertTrue(isinstance(order.last_event, OrderInitialized)) self.assertEqual(1, len(order.events)) self.assertFalse(order.is_working) self.assertFalse(order.is_completed) self.assertFalse(order.is_buy) self.assertTrue(order.is_sell) self.assertEqual(0, order.execution_ns) self.assertEqual(OrderInitialized, type(order.init_event)) def test_order_equality(self): # Arrange # Act order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) # Assert self.assertTrue(order == order) self.assertFalse(order != order) def test_order_str_and_repr(self): # Arrange # Act order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) # Assert self.assertEqual( "MarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, state=INITIALIZED, " "client_order_id=O-19700101-000000-000-001-1)", str(order), ) self.assertEqual( "MarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, state=INITIALIZED, " "client_order_id=O-19700101-000000-000-001-1)", repr(order), ) def test_initialize_limit_order(self): # Arrange # Act order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) # Assert self.assertEqual(OrderType.LIMIT, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(TimeInForce.GTC, order.time_in_force) self.assertTrue(order.is_passive) self.assertFalse(order.is_aggressive) self.assertFalse(order.is_completed) self.assertEqual(OrderInitialized, type(order.init_event)) self.assertEqual( "LimitOrder(BUY 100_000 AUD/USD.SIM LIMIT @ 1.00000 GTC, " "state=INITIALIZED, client_order_id=O-19700101-000000-000-001-1)", str(order), ) self.assertEqual( "LimitOrder(BUY 100_000 AUD/USD.SIM LIMIT @ 1.00000 GTC, " "state=INITIALIZED, client_order_id=O-19700101-000000-000-001-1)", repr(order), ) def test_initialize_limit_order_with_expire_time(self): # Arrange # Act order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), TimeInForce.GTD, expire_time=UNIX_EPOCH, ) # Assert self.assertEqual(AUDUSD_SIM.id, order.instrument_id) self.assertEqual(OrderType.LIMIT, order.type) self.assertEqual(Price.from_str("1.00000"), order.price) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(TimeInForce.GTD, order.time_in_force) self.assertEqual(UNIX_EPOCH, order.expire_time) self.assertFalse(order.is_completed) self.assertEqual(OrderInitialized, type(order.init_event)) def test_initialize_stop_market_order(self): # Arrange # Act order = self.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) # Assert self.assertEqual(OrderType.STOP_MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(TimeInForce.GTC, order.time_in_force) self.assertTrue(order.is_passive) self.assertFalse(order.is_aggressive) self.assertFalse(order.is_completed) self.assertEqual(OrderInitialized, type(order.init_event)) self.assertEqual( "StopMarketOrder(BUY 100_000 AUD/USD.SIM STOP_MARKET @ 1.00000 GTC, " "state=INITIALIZED, client_order_id=O-19700101-000000-000-001-1)", str(order), ) self.assertEqual( "StopMarketOrder(BUY 100_000 AUD/USD.SIM STOP_MARKET @ 1.00000 GTC, " "state=INITIALIZED, client_order_id=O-19700101-000000-000-001-1)", repr(order), ) def test_initialize_stop_limit_order(self): # Arrange # Act order = self.order_factory.stop_limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), Price.from_str("1.10010"), ) # Assert self.assertEqual(OrderType.STOP_LIMIT, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(TimeInForce.GTC, order.time_in_force) self.assertTrue(order.is_passive) self.assertFalse(order.is_aggressive) self.assertFalse(order.is_completed) self.assertEqual(OrderInitialized, type(order.init_event)) self.assertEqual( "StopLimitOrder(BUY 100_000 AUD/USD.SIM STOP_LIMIT @ 1.00000 GTC, " "trigger=1.10010, state=INITIALIZED, client_order_id=O-19700101-000000-000-001-1)", str(order), ) self.assertEqual( "StopLimitOrder(BUY 100_000 AUD/USD.SIM STOP_LIMIT @ 1.00000 GTC, " "trigger=1.10010, state=INITIALIZED, client_order_id=O-19700101-000000-000-001-1)", repr(order), ) def test_bracket_order_equality(self): # Arrange entry1 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) entry2 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) bracket_order1 = self.order_factory.bracket(entry1, Price.from_str("1.00000"), Price.from_str("1.00010")) bracket_order2 = self.order_factory.bracket(entry2, Price.from_str("1.00000"), Price.from_str("1.00010")) # Act # Assert self.assertTrue(bracket_order1 == bracket_order1) self.assertTrue(bracket_order1 != bracket_order2) def test_initialize_bracket_order(self): # Arrange entry_order = self.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("0.99995"), ) # Act bracket_order = self.order_factory.bracket( entry_order, Price.from_str("0.99990"), Price.from_str("1.00010"), TimeInForce.GTC, TimeInForce.GTC, ) # Assert self.assertEqual(AUDUSD_SIM.id, bracket_order.stop_loss.instrument_id) self.assertTrue(bracket_order.take_profit is not None) self.assertEqual(AUDUSD_SIM.id, bracket_order.take_profit.instrument_id) self.assertEqual( ClientOrderId("O-19700101-000000-000-001-1"), bracket_order.entry.client_order_id, ) self.assertEqual( ClientOrderId("O-19700101-000000-000-001-2"), bracket_order.stop_loss.client_order_id, ) self.assertEqual( ClientOrderId("O-19700101-000000-000-001-3"), bracket_order.take_profit.client_order_id, ) self.assertEqual(OrderSide.SELL, bracket_order.stop_loss.side) self.assertEqual(OrderSide.SELL, bracket_order.take_profit.side) self.assertEqual(Quantity.from_int(100000), bracket_order.stop_loss.quantity) self.assertEqual(Quantity.from_int(100000), bracket_order.take_profit.quantity) self.assertEqual(Price.from_str("0.99990"), bracket_order.stop_loss.price) self.assertEqual(Price.from_str("1.00010"), bracket_order.take_profit.price) self.assertEqual(TimeInForce.GTC, bracket_order.stop_loss.time_in_force) self.assertEqual(TimeInForce.GTC, bracket_order.take_profit.time_in_force) self.assertEqual(None, bracket_order.entry.expire_time) self.assertEqual(None, bracket_order.stop_loss.expire_time) self.assertEqual(None, bracket_order.take_profit.expire_time) self.assertEqual(ClientOrderLinkId("BO-19700101-000000-000-001-1"), bracket_order.id) self.assertEqual(0, bracket_order.timestamp_ns) def test_bracket_order_str_and_repr(self): # Arrange # Act entry_order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) bracket_order = self.order_factory.bracket( entry_order, Price.from_str("0.99990"), Price.from_str("1.00010"), ) # Assert self.assertEqual( "BracketOrder(id=BO-19700101-000000-000-001-1, " "EntryMarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, " "state=INITIALIZED, client_order_id=O-19700101-000000-000-001-1), " "SL=0.99990, TP=1.00010)", str(bracket_order), ) # noqa self.assertEqual( "BracketOrder(id=BO-19700101-000000-000-001-1, " "EntryMarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, " "state=INITIALIZED, client_order_id=O-19700101-000000-000-001-1), " "SL=0.99990, TP=1.00010)", repr(bracket_order), ) # noqa def test_apply_order_invalid_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) invalid = OrderInvalid( order.client_order_id, "SOME_REASON", uuid4(), 0, ) # Act order.apply(invalid) # Assert self.assertEqual(OrderState.INVALID, order.state) self.assertEqual(2, order.event_count) self.assertEqual(invalid, order.last_event) self.assertTrue(order.is_completed) def test_apply_order_denied_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) denied = OrderDenied( order.client_order_id, "SOME_REASON", uuid4(), 0, ) # Act order.apply(denied) # Assert self.assertEqual(OrderState.DENIED, order.state) self.assertEqual(2, order.event_count) self.assertEqual(denied, order.last_event) self.assertTrue(order.is_completed) def test_apply_order_submitted_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) submitted = TestStubs.event_order_submitted(order) # Act order.apply(submitted) # Assert self.assertEqual(OrderState.SUBMITTED, order.state) self.assertEqual(2, order.event_count) self.assertEqual(submitted, order.last_event) self.assertFalse(order.is_working) self.assertFalse(order.is_completed) def test_apply_order_accepted_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order.apply(TestStubs.event_order_submitted(order)) # Act order.apply(TestStubs.event_order_accepted(order)) # Assert self.assertEqual(OrderState.ACCEPTED, order.state) self.assertTrue(order.is_working) self.assertFalse(order.is_completed) self.assertEqual( "MarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, state=ACCEPTED, " "client_order_id=O-19700101-000000-000-001-1, venue_order_id=1)", str(order), ) self.assertEqual( "MarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, state=ACCEPTED, " "client_order_id=O-19700101-000000-000-001-1, venue_order_id=1)", repr(order), ) def test_apply_order_rejected_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order.apply(TestStubs.event_order_submitted(order)) # Act order.apply(TestStubs.event_order_rejected(order)) # Assert self.assertEqual(OrderState.REJECTED, order.state) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) def test_apply_order_expired_event(self): # Arrange order = self.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("0.99990"), TimeInForce.GTD, expire_time=UNIX_EPOCH, ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) # Act order.apply(TestStubs.event_order_expired(order)) # Assert self.assertEqual(OrderState.EXPIRED, order.state) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) def test_apply_order_triggered_event(self): # Arrange order = self.order_factory.stop_limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), Price.from_str("0.99990"), TimeInForce.GTD, expire_time=UNIX_EPOCH, ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) # Act order.apply(TestStubs.event_order_triggered(order)) # Assert self.assertEqual(OrderState.TRIGGERED, order.state) self.assertTrue(order.is_working) self.assertFalse(order.is_completed) def test_apply_order_canceled_event(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)) order.apply(TestStubs.event_order_pending_cancel(order)) # Act order.apply(TestStubs.event_order_canceled(order)) # Assert self.assertEqual(OrderState.CANCELED, order.state) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) self.assertEqual(5, order.event_count) def test_apply_order_updated_event_to_stop_order(self): # Arrange order = self.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) order.apply(TestStubs.event_order_pending_replace(order)) updated = OrderUpdated( self.account_id, order.client_order_id, VenueOrderId("1"), Quantity.from_int(120000), Price.from_str("1.00001"), 0, uuid4(), 0, ) # Act order.apply(updated) # Assert self.assertEqual(OrderState.ACCEPTED, order.state) self.assertEqual(VenueOrderId("1"), order.venue_order_id) self.assertEqual(Quantity.from_int(120000), order.quantity) self.assertEqual(Price.from_str("1.00001"), order.price) self.assertTrue(order.is_working) self.assertFalse(order.is_completed) self.assertEqual(5, order.event_count) def test_apply_order_updated_venue_id_change(self): # Arrange order = self.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) order.apply(TestStubs.event_order_pending_replace(order)) updated = OrderUpdated( self.account_id, order.client_order_id, VenueOrderId("2"), Quantity.from_int(120000), Price.from_str("1.00001"), 0, uuid4(), 0, ) # Act order.apply(updated) # Assert self.assertEqual(VenueOrderId("2"), order.venue_order_id) self.assertEqual([VenueOrderId("1")], order.venue_order_ids) 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 self.assertEqual(OrderState.FILLED, order.state) self.assertEqual(Quantity.from_int(100000), order.filled_qty) self.assertEqual(Decimal("1.00001"), order.avg_px) self.assertEqual(1, len(order.execution_ids)) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) self.assertEqual(0, order.execution_ns) def test_apply_order_filled_event_to_market_order(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 self.assertEqual(OrderState.FILLED, order.state) self.assertEqual(Quantity.from_int(100000), order.filled_qty) self.assertEqual(Decimal("1.00001"), order.avg_px) self.assertEqual(1, len(order.execution_ids)) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) self.assertEqual(0, order.execution_ns) def test_apply_partial_fill_events_to_market_order_results_in_partially_filled( 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)) fill1 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, execution_id=ExecutionId("1"), position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), last_qty=Quantity.from_int(20000), ) fill2 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, execution_id=ExecutionId("2"), position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00002"), last_qty=Quantity.from_int(40000), ) # Act order.apply(fill1) order.apply(fill2) # Assert self.assertEqual(OrderState.PARTIALLY_FILLED, order.state) self.assertEqual(Quantity.from_int(60000), order.filled_qty) self.assertEqual(Decimal("1.000014"), order.avg_px) self.assertEqual(2, len(order.execution_ids)) self.assertTrue(order.is_working) self.assertFalse(order.is_completed) self.assertEqual(0, order.execution_ns) def test_apply_filled_events_to_market_order_results_in_filled(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)) fill1 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, execution_id=ExecutionId("1"), position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), last_qty=Quantity.from_int(20000), ) fill2 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, execution_id=ExecutionId("2"), position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00002"), last_qty=Quantity.from_int(40000), ) fill3 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, execution_id=ExecutionId("3"), position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00003"), last_qty=Quantity.from_int(40000), ) # Act order.apply(fill1) order.apply(fill2) order.apply(fill3) # Assert self.assertEqual(OrderState.FILLED, order.state) self.assertEqual(Quantity.from_int(100000), order.filled_qty) self.assertEqual(Decimal("1.000018571428571428571428571"), order.avg_px) self.assertEqual(3, len(order.execution_ids)) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) self.assertEqual(0, order.execution_ns) def test_apply_order_filled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) filled = OrderFilled( self.account_id, order.client_order_id, VenueOrderId("1"), ExecutionId("E-1"), PositionId("P-1"), StrategyId.null(), order.instrument_id, order.side, order.quantity, Price.from_str("1.00001"), AUDUSD_SIM.quote_currency, Money(0, USD), LiquiditySide.MAKER, 0, uuid4(), 0, ) # Act order.apply(filled) # Assert self.assertEqual(OrderState.FILLED, order.state) self.assertEqual(Quantity.from_int(100000), order.filled_qty) self.assertEqual(Price.from_str("1.00000"), order.price) self.assertEqual(Decimal("1.00001"), order.avg_px) self.assertEqual(Decimal("0.00001"), order.slippage) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) self.assertEqual(0, order.execution_ns) def test_apply_order_partially_filled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) partially = OrderFilled( self.account_id, order.client_order_id, VenueOrderId("1"), ExecutionId("E-1"), PositionId("P-1"), StrategyId.null(), order.instrument_id, order.side, Quantity.from_int(50000), Price.from_str("0.999999"), AUDUSD_SIM.quote_currency, Money(0, USD), LiquiditySide.MAKER, 1_000_000_000, uuid4(), 1_000_000_000, ) # Act order.apply(partially) # Assert self.assertEqual(OrderState.PARTIALLY_FILLED, order.state) self.assertEqual(Quantity.from_int(50000), order.filled_qty) self.assertEqual(Price.from_str("1.00000"), order.price) self.assertEqual(Decimal("0.999999"), order.avg_px) self.assertEqual(Decimal("-0.000001"), order.slippage) self.assertTrue(order.is_working) self.assertFalse(order.is_completed) self.assertEqual(1_000_000_000, order.execution_ns)
class ReportProviderTests(unittest.TestCase): def setUp(self): # Fixture Setup self.account_id = TestStubs.account_id() self.order_factory = OrderFactory( trader_id=TraderId("TESTER", "000"), strategy_id=StrategyId("S", "001"), clock=TestClock(), ) def test_generate_accounts_report_with_initial_account_state_returns_expected( self): # Arrange state = AccountState( account_id=AccountId("BITMEX", "1513111"), balances=[Money("10.00000000", BTC)], balances_free=[Money("10.00000000", BTC)], balances_locked=[Money("0.00000000", BTC)], info={}, event_id=uuid4(), event_timestamp=UNIX_EPOCH, ) account = Account(state) report_provider = ReportProvider() # Act report = report_provider.generate_account_report(account) # Assert self.assertEqual(1, len(report)) def test_generate_orders_report_with_no_order_returns_emtpy_dataframe( self): # Arrange report_provider = ReportProvider() # Act report = report_provider.generate_orders_report([]) # Assert self.assertTrue(report.empty) def test_generate_orders_fills_report_with_no_order_returns_emtpy_dataframe( self): # Arrange report_provider = ReportProvider() # Act report = report_provider.generate_order_fills_report([]) # Assert self.assertTrue(report.empty) def test_generate_positions_report_with_no_positions_returns_emtpy_dataframe( self): # Arrange report_provider = ReportProvider() # Act report = report_provider.generate_positions_report([]) # Assert self.assertTrue(report.empty) def test_generate_orders_report(self): # Arrange report_provider = ReportProvider() order1 = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(1500000), Price("0.80010"), ) order1.apply(TestStubs.event_order_submitted(order1)) order1.apply(TestStubs.event_order_accepted(order1)) order1.apply(TestStubs.event_order_working(order1)) order2 = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.SELL, Quantity(1500000), Price("0.80000"), ) order2.apply(TestStubs.event_order_submitted(order2)) order2.apply(TestStubs.event_order_accepted(order2)) order2.apply(TestStubs.event_order_working(order2)) event = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-1"), fill_price=Price("0.80011"), ) order1.apply(event) orders = [order1, order2] # Act report = report_provider.generate_orders_report(orders) # Assert self.assertEqual(2, len(report)) self.assertEqual("cl_ord_id", report.index.name) self.assertEqual(order1.cl_ord_id.value, report.index[0]) self.assertEqual("AUD/USD", report.iloc[0]["symbol"]) self.assertEqual("BUY", report.iloc[0]["side"]) self.assertEqual("LIMIT", report.iloc[0]["type"]) self.assertEqual(1500000, report.iloc[0]["quantity"]) self.assertEqual(0.80011, report.iloc[0]["avg_price"]) self.assertEqual(0.00001, report.iloc[0]["slippage"]) self.assertEqual("None", report.iloc[1]["avg_price"]) def test_generate_order_fills_report(self): # Arrange report_provider = ReportProvider() order1 = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(1500000), Price("0.80010"), ) order1.apply(TestStubs.event_order_submitted(order1)) order1.apply(TestStubs.event_order_accepted(order1)) order1.apply(TestStubs.event_order_working(order1)) order2 = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.SELL, Quantity(1500000), Price("0.80000"), ) submitted2 = TestStubs.event_order_submitted(order2) accepted2 = TestStubs.event_order_accepted(order2) working2 = TestStubs.event_order_working(order2) order2.apply(submitted2) order2.apply(accepted2) order2.apply(working2) filled = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-1"), strategy_id=StrategyId("S", "1"), fill_price=Price("0.80011"), ) order1.apply(filled) orders = [order1, order2] # Act report = report_provider.generate_order_fills_report(orders) # Assert self.assertEqual(1, len(report)) self.assertEqual("cl_ord_id", report.index.name) self.assertEqual(order1.cl_ord_id.value, report.index[0]) self.assertEqual("AUD/USD", report.iloc[0]["symbol"]) self.assertEqual("BUY", report.iloc[0]["side"]) self.assertEqual("LIMIT", report.iloc[0]["type"]) self.assertEqual(1500000, report.iloc[0]["quantity"]) self.assertEqual(0.80011, report.iloc[0]["avg_price"]) self.assertEqual(0.00001, report.iloc[0]["slippage"]) def test_generate_positions_report(self): # Arrange report_provider = ReportProvider() order1 = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) order2 = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.SELL, Quantity(100000), ) fill1 = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S", "001"), fill_price=Price("1.00010"), ) fill2 = TestStubs.event_order_filled( order2, instrument=AUDUSD_SIM, position_id=PositionId("P-123457"), strategy_id=StrategyId("S", "001"), fill_price=Price("1.00010"), ) position1 = Position(fill1) position1.apply(fill2) position2 = Position(fill1) position2.apply(fill2) positions = [position1, position2] # Act report = report_provider.generate_positions_report(positions) # Assert self.assertEqual(2, len(report)) self.assertEqual("position_id", report.index.name) self.assertEqual(position1.id.value, report.index[0]) self.assertEqual("AUD/USD", report.iloc[0]["symbol"]) self.assertEqual("BUY", report.iloc[0]["entry"]) self.assertEqual(100000, report.iloc[0]["peak_quantity"]) self.assertEqual(1.0001, report.iloc[0]["avg_open"]) self.assertEqual(1.0001, report.iloc[0]["avg_close"]) self.assertEqual(UNIX_EPOCH, report.iloc[0]["opened_time"]) self.assertEqual(UNIX_EPOCH, report.iloc[0]["closed_time"]) self.assertEqual(0, report.iloc[0]["realized_points"]) self.assertEqual(0, report.iloc[0]["realized_return"])
class TestOrders: def setup(self): # Fixture Setup self.trader_id = TestStubs.trader_id() self.strategy_id = TestStubs.strategy_id() self.account_id = TestStubs.account_id() self.order_factory = OrderFactory( trader_id=self.trader_id, strategy_id=self.strategy_id, clock=TestClock(), ) def test_opposite_side_given_invalid_value_raises_value_error(self): # Arrange, Act, Assert with pytest.raises(ValueError): Order.opposite_side(0) # <-- invalid value def test_flatten_side_given_invalid_value_or_flat_raises_value_error(self): # Arrange, Act with pytest.raises(ValueError): Order.flatten_side(0) # <-- invalid value with pytest.raises(ValueError): Order.flatten_side(PositionSide.FLAT) @pytest.mark.parametrize( "side, expected", [ [OrderSide.BUY, OrderSide.SELL], [OrderSide.SELL, OrderSide.BUY], ], ) def test_opposite_side_returns_expected_sides(self, side, expected): # Arrange, Act result = Order.opposite_side(side) # Assert assert result == expected @pytest.mark.parametrize( "side, expected", [ [PositionSide.LONG, OrderSide.SELL], [PositionSide.SHORT, OrderSide.BUY], ], ) def test_flatten_side_returns_expected_sides(self, side, expected): # Arrange, Act result = Order.flatten_side(side) # Assert assert result == expected def test_market_order_with_quantity_zero_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.DAY, UUID4(), 0, ) 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_stop_market_order_with_gtd_and_expire_time_none_raises_type_error( self): # Arrange, Act, Assert with pytest.raises(TypeError): StopMarketOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity.from_int(100000), price=Price.from_str("1.00000"), init_id=UUID4(), ts_init=0, time_in_force=TimeInForce.GTD, expire_time=None, ) def test_stop_limit_buy_order_with_gtd_and_expire_time_none_raises_type_error( self): # Arrange, Act, Assert with pytest.raises(TypeError): StopLimitOrder( self.trader_id, self.strategy_id, AUDUSD_SIM.id, ClientOrderId("O-123456"), OrderSide.BUY, Quantity.from_int(100000), price=Price.from_str("1.00001"), trigger=Price.from_str("1.00000"), init_id=UUID4(), ts_init=0, time_in_force=TimeInForce.GTD, expire_time=None, ) def test_overfill_limit_buy_order_raises_value_error(self): # Arrange, Act, Assert order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) over_fill = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, last_qty=Quantity.from_int(110000) # <-- overfill ) # Assert with pytest.raises(ValueError): order.apply(over_fill) def test_reset_order_factory(self): # Arrange self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) # Act self.order_factory.reset() order2 = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) assert order2.client_order_id.value == "O-19700101-000000-000-001-1" def test_initialize_buy_market_order(self): # Arrange, Act order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) # Assert assert order.symbol == AUDUSD_SIM.id.symbol assert order.venue == AUDUSD_SIM.id.venue assert order.type == OrderType.MARKET assert order.status == OrderStatus.INITIALIZED assert order.event_count == 1 assert isinstance(order.last_event, OrderInitialized) assert order.is_active assert not order.is_inflight assert not order.is_working assert not order.is_completed assert order.is_buy assert order.is_aggressive assert not order.is_sell assert not order.is_contingency assert not order.is_passive assert not order.is_parent_order assert not order.is_child_order assert order.ts_last == 0 assert order.last_event.ts_init == 0 assert isinstance(order.init_event, OrderInitialized) def test_initialize_sell_market_order(self): # Arrange, Act order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(100000), ) # Assert assert order.type == OrderType.MARKET assert order.status == OrderStatus.INITIALIZED assert order.event_count == 1 assert isinstance(order.last_event, OrderInitialized) assert len(order.events) == 1 assert order.is_active assert not order.is_inflight assert not order.is_working assert not order.is_completed assert not order.is_buy assert order.is_sell assert order.ts_last == 0 assert isinstance(order.init_event, OrderInitialized) def test_order_equality(self): # Arrange, Act order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) # Assert assert order == order def test_order_hash_str_and_repr(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), tags="ENTRY", ) # Act, Assert assert isinstance(hash(order), int) assert ( str(order) == "MarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-1, venue_order_id=None, tags=ENTRY)" # noqa ) assert ( repr(order) == "MarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-1, venue_order_id=None, tags=ENTRY)" # noqa ) def test_market_order_to_dict(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) # Act result = order.to_dict() # Assert assert result == { "trader_id": "TESTER-000", "strategy_id": "S-001", "instrument_id": "AUD/USD.SIM", "client_order_id": "O-19700101-000000-000-001-1", "venue_order_id": None, "position_id": None, "account_id": None, "execution_id": None, "type": "MARKET", "side": "BUY", "quantity": "100000", "time_in_force": "GTC", "reduce_only": False, "filled_qty": "0", "avg_px": None, "slippage": "0", "status": "INITIALIZED", "order_list_id": None, "parent_order_id": None, "child_order_ids": None, "contingency": "NONE", "contingency_ids": None, "tags": None, "ts_last": 0, "ts_init": 0, } def test_initialize_limit_order(self): # Arrange, Act order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) # Assert assert order.type == OrderType.LIMIT assert order.status == OrderStatus.INITIALIZED assert order.time_in_force == TimeInForce.GTC assert order.is_passive assert order.is_active assert not order.is_aggressive assert not order.is_completed assert isinstance(order.init_event, OrderInitialized) assert ( str(order) == "LimitOrder(BUY 100_000 AUD/USD.SIM LIMIT @ 1.00000 GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-1, venue_order_id=None, tags=None)" # noqa ) assert ( repr(order) == "LimitOrder(BUY 100_000 AUD/USD.SIM LIMIT @ 1.00000 GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-1, venue_order_id=None, tags=None)" # noqa ) def test_limit_order_to_dict(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), display_qty=Quantity.from_int(20000), ) # Act result = order.to_dict() # Assert assert result == { "trader_id": "TESTER-000", "strategy_id": "S-001", "instrument_id": "AUD/USD.SIM", "client_order_id": "O-19700101-000000-000-001-1", "venue_order_id": None, "position_id": None, "account_id": None, "execution_id": None, "type": "LIMIT", "side": "BUY", "quantity": "100000", "price": "1.00000", "liquidity_side": "NONE", "expire_time_ns": 0, "time_in_force": "GTC", "filled_qty": "0", "avg_px": None, "slippage": "0", "status": "INITIALIZED", "is_post_only": False, "is_reduce_only": False, "display_qty": "20000", "order_list_id": None, "parent_order_id": None, "child_order_ids": None, "contingency": "NONE", "contingency_ids": None, "tags": None, "ts_last": 0, "ts_init": 0, } def test_initialize_limit_order_with_expire_time(self): # Arrange, Act order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), TimeInForce.GTD, expire_time=UNIX_EPOCH, ) # Assert assert order.instrument_id == AUDUSD_SIM.id assert order.type == OrderType.LIMIT assert order.price == Price.from_str("1.00000") assert order.status == OrderStatus.INITIALIZED assert order.time_in_force == TimeInForce.GTD assert order.expire_time == UNIX_EPOCH assert not order.is_completed assert isinstance(order.init_event, OrderInitialized) def test_initialize_stop_market_order(self): # Arrange, Act order = self.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) # Assert assert order.type == OrderType.STOP_MARKET assert order.status == OrderStatus.INITIALIZED assert order.time_in_force == TimeInForce.GTC assert order.is_passive assert not order.is_aggressive assert order.is_active assert not order.is_completed assert isinstance(order.init_event, OrderInitialized) assert ( str(order) == "StopMarketOrder(BUY 100_000 AUD/USD.SIM STOP_MARKET @ 1.00000 GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-1, venue_order_id=None, tags=None)" # noqa ) assert ( repr(order) == "StopMarketOrder(BUY 100_000 AUD/USD.SIM STOP_MARKET @ 1.00000 GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-1, venue_order_id=None, tags=None)" # noqa ) def test_stop_market_order_to_dict(self): # Arrange order = self.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) # Act result = order.to_dict() # Assert assert result == { "trader_id": "TESTER-000", "strategy_id": "S-001", "instrument_id": "AUD/USD.SIM", "client_order_id": "O-19700101-000000-000-001-1", "venue_order_id": None, "position_id": None, "account_id": None, "execution_id": None, "type": "STOP_MARKET", "side": "BUY", "quantity": "100000", "price": "1.00000", "liquidity_side": "NONE", "expire_time_ns": 0, "time_in_force": "GTC", "filled_qty": "0", "avg_px": None, "slippage": "0", "status": "INITIALIZED", "is_reduce_only": False, "order_list_id": None, "parent_order_id": None, "child_order_ids": None, "contingency": "NONE", "contingency_ids": None, "tags": None, "ts_last": 0, "ts_init": 0, } def test_initialize_stop_limit_order(self): # Arrange, Act order = self.order_factory.stop_limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), Price.from_str("1.10010"), tags="ENTRY", ) # Assert assert order.type == OrderType.STOP_LIMIT assert order.status == OrderStatus.INITIALIZED assert order.time_in_force == TimeInForce.GTC assert order.is_passive assert not order.is_aggressive assert not order.is_completed assert isinstance(order.init_event, OrderInitialized) assert ( str(order) == "StopLimitOrder(BUY 100_000 AUD/USD.SIM STOP_LIMIT @ 1.00000 GTC, trigger=1.10010, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-1)" # noqa ) assert ( repr(order) == "StopLimitOrder(BUY 100_000 AUD/USD.SIM STOP_LIMIT @ 1.00000 GTC, trigger=1.10010, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-1)" # noqa ) def test_stop_limit_order_to_dict(self): # Arrange order = self.order_factory.stop_limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), Price.from_str("1.10010"), tags="STOP_LOSS", ) # Act result = order.to_dict() # Assert assert result == { "trader_id": "TESTER-000", "strategy_id": "S-001", "instrument_id": "AUD/USD.SIM", "client_order_id": "O-19700101-000000-000-001-1", "venue_order_id": None, "position_id": None, "account_id": None, "execution_id": None, "type": "STOP_LIMIT", "side": "BUY", "quantity": "100000", "trigger": "1.10010", "price": "1.00000", "liquidity_side": "NONE", "expire_time_ns": 0, "time_in_force": "GTC", "filled_qty": "0", "avg_px": None, "slippage": "0", "status": "INITIALIZED", "is_post_only": False, "is_reduce_only": False, "display_qty": None, "order_list_id": None, "parent_order_id": None, "child_order_ids": None, "contingency": "NONE", "contingency_ids": None, "tags": "STOP_LOSS", "ts_last": 0, "ts_init": 0, } def test_order_list_equality(self): # Arrange bracket1 = self.order_factory.bracket_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), Price.from_str("1.00010"), ) bracket2 = self.order_factory.bracket_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), Price.from_str("1.00010"), ) # Act, Assert assert bracket1 == bracket1 assert bracket1 != bracket2 def test_bracket_market_order_list(self): # Arrange, Act bracket = self.order_factory.bracket_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("0.99990"), Price.from_str("1.00010"), TimeInForce.GTC, ) # Assert assert bracket.id == OrderListId("1") assert bracket.instrument_id == AUDUSD_SIM.id assert len(bracket.orders) == 3 assert bracket.orders[0].type == OrderType.MARKET assert bracket.orders[1].type == OrderType.STOP_MARKET assert bracket.orders[2].type == OrderType.LIMIT assert bracket.orders[0].instrument_id == AUDUSD_SIM.id assert bracket.orders[1].instrument_id == AUDUSD_SIM.id assert bracket.orders[2].instrument_id == AUDUSD_SIM.id assert bracket.orders[0].client_order_id == ClientOrderId( "O-19700101-000000-000-001-1") assert bracket.orders[1].client_order_id == ClientOrderId( "O-19700101-000000-000-001-2") assert bracket.orders[2].client_order_id == ClientOrderId( "O-19700101-000000-000-001-3") assert bracket.orders[0].side == OrderSide.BUY assert bracket.orders[1].side == OrderSide.SELL assert bracket.orders[2].side == OrderSide.SELL assert bracket.orders[0].quantity == Quantity.from_int(100000) assert bracket.orders[1].quantity == Quantity.from_int(100000) assert bracket.orders[2].quantity == Quantity.from_int(100000) assert bracket.orders[1].price == Price.from_str("0.99990") assert bracket.orders[2].price == Price.from_str("1.00010") assert bracket.orders[1].time_in_force == TimeInForce.GTC assert bracket.orders[2].time_in_force == TimeInForce.GTC assert bracket.orders[1].expire_time is None assert bracket.orders[2].expire_time is None assert bracket.orders[0].contingency == ContingencyType.OTO assert bracket.orders[1].contingency == ContingencyType.OCO assert bracket.orders[2].contingency == ContingencyType.OCO assert bracket.orders[0].contingency_ids == [ ClientOrderId("O-19700101-000000-000-001-2"), ClientOrderId("O-19700101-000000-000-001-3"), ] assert bracket.orders[1].contingency_ids == [ ClientOrderId("O-19700101-000000-000-001-3") ] assert bracket.orders[2].contingency_ids == [ ClientOrderId("O-19700101-000000-000-001-2") ] assert bracket.orders[0].child_order_ids == [ ClientOrderId("O-19700101-000000-000-001-2"), ClientOrderId("O-19700101-000000-000-001-3"), ] assert bracket.orders[1].parent_order_id == ClientOrderId( "O-19700101-000000-000-001-1") assert bracket.orders[2].parent_order_id == ClientOrderId( "O-19700101-000000-000-001-1") assert bracket.ts_init == 0 def test_bracket_limit_order_list(self): # Arrange, Act bracket = self.order_factory.bracket_limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), Price.from_str("0.99990"), Price.from_str("1.00010"), TimeInForce.GTC, ) # Assert assert bracket.id == OrderListId("1") assert bracket.instrument_id == AUDUSD_SIM.id assert len(bracket.orders) == 3 assert bracket.orders[0].type == OrderType.LIMIT assert bracket.orders[1].type == OrderType.STOP_MARKET assert bracket.orders[2].type == OrderType.LIMIT assert bracket.orders[0].instrument_id == AUDUSD_SIM.id assert bracket.orders[1].instrument_id == AUDUSD_SIM.id assert bracket.orders[2].instrument_id == AUDUSD_SIM.id assert bracket.orders[0].client_order_id == ClientOrderId( "O-19700101-000000-000-001-1") assert bracket.orders[1].client_order_id == ClientOrderId( "O-19700101-000000-000-001-2") assert bracket.orders[2].client_order_id == ClientOrderId( "O-19700101-000000-000-001-3") assert bracket.orders[0].side == OrderSide.BUY assert bracket.orders[1].side == OrderSide.SELL assert bracket.orders[2].side == OrderSide.SELL assert bracket.orders[0].quantity == Quantity.from_int(100000) assert bracket.orders[1].quantity == Quantity.from_int(100000) assert bracket.orders[2].quantity == Quantity.from_int(100000) assert bracket.orders[1].price == Price.from_str("0.99990") assert bracket.orders[2].price == Price.from_str("1.00010") assert bracket.orders[1].time_in_force == TimeInForce.GTC assert bracket.orders[2].time_in_force == TimeInForce.GTC assert bracket.orders[1].expire_time is None assert bracket.orders[2].expire_time is None assert bracket.orders[0].contingency == ContingencyType.OTO assert bracket.orders[1].contingency == ContingencyType.OCO assert bracket.orders[2].contingency == ContingencyType.OCO assert bracket.orders[0].contingency_ids == [ ClientOrderId("O-19700101-000000-000-001-2"), ClientOrderId("O-19700101-000000-000-001-3"), ] assert bracket.orders[1].contingency_ids == [ ClientOrderId("O-19700101-000000-000-001-3") ] assert bracket.orders[2].contingency_ids == [ ClientOrderId("O-19700101-000000-000-001-2") ] assert bracket.orders[0].child_order_ids == [ ClientOrderId("O-19700101-000000-000-001-2"), ClientOrderId("O-19700101-000000-000-001-3"), ] assert bracket.orders[1].parent_order_id == ClientOrderId( "O-19700101-000000-000-001-1") assert bracket.orders[2].parent_order_id == ClientOrderId( "O-19700101-000000-000-001-1") assert bracket.ts_init == 0 def test_order_list_str_and_repr(self): # Arrange, Act bracket = self.order_factory.bracket_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("0.99990"), Price.from_str("1.00010"), ) # Assert assert str(bracket) == ( "OrderList(id=1, instrument_id=AUD/USD.SIM, orders=[MarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-1, venue_order_id=None, tags=ENTRY), StopMarketOrder(SELL 100_000 AUD/USD.SIM STOP_MARKET @ 0.99990 GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-2, venue_order_id=None, tags=STOP_LOSS), LimitOrder(SELL 100_000 AUD/USD.SIM LIMIT @ 1.00010 GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-3, venue_order_id=None, tags=TAKE_PROFIT)])" # noqa ) assert repr(bracket) == ( "OrderList(id=1, instrument_id=AUD/USD.SIM, orders=[MarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-1, venue_order_id=None, tags=ENTRY), StopMarketOrder(SELL 100_000 AUD/USD.SIM STOP_MARKET @ 0.99990 GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-2, venue_order_id=None, tags=STOP_LOSS), LimitOrder(SELL 100_000 AUD/USD.SIM LIMIT @ 1.00010 GTC, status=INITIALIZED, client_order_id=O-19700101-000000-000-001-3, venue_order_id=None, tags=TAKE_PROFIT)])" # noqa ) def test_apply_order_denied_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) denied = OrderDenied( self.trader_id, self.strategy_id, AUDUSD_SIM.id, order.client_order_id, "SOME_REASON", UUID4(), 0, ) # Act order.apply(denied) # Assert assert order.status == OrderStatus.DENIED assert order.event_count == 2 assert order.last_event == denied assert not order.is_active assert order.is_completed def test_apply_order_submitted_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) submitted = TestStubs.event_order_submitted(order) # Act order.apply(submitted) # Assert assert order.status == OrderStatus.SUBMITTED assert order.event_count == 2 assert order.last_event == submitted assert order.is_active assert order.is_inflight assert not order.is_working assert not order.is_completed assert not order.is_pending_update assert not order.is_pending_cancel def test_apply_order_accepted_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order.apply(TestStubs.event_order_submitted(order)) # Act order.apply(TestStubs.event_order_accepted(order)) # Assert assert order.status == OrderStatus.ACCEPTED assert order.is_active assert not order.is_inflight assert order.is_working assert not order.is_completed assert ( str(order) == "MarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, status=ACCEPTED, client_order_id=O-19700101-000000-000-001-1, venue_order_id=1, tags=None)" # noqa ) assert ( repr(order) == "MarketOrder(BUY 100_000 AUD/USD.SIM MARKET GTC, status=ACCEPTED, client_order_id=O-19700101-000000-000-001-1, venue_order_id=1, tags=None)" # noqa ) def test_apply_order_rejected_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order.apply(TestStubs.event_order_submitted(order)) # Act order.apply(TestStubs.event_order_rejected(order)) # Assert assert order.status == OrderStatus.REJECTED assert not order.is_active assert not order.is_inflight assert not order.is_working assert order.is_completed def test_apply_order_expired_event(self): # Arrange order = self.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("0.99990"), TimeInForce.GTD, expire_time=UNIX_EPOCH, ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) # Act order.apply(TestStubs.event_order_expired(order)) # Assert assert order.status == OrderStatus.EXPIRED assert not order.is_active assert not order.is_inflight assert not order.is_working assert order.is_completed def test_apply_order_triggered_event(self): # Arrange order = self.order_factory.stop_limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), Price.from_str("0.99990"), TimeInForce.GTD, expire_time=UNIX_EPOCH, ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) # Act order.apply(TestStubs.event_order_triggered(order)) # Assert assert order.status == OrderStatus.TRIGGERED assert order.is_active assert not order.is_inflight assert order.is_working assert not order.is_completed def test_order_status_pending_cancel(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)) # Act order.apply(TestStubs.event_order_pending_cancel(order)) # Assert assert order.status == OrderStatus.PENDING_CANCEL assert order.is_active assert order.is_inflight assert order.is_working assert not order.is_completed assert not order.is_pending_update assert order.is_pending_cancel assert order.event_count == 4 def test_apply_order_canceled_event(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)) order.apply(TestStubs.event_order_pending_cancel(order)) # Act order.apply(TestStubs.event_order_canceled(order)) # Assert assert order.status == OrderStatus.CANCELED assert not order.is_active assert not order.is_inflight assert not order.is_working assert order.is_completed assert not order.is_pending_update assert not order.is_pending_cancel assert order.event_count == 5 def test_order_status_pending_replace(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)) # Act order.apply(TestStubs.event_order_pending_update(order)) # Assert assert order.status == OrderStatus.PENDING_UPDATE assert order.is_active assert order.is_inflight assert order.is_working assert not order.is_completed assert order.is_pending_update assert not order.is_pending_cancel assert order.event_count == 4 def test_apply_order_updated_event_to_stop_order(self): # Arrange order = self.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) order.apply(TestStubs.event_order_pending_update(order)) updated = OrderUpdated( order.trader_id, order.strategy_id, order.account_id, order.instrument_id, order.client_order_id, VenueOrderId("1"), Quantity.from_int(120000), Price.from_str("1.00001"), None, UUID4(), 0, 0, ) # Act order.apply(updated) # Assert assert order.status == OrderStatus.ACCEPTED assert order.venue_order_id == VenueOrderId("1") assert order.quantity == Quantity.from_int(120000) assert order.price == Price.from_str("1.00001") assert order.is_active assert not order.is_inflight assert order.is_working assert not order.is_completed assert order.event_count == 5 def test_apply_order_updated_venue_id_change(self): # Arrange order = self.order_factory.stop_market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) order.apply(TestStubs.event_order_pending_update(order)) updated = OrderUpdated( order.trader_id, order.strategy_id, order.account_id, order.instrument_id, order.client_order_id, VenueOrderId("2"), Quantity.from_int(120000), Price.from_str("1.00001"), None, UUID4(), 0, 0, ) # Act order.apply(updated) # Assert assert order.venue_order_id == VenueOrderId("2") assert order.venue_order_ids == [VenueOrderId("1")] 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_apply_order_filled_event_to_market_order(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.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_apply_partial_fill_events_to_market_order_results_in_partially_filled( 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)) fill1 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, execution_id=ExecutionId("1"), position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), last_qty=Quantity.from_int(20000), ) fill2 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, execution_id=ExecutionId("2"), position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00002"), last_qty=Quantity.from_int(40000), ) # Act order.apply(fill1) order.apply(fill2) # Assert assert order.status == OrderStatus.PARTIALLY_FILLED assert order.filled_qty == Quantity.from_int(60000) assert order.leaves_qty == Quantity.from_int(40000) assert order.avg_px == Decimal("1.000014") assert len(order.execution_ids) == 2 assert order.is_active assert not order.is_inflight assert order.is_working assert not order.is_completed assert order.ts_last == 0 def test_apply_filled_events_to_market_order_results_in_filled(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)) fill1 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, execution_id=ExecutionId("1"), position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00001"), last_qty=Quantity.from_int(20000), ) fill2 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, execution_id=ExecutionId("2"), position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00002"), last_qty=Quantity.from_int(40000), ) fill3 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, execution_id=ExecutionId("3"), position_id=PositionId("P-123456"), strategy_id=StrategyId("S-001"), last_px=Price.from_str("1.00003"), last_qty=Quantity.from_int(40000), ) # Act order.apply(fill1) order.apply(fill2) order.apply(fill3) # Assert assert order.status == OrderStatus.FILLED assert order.filled_qty == Quantity.from_int(100000) assert order.avg_px == Decimal("1.000018571428571428571428571") assert len(order.execution_ids) == 3 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_apply_order_filled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) filled = OrderFilled( order.trader_id, order.strategy_id, order.account_id, order.instrument_id, order.client_order_id, VenueOrderId("1"), ExecutionId("E-1"), PositionId("P-1"), order.side, order.type, order.quantity, Price.from_str("1.00001"), AUDUSD_SIM.quote_currency, Money(0, USD), LiquiditySide.MAKER, UUID4(), 0, 0, ) # Act order.apply(filled) # Assert assert order.status == OrderStatus.FILLED assert order.filled_qty == Quantity.from_int(100000) assert order.price == Price.from_str("1.00000") assert order.avg_px == Decimal("1.00001") assert order.slippage == Decimal("0.00001") 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_apply_order_partially_filled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), Price.from_str("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) partially = OrderFilled( order.trader_id, order.strategy_id, order.account_id, order.instrument_id, order.client_order_id, VenueOrderId("1"), ExecutionId("E-1"), PositionId("P-1"), order.side, order.type, Quantity.from_int(50000), Price.from_str("0.999999"), AUDUSD_SIM.quote_currency, Money(0, USD), LiquiditySide.MAKER, UUID4(), 1_000_000_000, 1_000_000_000, ) # Act order.apply(partially) # Assert assert order.status == OrderStatus.PARTIALLY_FILLED assert order.filled_qty == Quantity.from_int(50000) assert order.price == Price.from_str("1.00000") assert order.avg_px == Decimal("0.999999") assert order.slippage == Decimal("-0.000001") assert order.is_active assert not order.is_inflight assert order.is_working assert not order.is_completed assert order.ts_last == 1_000_000_000, order.ts_last
class TestOrderUnpackerSerializer: def setup(self): # Fixture Setup self.unpacker = OrderUnpacker() self.order_factory = OrderFactory( trader_id=TraderId("TESTER-000"), strategy_id=StrategyId("S-001"), clock=TestClock(), ) def test_pack_and_unpack_market_orders(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_limit_orders(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), Price(1.00000, precision=5), TimeInForce.DAY, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_limit_orders_with_expire_time(self): # Arrange order = LimitOrder( ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=uuid4(), timestamp_ns=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_stop_market_orders_with_expire_time(self): # Arrange order = StopMarketOrder( ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=uuid4(), timestamp_ns=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_stop_limit_orders(self): # Arrange order = StopLimitOrder( ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), trigger=Price(1.00010, precision=5), time_in_force=TimeInForce.GTC, expire_time=None, init_id=uuid4(), timestamp_ns=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order def test_pack_and_unpack_stop_limit_orders_with_expire_time(self): # Arrange order = StopLimitOrder( ClientOrderId("O-123456"), StrategyId("S-001"), AUDUSD_SIM.id, OrderSide.BUY, Quantity(100000, precision=0), price=Price(1.00000, precision=5), trigger=Price(1.00010, precision=5), time_in_force=TimeInForce.GTD, expire_time=UNIX_EPOCH, init_id=uuid4(), timestamp_ns=0, ) # Act packed = OrderInitialized.to_dict(order.last_event) unpacked = self.unpacker.unpack(packed) # Assert assert unpacked == order
class TestPortfolio: def setup(self): # Fixture Setup self.clock = TestClock() self.logger = Logger(self.clock) self.trader_id = TestStubs.trader_id() self.order_factory = OrderFactory( trader_id=self.trader_id, strategy_id=StrategyId("S-001"), clock=TestClock(), ) self.msgbus = MessageBus( trader_id=self.trader_id, clock=self.clock, logger=self.logger, ) self.cache = TestStubs.cache() self.portfolio = Portfolio( msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) self.exec_engine = ExecutionEngine( msgbus=self.msgbus, cache=self.cache, clock=self.clock, logger=self.logger, ) # Prepare components self.cache.add_instrument(AUDUSD_SIM) self.cache.add_instrument(GBPUSD_SIM) self.cache.add_instrument(BTCUSDT_BINANCE) self.cache.add_instrument(BTCUSD_BITMEX) self.cache.add_instrument(ETHUSD_BITMEX) self.cache.add_instrument(BETTING_INSTRUMENT) def test_account_when_no_account_returns_none(self): # Arrange, Act, Assert assert self.portfolio.account(SIM) is None def test_account_when_account_returns_the_account_facade(self): # Arrange state = AccountState( account_id=AccountId("BINANCE", "1513111"), account_type=AccountType.CASH, base_currency=None, reported=True, balances=[ AccountBalance( BTC, Money(10.00000000, BTC), Money(0.00000000, BTC), Money(10.00000000, BTC), ) ], info={}, event_id=UUID4(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) # Act result = self.portfolio.account(BINANCE) # Assert assert result.id.issuer == "BINANCE" def test_balances_locked_when_no_account_for_venue_returns_none(self): # Arrange, Act, Assert assert self.portfolio.balances_locked(SIM) is None def test_margins_init_when_no_account_for_venue_returns_none(self): # Arrange, Act, Assert assert self.portfolio.margins_init(SIM) is None def test_margins_maint_when_no_account_for_venue_returns_none(self): # Arrange, Act, Assert assert self.portfolio.margins_maint(SIM) is None def test_unrealized_pnl_for_instrument_when_no_instrument_returns_none( self): # Arrange, Act, Assert assert self.portfolio.unrealized_pnl(USDJPY_SIM.id) is None def test_unrealized_pnl_for_venue_when_no_account_returns_empty_dict(self): # Arrange, Act, Assert assert self.portfolio.unrealized_pnls(SIM) == {} def test_net_position_when_no_positions_returns_zero(self): # Arrange, Act, Assert assert self.portfolio.net_position(AUDUSD_SIM.id) == Decimal(0) def test_net_exposures_when_no_positions_returns_none(self): # Arrange, Act, Assert assert self.portfolio.net_exposures(SIM) is None def test_is_net_long_when_no_positions_returns_false(self): # Arrange, Act, Assert assert self.portfolio.is_net_long(AUDUSD_SIM.id) is False def test_is_net_short_when_no_positions_returns_false(self): # Arrange, Act, Assert assert self.portfolio.is_net_short(AUDUSD_SIM.id) is False def test_is_flat_when_no_positions_returns_true(self): # Arrange, Act, Assert assert self.portfolio.is_flat(AUDUSD_SIM.id) is True def test_is_completely_flat_when_no_positions_returns_true(self): # Arrange, Act, Assert assert self.portfolio.is_flat(AUDUSD_SIM.id) is True def test_open_value_when_no_account_returns_none(self): # Arrange, Act, Assert assert self.portfolio.net_exposures(SIM) is None def test_update_tick(self): # Arrange tick = TestStubs.quote_tick_5decimal(GBPUSD_SIM.id) # Act self.portfolio.update_tick(tick) # Assert assert self.portfolio.unrealized_pnl(GBPUSD_SIM.id) is None def test_update_orders_working_cash_account(self): # Arrange AccountFactory.register_calculated_account("BINANCE") account_id = AccountId("BINANCE", "000") state = AccountState( account_id=account_id, 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( USDT, Money(100000.00000000, USDT), Money(0.00000000, USDT), Money(100000.00000000, USDT), ), ], info={}, event_id=UUID4(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) # Create two working orders order = self.order_factory.limit( BTCUSDT_BINANCE.id, OrderSide.BUY, Quantity.from_str("1.0"), Price.from_str("50000.00"), ) self.cache.add_order(order, position_id=None) # Act: push order state to ACCEPTED self.exec_engine.process( TestStubs.event_order_submitted(order, account_id=account_id)) self.exec_engine.process( TestStubs.event_order_accepted(order, account_id=account_id)) # Assert assert self.portfolio.balances_locked( BINANCE)[USDT].as_decimal() == 50100 def test_update_orders_working_margin_account(self): # Arrange AccountFactory.register_calculated_account("BINANCE") account_id = AccountId("BINANCE", "01234") state = AccountState( account_id=account_id, account_type=AccountType.MARGIN, 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), ), AccountBalance( USDT, Money(100000.00000000, USDT), Money(0.00000000, USDT), Money(100000.00000000, USDT), ), ], info={}, event_id=UUID4(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) # Create two working orders order1 = self.order_factory.stop_market( BTCUSDT_BINANCE.id, OrderSide.BUY, Quantity.from_str("10.5"), Price.from_str("25000.00"), ) order2 = self.order_factory.stop_market( BTCUSDT_BINANCE.id, OrderSide.BUY, Quantity.from_str("10.5"), Price.from_str("25000.00"), ) self.cache.add_order(order1, position_id=None) self.cache.add_order(order2, position_id=None) # Push states to ACCEPTED order1.apply(TestStubs.event_order_submitted(order1)) self.cache.update_order(order1) order1.apply(TestStubs.event_order_accepted(order1)) self.cache.update_order(order1) filled1 = TestStubs.event_order_filled( order1, instrument=BTCUSDT_BINANCE, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-1"), last_px=Price.from_str("25000.00"), ) self.exec_engine.process(filled1) # Update the last quote last = QuoteTick( instrument_id=BTCUSDT_BINANCE.id, bid=Price.from_str("25001.00"), ask=Price.from_str("25002.00"), bid_size=Quantity.from_int(1), ask_size=Quantity.from_int(1), ts_event=0, ts_init=0, ) # Act self.portfolio.update_tick(last) self.portfolio.initialize_orders() # Assert assert self.portfolio.margins_init(BINANCE) == {} def test_order_accept_updates_margin_init(self): # Arrange AccountFactory.register_calculated_account("BINANCE") state = AccountState( account_id=AccountId("BETFAIR", "01234"), account_type=AccountType.MARGIN, base_currency=GBP, reported=True, balances=[ AccountBalance( currency=GBP, total=Money(1000, GBP), free=Money(1000, GBP), locked=Money(0, GBP), ), ], info={}, event_id=UUID4(), ts_event=0, ts_init=0, ) AccountFactory.register_calculated_account("BETFAIR") self.portfolio.update_account(state) # Create a passive order order1 = self.order_factory.limit( BETTING_INSTRUMENT.id, OrderSide.BUY, Quantity.from_str("100"), Price.from_str("0.5"), ) self.cache.add_order(order1, position_id=None) # Push states to ACCEPTED order1.apply(TestStubs.event_order_submitted(order1)) self.cache.update_order(order1) order1.apply( TestStubs.event_order_accepted(order1, venue_order_id=VenueOrderId("1"))) self.cache.update_order(order1) # Act self.portfolio.initialize_orders() # Assert assert self.portfolio.margins_init(BETFAIR)[ BETTING_INSTRUMENT.id] == Money(200, GBP) def test_update_positions(self): # Arrange AccountFactory.register_calculated_account("BINANCE") account_id = AccountId("BINANCE", "01234") state = AccountState( account_id=account_id, 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(), ts_event=0, ts_init=0, ) self.portfolio.update_account(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.cache.add_order(order1, position_id=None) self.cache.add_order(order2, position_id=None) # Push states to ACCEPTED order1.apply(TestStubs.event_order_submitted(order1)) self.cache.update_order(order1) order1.apply(TestStubs.event_order_accepted(order1)) self.cache.update_order(order1) fill1 = TestStubs.event_order_filled( order1, instrument=BTCUSDT_BINANCE, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-1"), last_px=Price.from_str("25000.00"), ) fill2 = TestStubs.event_order_filled( order2, instrument=BTCUSDT_BINANCE, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-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, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-2"), last_px=Price.from_str("25000.00"), ) position2 = Position(instrument=BTCUSDT_BINANCE, fill=fill3) # Update the last quote last = QuoteTick( instrument_id=BTCUSDT_BINANCE.id, bid=Price.from_str("25001.00"), ask=Price.from_str("25002.00"), bid_size=Quantity.from_int(1), ask_size=Quantity.from_int(1), ts_event=0, ts_init=0, ) # Act self.cache.add_position(position1, OMSType.HEDGING) self.cache.add_position(position2, OMSType.HEDGING) self.portfolio.initialize_positions() self.portfolio.update_tick(last) # Assert assert self.portfolio.is_net_long(BTCUSDT_BINANCE.id) def test_opening_one_long_position_updates_portfolio(self): # Arrange AccountFactory.register_calculated_account("BINANCE") account_id = AccountId("BINANCE", "01234") state = AccountState( account_id=account_id, account_type=AccountType.MARGIN, 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), ), AccountBalance( USDT, Money(100000.00000000, USDT), Money(0.00000000, USDT), Money(100000.00000000, USDT), ), ], info={}, event_id=UUID4(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) order = self.order_factory.market( BTCUSDT_BINANCE.id, OrderSide.BUY, Quantity.from_str("10.000000"), ) fill = TestStubs.event_order_filled( order=order, instrument=BTCUSDT_BINANCE, strategy_id=StrategyId("S-001"), account_id=account_id, position_id=PositionId("P-123456"), last_px=Price.from_str("10500.00"), ) last = QuoteTick( instrument_id=BTCUSDT_BINANCE.id, bid=Price.from_str("10510.00"), ask=Price.from_str("10511.00"), bid_size=Quantity.from_str("1.000000"), ask_size=Quantity.from_str("1.000000"), ts_event=0, ts_init=0, ) self.cache.add_quote_tick(last) self.portfolio.update_tick(last) position = Position(instrument=BTCUSDT_BINANCE, fill=fill) # Act self.cache.add_position(position, OMSType.HEDGING) self.portfolio.update_position( TestStubs.event_position_opened(position)) # Assert assert self.portfolio.net_exposures(BINANCE) == { USDT: Money(105100.00000000, USDT) } assert self.portfolio.unrealized_pnls(BINANCE) == { USDT: Money(100.00000000, USDT) } assert self.portfolio.margins_maint(BINANCE) == { BTCUSDT_BINANCE.id: Money(105.00000000, USDT) } assert self.portfolio.net_exposure(BTCUSDT_BINANCE.id) == Money( 105100.00000000, USDT) assert self.portfolio.unrealized_pnl(BTCUSDT_BINANCE.id) == Money( 100.00000000, USDT) assert self.portfolio.net_position( order.instrument_id) == Decimal("10.00000000") assert self.portfolio.is_net_long(order.instrument_id) assert not self.portfolio.is_net_short(order.instrument_id) assert not self.portfolio.is_flat(order.instrument_id) assert not self.portfolio.is_completely_flat() def test_opening_one_short_position_updates_portfolio(self): # Arrange AccountFactory.register_calculated_account("BINANCE") account_id = AccountId("BINANCE", "01234") state = AccountState( account_id=account_id, account_type=AccountType.MARGIN, 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), ), AccountBalance( USDT, Money(100000.00000000, USDT), Money(0.00000000, USDT), Money(100000.00000000, USDT), ), ], info={}, event_id=UUID4(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) order = self.order_factory.market( BTCUSDT_BINANCE.id, OrderSide.SELL, Quantity.from_str("0.515"), ) fill = TestStubs.event_order_filled( order=order, instrument=BTCUSDT_BINANCE, strategy_id=StrategyId("S-001"), account_id=account_id, position_id=PositionId("P-123456"), last_px=Price.from_str("15000.00"), ) last = QuoteTick( instrument_id=BTCUSDT_BINANCE.id, bid=Price.from_str("15510.15"), ask=Price.from_str("15510.25"), bid_size=Quantity.from_str("12.62"), ask_size=Quantity.from_str("3.1"), ts_event=0, ts_init=0, ) self.cache.add_quote_tick(last) self.portfolio.update_tick(last) position = Position(instrument=BTCUSDT_BINANCE, fill=fill) # Act self.cache.add_position(position, OMSType.HEDGING) self.portfolio.update_position( TestStubs.event_position_opened(position)) # Assert assert self.portfolio.net_exposures(BINANCE) == { USDT: Money(7987.77875000, USDT) } assert self.portfolio.unrealized_pnls(BINANCE) == { USDT: Money(-262.77875000, USDT) } assert self.portfolio.margins_maint(BINANCE) == { BTCUSDT_BINANCE.id: Money(7.72500000, USDT) } assert self.portfolio.net_exposure(BTCUSDT_BINANCE.id) == Money( 7987.77875000, USDT) assert self.portfolio.unrealized_pnl(BTCUSDT_BINANCE.id) == Money( -262.77875000, USDT) assert self.portfolio.net_position( order.instrument_id) == Decimal("-0.515") assert not self.portfolio.is_net_long(order.instrument_id) assert self.portfolio.is_net_short(order.instrument_id) assert not self.portfolio.is_flat(order.instrument_id) assert not self.portfolio.is_completely_flat() def test_opening_positions_with_multi_asset_account(self): # Arrange AccountFactory.register_calculated_account("BITMEX") account_id = AccountId("BITMEX", "01234") state = AccountState( account_id=account_id, account_type=AccountType.MARGIN, 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(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) last_ethusd = QuoteTick( instrument_id=ETHUSD_BITMEX.id, bid=Price.from_str("376.05"), ask=Price.from_str("377.10"), bid_size=Quantity.from_str("16"), ask_size=Quantity.from_str("25"), ts_event=0, ts_init=0, ) last_btcusd = QuoteTick( instrument_id=BTCUSD_BITMEX.id, bid=Price.from_str("10500.05"), ask=Price.from_str("10501.51"), bid_size=Quantity.from_str("2.54"), ask_size=Quantity.from_str("0.91"), ts_event=0, ts_init=0, ) self.cache.add_quote_tick(last_ethusd) self.cache.add_quote_tick(last_btcusd) self.portfolio.update_tick(last_ethusd) self.portfolio.update_tick(last_btcusd) order = self.order_factory.market( ETHUSD_BITMEX.id, OrderSide.BUY, Quantity.from_int(10000), ) fill = TestStubs.event_order_filled( order=order, instrument=ETHUSD_BITMEX, strategy_id=StrategyId("S-001"), account_id=account_id, position_id=PositionId("P-123456"), last_px=Price.from_str("376.05"), ) position = Position(instrument=ETHUSD_BITMEX, fill=fill) # Act self.cache.add_position(position, OMSType.HEDGING) self.portfolio.update_position( TestStubs.event_position_opened(position)) # Assert assert self.portfolio.net_exposures(BITMEX) == { ETH: Money(26.59220848, ETH) } assert self.portfolio.margins_maint(BITMEX) == { ETHUSD_BITMEX.id: Money(0.20608962, ETH) } assert self.portfolio.net_exposure(ETHUSD_BITMEX.id) == Money( 26.59220848, ETH) assert self.portfolio.unrealized_pnl(ETHUSD_BITMEX.id) == Money( 0.00000000, ETH) def test_unrealized_pnl_when_insufficient_data_for_xrate_returns_none( self): # Arrange AccountFactory.register_calculated_account("BITMEX") 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(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) order = self.order_factory.market( ETHUSD_BITMEX.id, OrderSide.BUY, Quantity.from_int(100), ) self.cache.add_order(order, position_id=None) 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, strategy_id=StrategyId("S-1"), position_id=PositionId("P-123456"), 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 assert result == {} def test_market_value_when_insufficient_data_for_xrate_returns_none(self): # Arrange AccountFactory.register_calculated_account("BITMEX") account_id = AccountId("BITMEX", "01234") state = AccountState( account_id=account_id, account_type=AccountType.MARGIN, base_currency=BTC, reported=True, balances=[ AccountBalance( BTC, Money(10.00000000, BTC), Money(0.00000000, BTC), Money(10.00000000, BTC), ), ], info={}, event_id=UUID4(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) order = self.order_factory.market( ETHUSD_BITMEX.id, OrderSide.BUY, Quantity.from_int(100), ) fill = TestStubs.event_order_filled( order=order, instrument=ETHUSD_BITMEX, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-123456"), last_px=Price.from_str("376.05"), ) last_ethusd = QuoteTick( instrument_id=ETHUSD_BITMEX.id, bid=Price.from_str("376.05"), ask=Price.from_str("377.10"), bid_size=Quantity.from_str("16"), ask_size=Quantity.from_str("25"), ts_event=0, ts_init=0, ) last_xbtusd = QuoteTick( instrument_id=BTCUSD_BITMEX.id, bid=Price.from_str("50000.00"), ask=Price.from_str("50000.00"), bid_size=Quantity.from_str("1"), ask_size=Quantity.from_str("1"), ts_event=0, ts_init=0, ) position = Position(instrument=ETHUSD_BITMEX, fill=fill) self.portfolio.update_position( TestStubs.event_position_opened(position)) self.cache.add_position(position, OMSType.HEDGING) self.cache.add_quote_tick(last_ethusd) self.cache.add_quote_tick(last_xbtusd) self.portfolio.update_tick(last_ethusd) self.portfolio.update_tick(last_xbtusd) # Act result = self.portfolio.net_exposures(BITMEX) # Assert assert result == {BTC: Money(0.00200000, BTC)} def test_opening_several_positions_updates_portfolio(self): # Arrange AccountFactory.register_calculated_account("SIM") account_id = AccountId("SIM", "01234") state = AccountState( account_id=account_id, 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(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) last_audusd = QuoteTick( instrument_id=AUDUSD_SIM.id, bid=Price.from_str("0.80501"), ask=Price.from_str("0.80505"), bid_size=Quantity.from_int(1), ask_size=Quantity.from_int(1), ts_event=0, ts_init=0, ) last_gbpusd = QuoteTick( instrument_id=GBPUSD_SIM.id, bid=Price.from_str("1.30315"), ask=Price.from_str("1.30317"), bid_size=Quantity.from_int(1), ask_size=Quantity.from_int(1), ts_event=0, ts_init=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.cache.add_order(order1, position_id=None) self.cache.add_order(order2, position_id=None) fill1 = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-1"), last_px=Price.from_str("1.00000"), ) fill2 = TestStubs.event_order_filled( order2, instrument=GBPUSD_SIM, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-2"), last_px=Price.from_str("1.00000"), ) self.cache.update_order(order1) self.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, OMSType.HEDGING) self.cache.add_position(position2, OMSType.HEDGING) self.portfolio.update_position(position_opened1) self.portfolio.update_position(position_opened2) # Assert assert self.portfolio.net_exposures(SIM) == { USD: Money(210816.00, USD) } assert self.portfolio.unrealized_pnls(SIM) == { USD: Money(10816.00, USD) } assert self.portfolio.margins_maint(SIM) == { AUDUSD_SIM.id: Money(3002.00, USD), GBPUSD_SIM.id: Money(3002.00, USD), } assert self.portfolio.net_exposure(AUDUSD_SIM.id) == Money( 80501.00, USD) assert self.portfolio.net_exposure(GBPUSD_SIM.id) == Money( 130315.00, USD) assert self.portfolio.unrealized_pnl(AUDUSD_SIM.id) == Money( -19499.00, USD) assert self.portfolio.unrealized_pnl(GBPUSD_SIM.id) == Money( 30315.00, USD) assert self.portfolio.net_position(AUDUSD_SIM.id) == Decimal(100000) assert self.portfolio.net_position(GBPUSD_SIM.id) == Decimal(100000) assert self.portfolio.is_net_long(AUDUSD_SIM.id) assert not self.portfolio.is_net_short(AUDUSD_SIM.id) assert not self.portfolio.is_flat(AUDUSD_SIM.id) assert not self.portfolio.is_completely_flat() def test_modifying_position_updates_portfolio(self): # Arrange AccountFactory.register_calculated_account("SIM") account_id = AccountId("SIM", "01234") state = AccountState( account_id=account_id, 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(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) last_audusd = QuoteTick( instrument_id=AUDUSD_SIM.id, bid=Price.from_str("0.80501"), ask=Price.from_str("0.80505"), bid_size=Quantity.from_int(1), ask_size=Quantity.from_int(1), ts_event=0, ts_init=0, ) self.cache.add_quote_tick(last_audusd) self.portfolio.update_tick(last_audusd) order1 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) fill1 = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-123456"), last_px=Price.from_str("1.00000"), ) position = Position(instrument=AUDUSD_SIM, fill=fill1) self.cache.add_position(position, OMSType.HEDGING) self.portfolio.update_position( TestStubs.event_position_opened(position)) order2 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(50000), ) order2_filled = TestStubs.event_order_filled( order2, instrument=AUDUSD_SIM, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-123456"), last_px=Price.from_str("1.00000"), ) position.apply(order2_filled) # Act self.portfolio.update_position( TestStubs.event_position_changed(position)) # Assert assert self.portfolio.net_exposures(SIM) == {USD: Money(40250.50, USD)} assert self.portfolio.unrealized_pnls(SIM) == { USD: Money(-9749.50, USD) } assert self.portfolio.margins_maint(SIM) == { AUDUSD_SIM.id: Money(1501.00, USD) } assert self.portfolio.net_exposure(AUDUSD_SIM.id) == Money( 40250.50, USD) assert self.portfolio.unrealized_pnl(AUDUSD_SIM.id) == Money( -9749.50, USD) assert self.portfolio.net_position(AUDUSD_SIM.id) == Decimal(50000) assert self.portfolio.is_net_long(AUDUSD_SIM.id) assert not self.portfolio.is_net_short(AUDUSD_SIM.id) assert not self.portfolio.is_flat(AUDUSD_SIM.id) assert not self.portfolio.is_completely_flat() assert self.portfolio.unrealized_pnls(BINANCE) == {} assert self.portfolio.net_exposures(BINANCE) is None def test_closing_position_updates_portfolio(self): # Arrange AccountFactory.register_calculated_account("SIM") account_id = AccountId("SIM", "01234") state = AccountState( account_id=account_id, 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(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) order1 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) fill1 = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-123456"), last_px=Price.from_str("1.00000"), ) position = Position(instrument=AUDUSD_SIM, fill=fill1) self.cache.add_position(position, OMSType.HEDGING) self.portfolio.update_position( TestStubs.event_position_opened(position)) order2 = self.order_factory.market( AUDUSD_SIM.id, OrderSide.SELL, Quantity.from_int(100000), ) order2_filled = TestStubs.event_order_filled( order2, instrument=AUDUSD_SIM, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-123456"), last_px=Price.from_str("1.00010"), ) position.apply(order2_filled) self.cache.update_position(position) # Act self.portfolio.update_position( TestStubs.event_position_closed(position)) # Assert assert self.portfolio.net_exposures(SIM) == {} assert self.portfolio.unrealized_pnls(SIM) == {} assert self.portfolio.margins_maint(SIM) == {} assert self.portfolio.net_exposure(AUDUSD_SIM.id) == Money(0, USD) assert self.portfolio.unrealized_pnl(AUDUSD_SIM.id) == Money(0, USD) assert self.portfolio.net_position(AUDUSD_SIM.id) == Decimal(0) assert not self.portfolio.is_net_long(AUDUSD_SIM.id) assert not self.portfolio.is_net_short(AUDUSD_SIM.id) assert self.portfolio.is_flat(AUDUSD_SIM.id) assert self.portfolio.is_completely_flat() def test_several_positions_with_different_instruments_updates_portfolio( self): # Arrange account_id = AccountId("SIM", "01234") state = AccountState( account_id=account_id, 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(), ts_event=0, ts_init=0, ) self.portfolio.update_account(state) 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( GBPUSD_SIM.id, OrderSide.BUY, Quantity.from_int(100000), ) order4 = self.order_factory.market( GBPUSD_SIM.id, OrderSide.SELL, Quantity.from_int(100000), ) fill1 = TestStubs.event_order_filled( order1, instrument=AUDUSD_SIM, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-1"), last_px=Price.from_str("1.00000"), ) fill2 = TestStubs.event_order_filled( order2, instrument=AUDUSD_SIM, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-2"), last_px=Price.from_str("1.00000"), ) fill3 = TestStubs.event_order_filled( order3, instrument=GBPUSD_SIM, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-3"), last_px=Price.from_str("1.00000"), ) fill4 = TestStubs.event_order_filled( order4, instrument=GBPUSD_SIM, strategy_id=StrategyId("S-1"), account_id=account_id, position_id=PositionId("P-3"), last_px=Price.from_str("1.00100"), ) position1 = Position(instrument=AUDUSD_SIM, fill=fill1) position2 = Position(instrument=AUDUSD_SIM, fill=fill2) position3 = Position(instrument=GBPUSD_SIM, fill=fill3) last_audusd = QuoteTick( instrument_id=AUDUSD_SIM.id, bid=Price.from_str("0.80501"), ask=Price.from_str("0.80505"), bid_size=Quantity.from_int(1), ask_size=Quantity.from_int(1), ts_event=0, ts_init=0, ) last_gbpusd = QuoteTick( instrument_id=GBPUSD_SIM.id, bid=Price.from_str("1.30315"), ask=Price.from_str("1.30317"), bid_size=Quantity.from_int(1), ask_size=Quantity.from_int(1), ts_event=0, ts_init=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) self.cache.add_position(position1, OMSType.HEDGING) self.cache.add_position(position2, OMSType.HEDGING) self.cache.add_position(position3, OMSType.HEDGING) # Act self.portfolio.update_position( TestStubs.event_position_opened(position1)) self.portfolio.update_position( TestStubs.event_position_opened(position2)) self.portfolio.update_position( TestStubs.event_position_opened(position3)) position3.apply(fill4) self.cache.update_position(position3) self.portfolio.update_position( TestStubs.event_position_closed(position3)) # Assert assert { USD: Money(-38998.00, USD) } == self.portfolio.unrealized_pnls(SIM) assert { USD: Money(161002.00, USD) } == self.portfolio.net_exposures(SIM) assert Money(161002.00, USD) == self.portfolio.net_exposure(AUDUSD_SIM.id) assert Money(-38998.00, USD) == self.portfolio.unrealized_pnl(AUDUSD_SIM.id) assert self.portfolio.unrealized_pnl(GBPUSD_SIM.id) == Money(0, USD) assert self.portfolio.net_position(AUDUSD_SIM.id) == Decimal(200000) assert self.portfolio.net_position(GBPUSD_SIM.id) == Decimal(0) assert self.portfolio.is_net_long(AUDUSD_SIM.id) assert self.portfolio.is_flat(GBPUSD_SIM.id) assert not self.portfolio.is_completely_flat()
class OrderTests(unittest.TestCase): def setUp(self): # Fixture Setup self.account_id = TestStubs.account_id() self.order_factory = OrderFactory( trader_id=TraderId("TESTER", "000"), strategy_id=StrategyId("S", "001"), clock=TestClock(), ) def test_opposite_side_given_undefined_raises_value_error(self): # Arrange # Act # Assert self.assertRaises(ValueError, Order.opposite_side, OrderSide.UNDEFINED) def test_flatten_side_given_undefined_or_flat_raises_value_error(self): # Arrange # Act # Assert self.assertRaises(ValueError, Order.flatten_side, PositionSide.UNDEFINED) self.assertRaises(ValueError, Order.flatten_side, PositionSide.FLAT) @parameterized.expand([ [OrderSide.BUY, OrderSide.SELL], [OrderSide.SELL, OrderSide.BUY], ]) def test_opposite_side_returns_expected_sides(self, side, expected): # Arrange # Act result = Order.opposite_side(side) # Assert self.assertEqual(expected, result) @parameterized.expand([ [PositionSide.LONG, OrderSide.SELL], [PositionSide.SHORT, OrderSide.BUY], ]) def test_flatten_side_returns_expected_sides(self, side, expected): # Arrange # Act result = Order.flatten_side(side) # Assert self.assertEqual(expected, result) def test_market_order_with_quantity_zero_raises_exception(self): # Arrange # Act self.assertRaises( ValueError, MarketOrder, ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(), TimeInForce.DAY, uuid4(), UNIX_EPOCH, ) def test_market_order_with_invalid_tif_raises_exception(self): # Arrange # Act self.assertRaises( ValueError, MarketOrder, ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100), TimeInForce.GTD, uuid4(), UNIX_EPOCH, ) def test_stop_order_with_gtd_and_expire_time_none_raises_exception(self): # Arrange # Act self.assertRaises( TypeError, StopMarketOrder, ClientOrderId("O-123456"), StrategyId("S", "001"), AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), price=Price("1.00000"), init_id=uuid4(), timestamp=UNIX_EPOCH, time_in_force=TimeInForce.GTD, expire_time=None, ) def test_reset_order_factory(self): # Arrange self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) # Act self.order_factory.reset() order2 = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) self.assertEqual(ClientOrderId("O-19700101-000000-000-001-1"), order2.cl_ord_id) def test_limit_order_can_create_expected_decimal_price(self): # Arrange # Act order1 = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) order2 = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) order3 = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) order4 = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00001"), ) # Assert self.assertEqual(Price("1.00000"), order1.price) self.assertEqual(Price("1.00000"), order2.price) self.assertEqual(Price("1.00000"), order3.price) self.assertEqual(Price("1.00001"), order4.price) def test_initialize_buy_market_order(self): # Arrange # Act order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) # Assert self.assertEqual(OrderType.MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(1, order.event_count) self.assertTrue(isinstance(order.last_event, OrderInitialized)) self.assertFalse(order.is_working) self.assertFalse(order.is_completed) self.assertTrue(order.is_buy) self.assertFalse(order.is_sell) self.assertFalse(order.is_passive) self.assertTrue(order.is_aggressive) self.assertEqual(None, order.filled_timestamp) self.assertEqual(UNIX_EPOCH, order.last_event.timestamp) self.assertEqual(OrderInitialized, type(order.init_event)) self.assertTrue(order == order) self.assertFalse(order != order) def test_initialize_sell_market_order(self): # Arrange # Act order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.SELL, Quantity(100000), ) # Assert self.assertEqual(OrderType.MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(1, order.event_count) self.assertTrue(isinstance(order.last_event, OrderInitialized)) self.assertEqual(1, len(order.events)) self.assertTrue(order.is_active) self.assertFalse(order.is_working) self.assertFalse(order.is_completed) self.assertFalse(order.is_buy) self.assertTrue(order.is_sell) self.assertEqual(None, order.filled_timestamp) self.assertEqual(OrderInitialized, type(order.init_event)) def test_order_equality(self): # Arrange # Act order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) # Assert self.assertTrue(order == order) self.assertFalse(order != order) def test_order_str_and_repr(self): # Arrange # Act order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) # Assert self.assertEqual("MarketOrder(cl_ord_id=O-19700101-000000-000-001-1, id=NULL, state=INITIALIZED, BUY 100,000 AUD/USD.SIM MARKET GTC)", str(order)) # noqa self.assertEqual("MarketOrder(cl_ord_id=O-19700101-000000-000-001-1, id=NULL, state=INITIALIZED, BUY 100,000 AUD/USD.SIM MARKET GTC)", repr(order)) # noqa def test_initialize_limit_order(self): # Arrange # Act order = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) # Assert self.assertEqual(OrderType.LIMIT, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(TimeInForce.GTC, order.time_in_force) self.assertTrue(order.is_passive) self.assertTrue(order.is_active) self.assertFalse(order.is_aggressive) self.assertFalse(order.is_completed) self.assertEqual(OrderInitialized, type(order.init_event)) def test_initialize_limit_order_with_expire_time(self): # Arrange # Act order = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), TimeInForce.GTD, UNIX_EPOCH, ) # Assert self.assertEqual(AUDUSD_SIM.symbol, order.symbol) self.assertEqual(OrderType.LIMIT, order.type) self.assertEqual(Price("1.00000"), order.price) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(TimeInForce.GTD, order.time_in_force) self.assertEqual(UNIX_EPOCH, order.expire_time) self.assertFalse(order.is_completed) self.assertEqual(OrderInitialized, type(order.init_event)) def test_initialize_stop_order(self): # Arrange # Act order = self.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) # Assert self.assertEqual(OrderType.STOP_MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(TimeInForce.GTC, order.time_in_force) self.assertTrue(order.is_passive) self.assertFalse(order.is_aggressive) self.assertFalse(order.is_completed) self.assertEqual(OrderInitialized, type(order.init_event)) def test_bracket_order_equality(self): # Arrange entry1 = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) entry2 = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) bracket_order1 = self.order_factory.bracket(entry1, Price("1.00000")) bracket_order2 = self.order_factory.bracket(entry2, Price("1.00000")) # Act # Assert self.assertTrue(bracket_order1 == bracket_order1) self.assertTrue(bracket_order1 != bracket_order2) def test_initialize_bracket_order_market_with_no_take_profit(self): # Arrange entry_order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) # Act bracket_order = self.order_factory.bracket(entry_order, Price("0.99990")) # Assert self.assertEqual(AUDUSD_SIM.symbol, bracket_order.stop_loss.symbol) self.assertFalse(bracket_order.take_profit is not None) self.assertEqual(ClientOrderId("O-19700101-000000-000-001-1"), bracket_order.entry.cl_ord_id) self.assertEqual(ClientOrderId("O-19700101-000000-000-001-2"), bracket_order.stop_loss.cl_ord_id) self.assertEqual(OrderSide.SELL, bracket_order.stop_loss.side) self.assertEqual(Quantity(100000), bracket_order.entry.quantity) self.assertEqual(Quantity(100000), bracket_order.stop_loss.quantity) self.assertEqual(Price("0.99990"), bracket_order.stop_loss.price) self.assertEqual(TimeInForce.GTC, bracket_order.stop_loss.time_in_force) self.assertEqual(None, bracket_order.stop_loss.expire_time) self.assertEqual(BracketOrderId("BO-19700101-000000-000-001-1"), bracket_order.id) self.assertEqual(UNIX_EPOCH, bracket_order.timestamp) def test_initialize_bracket_order_stop_with_take_profit(self): # Arrange entry_order = self.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("0.99995"), ) # Act bracket_order = self.order_factory.bracket( entry_order, Price("0.99990"), Price("1.00010"), ) # Assert self.assertEqual(AUDUSD_SIM.symbol, bracket_order.stop_loss.symbol) self.assertTrue(bracket_order.take_profit is not None) self.assertEqual(AUDUSD_SIM.symbol, bracket_order.take_profit.symbol) self.assertEqual(ClientOrderId("O-19700101-000000-000-001-1"), bracket_order.entry.cl_ord_id) self.assertEqual(ClientOrderId("O-19700101-000000-000-001-2"), bracket_order.stop_loss.cl_ord_id) self.assertEqual(ClientOrderId("O-19700101-000000-000-001-3"), bracket_order.take_profit.cl_ord_id) self.assertEqual(OrderSide.SELL, bracket_order.stop_loss.side) self.assertEqual(OrderSide.SELL, bracket_order.take_profit.side) self.assertEqual(Quantity(100000), bracket_order.stop_loss.quantity) self.assertEqual(Quantity(100000), bracket_order.take_profit.quantity) self.assertEqual(Price("0.99990"), bracket_order.stop_loss.price) self.assertEqual(Price("1.00010"), bracket_order.take_profit.price) self.assertEqual(TimeInForce.GTC, bracket_order.stop_loss.time_in_force) self.assertEqual(TimeInForce.GTC, bracket_order.take_profit.time_in_force) self.assertEqual(None, bracket_order.entry.expire_time) self.assertEqual(None, bracket_order.stop_loss.expire_time) self.assertEqual(None, bracket_order.take_profit.expire_time) self.assertEqual(BracketOrderId("BO-19700101-000000-000-001-1"), bracket_order.id) self.assertEqual(UNIX_EPOCH, bracket_order.timestamp) def test_bracket_order_str_and_repr(self): # Arrange # Act entry_order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) bracket_order = self.order_factory.bracket( entry_order, Price("0.99990"), Price("1.00010"), ) # Assert self.assertEqual("BracketOrder(id=BO-19700101-000000-000-001-1, EntryMarketOrder(cl_ord_id=O-19700101-000000-000-001-1, id=NULL, state=INITIALIZED, BUY 100,000 AUD/USD.SIM MARKET GTC), SL=0.99990, TP=1.00010)", str(bracket_order)) # noqa self.assertEqual("BracketOrder(id=BO-19700101-000000-000-001-1, EntryMarketOrder(cl_ord_id=O-19700101-000000-000-001-1, id=NULL, state=INITIALIZED, BUY 100,000 AUD/USD.SIM MARKET GTC), SL=0.99990, TP=1.00010)", repr(bracket_order)) # noqa def test_apply_order_invalid_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) invalid = OrderInvalid( order.cl_ord_id, "SOME_REASON", uuid4(), UNIX_EPOCH, ) # Act order.apply(invalid) # Assert self.assertEqual(OrderState.INVALID, order.state) self.assertEqual(2, order.event_count) self.assertEqual(invalid, order.last_event) self.assertFalse(order.is_active) self.assertTrue(order.is_completed) def test_apply_order_denied_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) denied = OrderDenied( order.cl_ord_id, "SOME_REASON", uuid4(), UNIX_EPOCH, ) # Act order.apply(denied) # Assert self.assertEqual(OrderState.DENIED, order.state) self.assertEqual(2, order.event_count) self.assertEqual(denied, order.last_event) self.assertFalse(order.is_active) self.assertTrue(order.is_completed) def test_apply_order_submitted_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) submitted = TestStubs.event_order_submitted(order) # Act order.apply(submitted) # Assert self.assertEqual(OrderState.SUBMITTED, order.state) self.assertEqual(2, order.event_count) self.assertEqual(submitted, order.last_event) self.assertTrue(order.is_active) self.assertFalse(order.is_working) self.assertFalse(order.is_completed) def test_apply_order_accepted_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) order.apply(TestStubs.event_order_submitted(order)) # Act order.apply(TestStubs.event_order_accepted(order)) # Assert self.assertEqual(OrderState.ACCEPTED, order.state) self.assertTrue(order.is_active) self.assertTrue(order.is_working) self.assertFalse(order.is_completed) def test_apply_order_rejected_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) order.apply(TestStubs.event_order_submitted(order)) # Act order.apply(TestStubs.event_order_rejected(order)) # Assert self.assertEqual(OrderState.REJECTED, order.state) self.assertFalse(order.is_active) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) def test_apply_order_expired_event(self): # Arrange order = self.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("0.99990"), TimeInForce.GTD, UNIX_EPOCH, ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) # Act order.apply(TestStubs.event_order_expired(order)) # Assert self.assertEqual(OrderState.EXPIRED, order.state) self.assertFalse(order.is_active) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) def test_apply_order_cancelled_event(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) # Act order.apply(TestStubs.event_order_cancelled(order)) # Assert self.assertEqual(OrderState.CANCELLED, order.state) self.assertFalse(order.is_active) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) def test_apply_order_amended_event_to_stop_order(self): # Arrange order = self.order_factory.stop_market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) amended = OrderAmended( self.account_id, order.cl_ord_id, OrderId("1"), Quantity(120000), Price("1.00001"), UNIX_EPOCH, uuid4(), UNIX_EPOCH, ) # Act order.apply(amended) # Assert self.assertEqual(OrderState.ACCEPTED, order.state) self.assertEqual(OrderId("1"), order.id) self.assertEqual(Quantity(120000), order.quantity) self.assertEqual(Price("1.00001"), order.price) self.assertTrue(order.is_active) self.assertTrue(order.is_working) self.assertFalse(order.is_completed) self.assertEqual(4, order.event_count) def test_apply_order_filled_event_to_order_without_accepted(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(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"), fill_price=Price("1.00001"), ) # Act order.apply(filled) # Assert self.assertEqual(OrderState.FILLED, order.state) self.assertEqual(Quantity(100000), order.filled_qty) self.assertEqual(Decimal("1.00001"), order.avg_price) self.assertEqual(1, len(order.execution_ids)) self.assertFalse(order.is_active) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp) def test_apply_order_filled_event_to_market_order(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(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"), fill_price=Price("1.00001"), ) # Act order.apply(filled) # Assert self.assertEqual(OrderState.FILLED, order.state) self.assertEqual(Quantity(100000), order.filled_qty) self.assertEqual(Decimal("1.00001"), order.avg_price) self.assertEqual(1, len(order.execution_ids)) self.assertFalse(order.is_active) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp) def test_apply_partial_fill_events_to_market_order_results_in_partially_filled(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) fill1 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S", "001"), fill_price=Price("1.00001"), fill_qty=Quantity(20000), ) fill2 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S", "001"), fill_price=Price("1.00002"), fill_qty=Quantity(40000), ) # Act order.apply(fill1) order.apply(fill2) # Assert self.assertEqual(OrderState.PARTIALLY_FILLED, order.state) self.assertEqual(Quantity(60000), order.filled_qty) self.assertEqual(Decimal("1.000014"), order.avg_price) self.assertEqual(2, len(order.execution_ids)) self.assertTrue(order.is_active) self.assertTrue(order.is_working) self.assertFalse(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp) def test_apply_filled_events_to_market_order_results_in_filled(self): # Arrange order = self.order_factory.market( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) fill1 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S", "001"), fill_price=Price("1.00001"), fill_qty=Quantity(20000), ) fill2 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S", "001"), fill_price=Price("1.00002"), fill_qty=Quantity(40000), ) fill3 = TestStubs.event_order_filled( order, instrument=AUDUSD_SIM, position_id=PositionId("P-123456"), strategy_id=StrategyId("S", "001"), fill_price=Price("1.00003"), fill_qty=Quantity(40000), ) # Act order.apply(fill1) order.apply(fill2) order.apply(fill3) # Assert self.assertEqual(OrderState.FILLED, order.state) self.assertEqual(Quantity(100000), order.filled_qty) self.assertEqual(Decimal("1.000018571428571428571428571"), order.avg_price) self.assertEqual(3, len(order.execution_ids)) self.assertFalse(order.is_active) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp) def test_apply_order_filled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) filled = OrderFilled( self.account_id, order.cl_ord_id, OrderId("1"), ExecutionId("E-1"), PositionId("P-1"), StrategyId.null(), order.symbol, order.side, order.quantity, order.quantity, Quantity(), Price("1.00001"), AUDUSD_SIM.quote_currency, AUDUSD_SIM.is_inverse, Money(0, USD), LiquiditySide.MAKER, UNIX_EPOCH, uuid4(), UNIX_EPOCH, ) # Act order.apply(filled) # Assert self.assertEqual(OrderState.FILLED, order.state) self.assertEqual(Quantity(100000), order.filled_qty) self.assertEqual(Price("1.00000"), order.price) self.assertEqual(Decimal("1.00001"), order.avg_price) self.assertEqual(Decimal("0.00001"), order.slippage) self.assertFalse(order.is_active) self.assertFalse(order.is_working) self.assertTrue(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp) def test_apply_order_partially_filled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit( AUDUSD_SIM.symbol, OrderSide.BUY, Quantity(100000), Price("1.00000"), ) order.apply(TestStubs.event_order_submitted(order)) order.apply(TestStubs.event_order_accepted(order)) partially = OrderFilled( self.account_id, order.cl_ord_id, OrderId("1"), ExecutionId("E-1"), PositionId("P-1"), StrategyId.null(), order.symbol, order.side, Quantity(50000), Quantity(50000), Quantity(50000), Price("0.999999"), AUDUSD_SIM.quote_currency, AUDUSD_SIM.is_inverse, Money(0, USD), LiquiditySide.MAKER, UNIX_EPOCH, uuid4(), UNIX_EPOCH, ) # Act order.apply(partially) # Assert self.assertEqual(OrderState.PARTIALLY_FILLED, order.state) self.assertEqual(Quantity(50000), order.filled_qty) self.assertEqual(Price("1.00000"), order.price) self.assertEqual(Decimal("0.999999"), order.avg_price) self.assertEqual(Decimal("-0.000001"), order.slippage) self.assertTrue(order.is_active) self.assertTrue(order.is_working) self.assertFalse(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp)
class OrderTests(unittest.TestCase): def setUp(self): # Fixture Setup self.account_id = TestStubs.account_id() self.order_factory = OrderFactory(id_tag_trader=IdTag('001'), id_tag_strategy=IdTag('001'), clock=TestClock(), guid_factory=TestGuidFactory()) def test_market_order_with_quantity_zero_raises_exception(self): # Arrange # Act self.assertRaises(ValueError, Order, OrderId('O-123456'), AUDUSD_FXCM, OrderSide.BUY, OrderType.MARKET, Quantity(), GUID(uuid.uuid4()), UNIX_EPOCH) def test_priced_order_with_GTD_time_in_force_and_expire_time_none_raises_exception( self): # Arrange # Act self.assertRaises(ValueError, Order, OrderId('O-123456'), AUDUSD_FXCM, OrderSide.BUY, OrderType.LIMIT, Quantity(100000), GUID(uuid.uuid4()), UNIX_EPOCH, price=Price(1.00000, 5), time_in_force=TimeInForce.GTD, expire_time=None) def test_market_order_with_price_input_raises_exception(self): # Arrange # Act self.assertRaises(ValueError, Order, OrderId('O-123456'), AUDUSD_FXCM, OrderSide.BUY, OrderType.MARKET, Quantity(100000), GUID(uuid.uuid4()), UNIX_EPOCH, price=Price(1.00000, 5)) def test_stop_order_with_no_price_input_raises_exception(self): # Arrange # Act self.assertRaises(ValueError, Order, OrderId('O-123456'), AUDUSD_FXCM, OrderSide.BUY, OrderType.STOP, Quantity(100000), GUID(uuid.uuid4()), UNIX_EPOCH) def test_stop_order_with_zero_price_input_raises_exception(self): # Arrange # Act self.assertRaises(ValueError, Order, OrderId('O-123456'), AUDUSD_FXCM, OrderSide.BUY, OrderType.STOP, Quantity(100000), GUID(uuid.uuid4()), UNIX_EPOCH, price=None) def test_can_reset_order_factory(self): # Arrange self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) # Act self.order_factory.reset() order2 = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) self.assertEqual(OrderId('O-19700101-000000-001-001-1'), order2.id) def test_limit_order_can_create_expected_decimal_price(self): # Arrange # Act order1 = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) order2 = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) order3 = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) order4 = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00001, 5)) # Assert self.assertEqual(Price(1.00000, 5), order1.price) self.assertEqual(Price(1.00000, 5), order2.price) self.assertEqual(Price(1.00000, 5), order3.price) self.assertEqual(Price(1.00001, 5), order4.price) def test_can_initialize_buy_market_order(self): # Arrange # Act order = self.order_factory.market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), ) # Assert self.assertEqual(OrderType.MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(1, order.event_count) self.assertTrue(isinstance(order.last_event, OrderInitialized)) self.assertFalse(order.is_working) self.assertFalse(order.is_completed) self.assertTrue(order.is_buy) self.assertFalse(order.is_sell) self.assertEqual(None, order.filled_timestamp) def test_can_initialize_sell_market_order(self): # Arrange # Act order = self.order_factory.market( AUDUSD_FXCM, OrderSide.SELL, Quantity(100000), ) # Assert self.assertEqual(OrderType.MARKET, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(1, order.event_count) self.assertTrue(isinstance(order.last_event, OrderInitialized)) self.assertFalse(order.is_working) self.assertFalse(order.is_completed) self.assertFalse(order.is_buy) self.assertTrue(order.is_sell) self.assertEqual(None, order.filled_timestamp) def test_order_str_and_repr(self): # Arrange # Act order = self.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) # Assert self.assertEqual( 'Order(id=O-19700101-000000-001-001-1, state=INITIALIZED, BUY 100K AUDUSD.FXCM MARKET DAY)', str(order)) self.assertTrue( repr(order).startswith( '<Order(id=O-19700101-000000-001-001-1, state=INITIALIZED, BUY 100K AUDUSD.FXCM MARKET DAY) object at' )) def test_can_initialize_limit_order(self): # Arrange # Act order = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) # Assert self.assertEqual(OrderType.LIMIT, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(TimeInForce.DAY, order.time_in_force) self.assertFalse(order.is_completed) def test_can_initialize_limit_order_with_expire_time(self): # Arrange # Act order = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5), Label('U1_TP'), OrderPurpose.NONE, TimeInForce.GTD, UNIX_EPOCH) # Assert self.assertEqual(AUDUSD_FXCM, order.symbol) self.assertEqual(OrderType.LIMIT, order.type) self.assertEqual(Price(1.00000, 5), order.price) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(TimeInForce.GTD, order.time_in_force) self.assertEqual(UNIX_EPOCH, order.expire_time) self.assertFalse(order.is_completed) def test_can_initialize_stop_market_order(self): # Arrange # Act order = self.order_factory.stop(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) # Assert self.assertEqual(OrderType.STOP, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertEqual(TimeInForce.DAY, order.time_in_force) self.assertFalse(order.is_completed) def test_can_initialize_stop_limit_order(self): # Arrange # Act order = self.order_factory.stop_limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) # Assert self.assertEqual(OrderType.STOP_LIMIT, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertFalse(order.is_completed) def test_can_initialize_market_if_touched_order(self): # Arrange # Act order = self.order_factory.market_if_touched(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) # Assert self.assertEqual(OrderType.MIT, order.type) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertFalse(order.is_completed) def test_can_initialize_fill_or_kill_order(self): # Arrange # Act order = self.order_factory.fill_or_kill(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) # Assert self.assertEqual(OrderType.MARKET, order.type) self.assertEqual(TimeInForce.FOC, order.time_in_force) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertFalse(order.is_completed) def test_can_initialize_immediate_or_cancel_order(self): # Arrange # Act order = self.order_factory.immediate_or_cancel(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) # Assert self.assertEqual(OrderType.MARKET, order.type) self.assertEqual(TimeInForce.IOC, order.time_in_force) self.assertEqual(OrderState.INITIALIZED, order.state) self.assertFalse(order.is_completed) def test_can_initialize_atomic_order_market_with_no_take_profit_or_label( self): # Arrange # Act atomic_order = self.order_factory.atomic_market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(0.99990, 5)) # Assert self.assertEqual(AUDUSD_FXCM, atomic_order.stop_loss.symbol) self.assertFalse(atomic_order.has_take_profit) self.assertEqual(OrderId('O-19700101-000000-001-001-1'), atomic_order.entry.id) self.assertEqual(OrderId('O-19700101-000000-001-001-2'), atomic_order.stop_loss.id) self.assertEqual(OrderSide.SELL, atomic_order.stop_loss.side) self.assertEqual(Quantity(100000), atomic_order.entry.quantity) self.assertEqual(Quantity(100000), atomic_order.stop_loss.quantity) self.assertEqual(Price(0.99990, 5), atomic_order.stop_loss.price) self.assertEqual(None, atomic_order.entry.label) self.assertEqual(None, atomic_order.stop_loss.label) self.assertEqual(TimeInForce.GTC, atomic_order.stop_loss.time_in_force) self.assertEqual(None, atomic_order.entry.expire_time) self.assertEqual(None, atomic_order.stop_loss.expire_time) self.assertEqual(AtomicOrderId('AO-19700101-000000-001-001-1'), atomic_order.id) self.assertEqual(UNIX_EPOCH, atomic_order.timestamp) def test_can_initialize_atomic_order_market_with_take_profit_and_label( self): # Arrange # Act atomic_order = self.order_factory.atomic_market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(0.99990, 5), Price(1.00010, 5), Label('U1')) # Assert self.assertEqual(AUDUSD_FXCM, atomic_order.stop_loss.symbol) self.assertTrue(atomic_order.has_take_profit) self.assertEqual(AUDUSD_FXCM, atomic_order.take_profit.symbol) self.assertEqual(OrderId('O-19700101-000000-001-001-1'), atomic_order.entry.id) self.assertEqual(OrderId('O-19700101-000000-001-001-2'), atomic_order.stop_loss.id) self.assertEqual(OrderId('O-19700101-000000-001-001-3'), atomic_order.take_profit.id) self.assertEqual(OrderSide.SELL, atomic_order.stop_loss.side) self.assertEqual(OrderSide.SELL, atomic_order.take_profit.side) self.assertEqual(Quantity(100000), atomic_order.stop_loss.quantity) self.assertEqual(Quantity(100000), atomic_order.take_profit.quantity) self.assertEqual(Price(0.99990, 5), atomic_order.stop_loss.price) self.assertEqual(Price(1.00010, 5), atomic_order.take_profit.price) self.assertEqual(Label('U1_E'), atomic_order.entry.label) self.assertEqual(Label('U1_SL'), atomic_order.stop_loss.label) self.assertEqual(Label('U1_TP'), atomic_order.take_profit.label) self.assertEqual(TimeInForce.GTC, atomic_order.stop_loss.time_in_force) self.assertEqual(TimeInForce.GTC, atomic_order.take_profit.time_in_force) self.assertEqual(None, atomic_order.entry.expire_time) self.assertEqual(None, atomic_order.stop_loss.expire_time) self.assertEqual(None, atomic_order.take_profit.expire_time) self.assertEqual(AtomicOrderId('AO-19700101-000000-001-001-1'), atomic_order.id) self.assertEqual(UNIX_EPOCH, atomic_order.timestamp) def test_atomic_order_str_and_repr(self): # Arrange # Act atomic_order = self.order_factory.atomic_market( AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(0.99990, 5), Price(1.00010, 5), Label('U1')) # Assert self.assertEqual( 'AtomicOrder(id=AO-19700101-000000-001-001-1, EntryOrder(id=O-19700101-000000-001-001-1, state=INITIALIZED, label=U1_E, BUY 100K AUDUSD.FXCM MARKET DAY), SL=0.99990, TP=1.00010)', str(atomic_order)) self.assertTrue( repr(atomic_order).startswith( '<AtomicOrder(id=AO-19700101-000000-001-001-1, EntryOrder(id=O-19700101-000000-001-001-1, state=INITIALIZED, label=U1_E, BUY 100K AUDUSD.FXCM MARKET DAY), SL=0.99990, TP=1.00010) object at' )) self.assertTrue(repr(atomic_order).endswith('>')) def test_can_apply_order_submitted_event_to_order(self): # Arrange order = self.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) event = OrderSubmitted(self.account_id, order.id, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) # Act order.apply(event) # Assert self.assertEqual(OrderState.SUBMITTED, order.state) self.assertEqual(2, order.event_count) self.assertEqual(event, order.last_event) self.assertFalse(order.is_completed) def test_can_apply_order_accepted_event_to_order(self): # Arrange order = self.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) event = OrderAccepted(self.account_id, order.id, OrderIdBroker('B' + order.id.value), Label('E'), UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) # Act order.apply(event) # Assert self.assertEqual(OrderState.ACCEPTED, order.state) self.assertFalse(order.is_completed) def test_can_apply_order_rejected_event_to_order(self): # Arrange order = self.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) event = OrderRejected(self.account_id, order.id, UNIX_EPOCH, ValidString('ORDER ID INVALID'), GUID(uuid.uuid4()), UNIX_EPOCH) # Act order.apply(event) # Assert self.assertEqual(OrderState.REJECTED, order.state) self.assertTrue(order.is_completed) def test_can_apply_order_working_event_to_order(self): # Arrange order = self.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) event = OrderWorking(self.account_id, order.id, OrderIdBroker('SOME_BROKER_ID'), order.symbol, order.label, order.side, order.type, order.quantity, Price(1.0, 1), order.time_in_force, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH, order.expire_time) # Act order.apply(event) # Assert # print(order) self.assertEqual(OrderState.WORKING, order.state) self.assertEqual(OrderIdBroker('SOME_BROKER_ID'), order.id_broker) self.assertFalse(order.is_completed) self.assertTrue(order.is_working) self.assertEqual(None, order.filled_timestamp) def test_can_apply_order_expired_event_to_order(self): # Arrange order = self.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) event = OrderExpired(self.account_id, order.id, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) # Act order.apply(event) # Assert self.assertEqual(OrderState.EXPIRED, order.state) self.assertTrue(order.is_completed) def test_can_apply_order_cancelled_event_to_order(self): # Arrange order = self.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) event = OrderCancelled(self.account_id, order.id, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) # Act order.apply(event) # Assert self.assertEqual(OrderState.CANCELLED, order.state) self.assertTrue(order.is_completed) def test_can_apply_order_cancel_reject_event_to_order(self): # Arrange order = self.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) event = OrderCancelReject(self.account_id, order.id, UNIX_EPOCH, ValidString('REJECT_RESPONSE'), ValidString('ORDER DOES NOT EXIST'), GUID(uuid.uuid4()), UNIX_EPOCH) # Act order.apply(event) # Assert self.assertEqual(OrderState.INITIALIZED, order.state) def test_can_apply_order_modified_event_to_order(self): # Arrange order = self.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) order_working = OrderWorking(self.account_id, order.id, OrderIdBroker('SOME_BROKER_ID_1'), order.symbol, order.label, order.side, order.type, order.quantity, Price(1.00000, 5), order.time_in_force, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH, order.expire_time) order_modified = OrderModified(self.account_id, order.id, OrderIdBroker('SOME_BROKER_ID_2'), Quantity(120000), Price(1.00001, 5), UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) order.apply(order_working) # Act order.apply(order_modified) # Assert self.assertEqual(OrderState.WORKING, order.state) self.assertEqual(OrderIdBroker('SOME_BROKER_ID_2'), order.id_broker) self.assertEqual(Quantity(120000), order.quantity) self.assertEqual(Price(1.00001, 5), order.price) self.assertTrue(order.is_working) self.assertFalse(order.is_completed) self.assertEqual(3, order.event_count) def test_can_apply_order_filled_event_to_market_order(self): # Arrange order = self.order_factory.market(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000)) event = OrderFilled(self.account_id, order.id, ExecutionId('SOME_EXEC_ID_1'), PositionIdBroker('SOME_EXEC_TICKET_1'), order.symbol, order.side, order.quantity, Price(1.00001, 5), Currency.USD, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) # Act order.apply(event) # Assert self.assertEqual(OrderState.FILLED, order.state) self.assertEqual(Quantity(100000), order.filled_quantity) self.assertEqual(Price(1.00001, 5), order.average_price) self.assertTrue(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp) def test_can_apply_order_filled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) event = OrderFilled(self.account_id, order.id, ExecutionId('SOME_EXEC_ID_1'), PositionIdBroker('SOME_EXEC_TICKET_1'), order.symbol, order.side, order.quantity, Price(1.00001, 5), Currency.USD, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) # Act order.apply(event) # Assert self.assertEqual(OrderState.FILLED, order.state) self.assertEqual(Quantity(100000), order.filled_quantity) self.assertEqual(Price(1.00000, 5), order.price) self.assertEqual(Price(1.00001, 5), order.average_price) self.assertEqual(Decimal(0.00001, 5), order.slippage) self.assertTrue(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp) def test_can_apply_order_partially_filled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) event = OrderPartiallyFilled(self.account_id, order.id, ExecutionId('SOME_EXEC_ID_1'), PositionIdBroker('SOME_EXEC_TICKET_1'), order.symbol, order.side, Quantity(50000), Quantity(50000), Price(0.999999, 6), Currency.USD, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) # Act order.apply(event) # Assert self.assertEqual(OrderState.PARTIALLY_FILLED, order.state) self.assertEqual(Quantity(50000), order.filled_quantity) self.assertEqual(Price(1.00000, 5), order.price) self.assertEqual(Price(0.999999, 6), order.average_price) self.assertEqual(Decimal(-0.000001, 6), order.slippage) self.assertFalse(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp) def test_can_apply_order_overfilled_event_to_buy_limit_order(self): # Arrange order = self.order_factory.limit(AUDUSD_FXCM, OrderSide.BUY, Quantity(100000), Price(1.00000, 5)) event = OrderFilled(self.account_id, order.id, ExecutionId('SOME_EXEC_ID_1'), PositionIdBroker('SOME_EXEC_TICKET_1'), order.symbol, order.side, Quantity(150000), Price(0.99999, 5), Currency.USD, UNIX_EPOCH, GUID(uuid.uuid4()), UNIX_EPOCH) # Act order.apply(event) # Assert self.assertEqual(OrderState.OVER_FILLED, order.state) self.assertEqual(Quantity(150000), order.filled_quantity) self.assertFalse(order.is_completed) self.assertEqual(UNIX_EPOCH, order.filled_timestamp)