Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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)
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
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
Exemplo n.º 5
0
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)