Exemple #1
0
    def test_handle_position_opening_with_position_id_none(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order = strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        submit_order = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        self.exec_engine.execute(submit_order)

        # Act
        self.exec_engine.process(TestStubs.event_order_submitted(order))
        self.exec_engine.process(TestStubs.event_order_accepted(order))
        self.exec_engine.process(TestStubs.event_order_filled(order, AUDUSD_SIM, PositionId.null()))

        expected_id = PositionId("P-000-AUD/USD.SIM-1")  # Generated inside engine

        # Assert
        self.assertTrue(self.cache.position_exists(expected_id))
        self.assertTrue(self.cache.is_position_open(expected_id))
        self.assertFalse(self.cache.is_position_closed(expected_id))
        self.assertEqual(Position, type(self.cache.position(expected_id)))
        self.assertIn(expected_id, self.cache.position_ids())
        self.assertNotIn(expected_id, self.cache.position_closed_ids(strategy_id=strategy.id))
        self.assertNotIn(expected_id, self.cache.position_closed_ids())
        self.assertIn(expected_id, self.cache.position_open_ids(strategy_id=strategy.id))
        self.assertIn(expected_id, self.cache.position_open_ids())
        self.assertEqual(1, self.cache.positions_total_count())
        self.assertEqual(1, self.cache.positions_open_count())
        self.assertEqual(0, self.cache.positions_closed_count())
    def test_position_identifier(self):
        # Arrange
        # Act
        position_id0 = PositionId.null()

        # Assert
        self.assertEqual("P-NULL", position_id0.value)
Exemple #3
0
    def test_submit_order_when_not_connected_logs_and_does_not_send(self):
        # Arrange
        strategy = TradingStrategy("000")
        order = self.order_factory.market(
            ETHUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity(100),
        )

        command = SubmitOrder(
            BINANCE,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        # Act
        self.exec_client.submit_order(command)

        # Assert
        self.assertEqual(OrderState.INITIALIZED, order.state)
    def test_submit_order_when_not_connected_logs_and_does_not_send(self):
        # Arrange
        strategy = TradingStrategy("000")
        order = self.order_factory.market(
            ETHUSDT_BINANCE.id,
            OrderSide.BUY,
            Quantity(100),
        )

        command = SubmitOrder(
            order.instrument_id.venue.client_id,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        # Act
        self.exec_client.submit_order(command)

        # Assert
        assert order.state == OrderState.INITIALIZED
Exemple #5
0
    def test_unrealized_pnl_when_insufficient_data_for_xrate_returns_none(
            self):
        # Arrange
        state = AccountState(
            account_id=AccountId("BITMEX", "01234"),
            account_type=AccountType.MARGIN,
            base_currency=BTC,
            reported=True,
            balances=[
                AccountBalance(
                    BTC,
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
                AccountBalance(
                    ETH,
                    Money(20.00000000, ETH),
                    Money(0.00000000, ETH),
                    Money(20.00000000, ETH),
                ),
            ],
            info={},
            event_id=uuid4(),
            updated_ns=0,
            timestamp_ns=0,
        )

        self.exec_engine.process(state)

        order = self.order_factory.market(
            ETHUSD_BITMEX.id,
            OrderSide.BUY,
            Quantity.from_int(100),
        )

        self.exec_engine.cache.add_order(order, PositionId.null())
        self.exec_engine.process(TestStubs.event_order_submitted(order))
        self.exec_engine.process(TestStubs.event_order_accepted(order))

        fill = TestStubs.event_order_filled(
            order=order,
            instrument=ETHUSD_BITMEX,
            position_id=PositionId("P-123456"),
            strategy_id=StrategyId("S-001"),
            last_px=Price.from_str("376.05"),
        )

        self.exec_engine.process(fill)

        position = Position(instrument=ETHUSD_BITMEX, fill=fill)

        self.portfolio.update_position(
            TestStubs.event_position_opened(position))

        # Act
        result = self.portfolio.unrealized_pnls(BITMEX)

        # # Assert
        self.assertEqual({}, result)
Exemple #6
0
    def test_position_identifier(self):
        # Arrange
        # Act
        position_id0 = PositionId.null()

        # Assert
        assert "NULL" == position_id0.value
    def test_submit_order_with_default_settings_sends_to_client(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order = strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        submit_order = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        # Act
        self.risk_engine.execute(submit_order)

        # Assert
        assert self.exec_client.calls == ['connect', 'submit_order']
        async def run_test():
            # Arrange
            self.engine.start()

            strategy = TradingStrategy(order_id_tag="001")
            strategy.register_trader(
                TraderId("TESTER", "000"),
                self.clock,
                self.logger,
            )

            self.engine.register_strategy(strategy)

            order = strategy.order_factory.limit(
                AUDUSD_SIM.id,
                OrderSide.BUY,
                Quantity(100000),
                Price("1.00000"),
            )

            submit_order = SubmitOrder(
                AUDUSD_SIM.id,
                self.trader_id,
                self.account_id,
                strategy.id,
                PositionId.null(),
                order,
                self.uuid_factory.generate(),
                self.clock.timestamp_ns(),
            )

            self.engine.execute(submit_order)
            self.engine.process(TestStubs.event_order_submitted(order))
            self.engine.process(TestStubs.event_order_accepted(order))

            report = OrderStatusReport(
                client_order_id=order.client_order_id,
                venue_order_id=VenueOrderId("1"),  # <-- from stub event
                order_state=OrderState.EXPIRED,
                filled_qty=Quantity(0),
                timestamp_ns=0,
            )

            self.client.add_order_status_report(report)

            await asyncio.sleep(0.01)

            # Act
            result = await self.engine.reconcile_state()
            self.engine.stop()

            # Assert
            assert result
Exemple #9
0
    def test_update_order_with_default_settings_sends_to_client(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER-000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order = strategy.order_factory.stop_market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
            Price.from_str("1.00010"),
        )

        submit = SubmitOrder(
            self.trader_id,
            strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        update = UpdateOrder(
            self.trader_id,
            strategy.id,
            order.instrument_id,
            order.client_order_id,
            order.venue_order_id,
            order.quantity,
            Price.from_str("1.00010"),
            None,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        self.risk_engine.execute(submit)

        # Act
        self.risk_engine.execute(update)

        # Assert
        assert self.exec_client.calls == [
            "connect", "submit_order", "update_order"
        ]
        assert self.risk_engine.command_count == 2
        assert self.exec_engine.command_count == 2
Exemple #10
0
    def test_cancel_order_with_default_settings_sends_to_client(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order = strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        submit = SubmitOrder(
            order.instrument_id.venue.client_id,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        cancel = CancelOrder(
            order.instrument_id.venue.client_id,
            self.trader_id,
            self.account_id,
            order.instrument_id,
            order.client_order_id,
            order.venue_order_id,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        self.risk_engine.execute(submit)

        # Act
        self.risk_engine.execute(cancel)

        # Assert
        assert self.exec_client.calls == [
            "connect", "submit_order", "cancel_order"
        ]
Exemple #11
0
    def event_order_filled(
        order,
        instrument,
        position_id=None,
        strategy_id=None,
        fill_price=None,
        fill_qty=None,
        liquidity_side=LiquiditySide.TAKER,
    ) -> OrderFilled:
        if position_id is None:
            position_id = PositionId.null()
        if strategy_id is None:
            strategy_id = StrategyId.null()
        if fill_price is None:
            fill_price = Price("1.00000")
        if fill_qty is None:
            fill_qty = order.quantity

        commission = instrument.calculate_commission(
            quantity=order.quantity,
            avg_price=fill_price,
            liquidity_side=liquidity_side,
        )

        return OrderFilled(
            account_id=TestStubs.account_id(),
            cl_ord_id=order.cl_ord_id,
            order_id=order.id,
            execution_id=ExecutionId(order.cl_ord_id.value.replace("O", "E")),
            position_id=position_id,
            strategy_id=strategy_id,
            symbol=order.symbol,
            order_side=order.side,
            fill_qty=fill_qty,
            cum_qty=Quantity(order.filled_qty + fill_qty),
            leaves_qty=Quantity(
                max(0, order.quantity - order.filled_qty - fill_qty)),
            fill_price=order.price if fill_price is None else fill_price,
            currency=instrument.quote_currency,
            is_inverse=instrument.is_inverse,
            commission=commission,
            liquidity_side=liquidity_side,
            execution_time=UNIX_EPOCH,
            event_id=uuid4(),
            event_timestamp=UNIX_EPOCH,
        )
    def test_message_qsize_at_max_blocks_on_put_event(self):
        # Arrange
        self.risk_engine = LiveRiskEngine(
            loop=self.loop,
            exec_engine=self.exec_engine,
            portfolio=self.portfolio,
            clock=self.clock,
            logger=self.logger,
            config={"qsize": 1},
        )

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order = strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        submit_order = SubmitOrder(
            order.instrument_id,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        event = TestStubs.event_order_submitted(order)

        # Act
        self.risk_engine.execute(submit_order)
        self.risk_engine.process(event)  # Add over max size

        # Assert
        assert self.risk_engine.qsize() == 1
        assert self.risk_engine.event_count == 0
Exemple #13
0
    def test_message_qsize_at_max_blocks_on_put_event(self):
        # Arrange
        self.exec_engine = LiveExecutionEngine(loop=self.loop,
                                               database=self.database,
                                               portfolio=self.portfolio,
                                               clock=self.clock,
                                               logger=self.logger,
                                               config={"qsize": 1})

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order = strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        submit_order = SubmitOrder(
            Venue("SIM"),
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        event = TestStubs.event_order_submitted(order)

        # Act
        self.exec_engine.execute(submit_order)
        self.exec_engine.process(event)  # Add over max size

        # Assert
        self.assertEqual(1, self.exec_engine.qsize())
        self.assertEqual(0, self.exec_engine.command_count)
Exemple #14
0
    def test_message_qsize_at_max_blocks_on_put_command(self):
        # Arrange
        self.exec_engine = LiveExecutionEngine(
            loop=self.loop,
            portfolio=self.portfolio,
            cache=self.cache,
            clock=self.clock,
            logger=self.logger,
            config={"qsize": 1},
        )

        self.exec_engine.register_risk_engine(self.risk_engine)

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER-000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order = strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        submit_order = SubmitOrder(
            self.trader_id,
            strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        # Act
        self.exec_engine.execute(submit_order)
        self.exec_engine.execute(submit_order)

        # Assert
        assert self.exec_engine.qsize() == 1
        assert self.exec_engine.command_count == 0
    def test_submit_order_raises_exception(self):
        order = self.order_factory.limit(
            AUDUSD_SIM.id,
            OrderSide.SELL,
            Quantity.from_int(100000),
            Price.from_str("1.00000"),
        )

        command = SubmitOrder(
            self.trader_id,
            order.strategy_id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        self.assertRaises(NotImplementedError, self.client.submit_order,
                          command)
    def test_submit_order_raises_exception(self):
        order = self.order_factory.limit(
            AUDUSD_SIM.symbol,
            OrderSide.SELL,
            Quantity(100000),
            Price("1.00000"),
        )

        command = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            StrategyId("SCALPER", "001"),
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        self.assertRaises(NotImplementedError, self.client.submit_order, command)
    def test_execute_command(self):
        order = self.strategy.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.BUY,
            Quantity.from_str("1.00000000"),
        )

        command = SubmitOrder(
            self.trader_id,
            self.strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        def execute_command():
            self.exec_engine.execute(command)

        self.benchmark.pedantic(execute_command, iterations=10_000, rounds=1)
Exemple #18
0
        async def run_test():
            # Arrange
            self.exec_engine.start()

            strategy = TradingStrategy(order_id_tag="001")
            strategy.register_trader(
                TraderId("TESTER", "000"),
                self.clock,
                self.logger,
            )

            self.exec_engine.register_strategy(strategy)

            order = strategy.order_factory.market(
                AUDUSD_SIM.symbol,
                OrderSide.BUY,
                Quantity(100000),
            )

            submit_order = SubmitOrder(
                Venue("SIM"),
                self.trader_id,
                self.account_id,
                strategy.id,
                PositionId.null(),
                order,
                self.uuid_factory.generate(),
                self.clock.utc_now(),
            )

            # Act
            self.exec_engine.execute(submit_order)
            await asyncio.sleep(0.1)

            # Assert
            self.assertEqual(0, self.exec_engine.qsize())
            self.assertEqual(1, self.exec_engine.command_count)

            # Tear Down
            self.exec_engine.stop()
        async def run_test():
            # Arrange
            self.risk_engine.start()

            strategy = TradingStrategy(order_id_tag="001")
            strategy.register_trader(
                TraderId("TESTER", "000"),
                self.clock,
                self.logger,
            )

            self.exec_engine.register_strategy(strategy)

            order = strategy.order_factory.market(
                AUDUSD_SIM.id,
                OrderSide.BUY,
                Quantity(100000),
            )

            submit_order = SubmitOrder(
                order.instrument_id,
                self.trader_id,
                self.account_id,
                strategy.id,
                PositionId.null(),
                order,
                self.uuid_factory.generate(),
                self.clock.timestamp_ns(),
            )

            # Act
            self.risk_engine.execute(submit_order)
            await asyncio.sleep(0.1)

            # Assert
            assert self.risk_engine.qsize() == 0
            assert self.risk_engine.command_count == 1

            # Tear Down
            self.risk_engine.stop()
Exemple #20
0
    def test_execute_command(self):
        order = self.strategy.order_factory.market(
            BTCUSDT_BINANCE.symbol,
            OrderSide.BUY,
            Quantity("1.00000000"),
        )

        command = SubmitOrder(
            order.symbol.venue,
            self.trader_id,
            self.account_id,
            self.strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        def execute_command():
            self.exec_engine.execute(command)

        PerformanceHarness.profile_function(execute_command, 10000, 1)
Exemple #21
0
    def test_submit_order_when_block_all_orders_true_then_denies_order(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order = strategy.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity(100000),
        )

        submit_order = SubmitOrder(
            order.instrument_id.venue.client_id,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.timestamp_ns(),
        )

        self.risk_engine.set_block_all_orders()

        # Act
        self.exec_engine.execute(submit_order)

        # Assert
        assert self.exec_client.calls == ["connect"]
        assert self.exec_engine.event_count == 1
Exemple #22
0
    def test_submit_order(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order = strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        submit_order = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        # Act
        self.exec_engine.execute(submit_order)

        # Assert
        self.assertIn(submit_order, self.exec_client.commands)
        self.assertTrue(self.cache.order_exists(order.cl_ord_id))
        async def run_test():
            # Arrange
            self.exec_engine.start()

            strategy = TradingStrategy(order_id_tag="001")
            strategy.register_trader(
                TraderId("TESTER-000"),
                self.clock,
                self.logger,
            )

            self.exec_engine.register_strategy(strategy)

            order = strategy.order_factory.limit(
                AUDUSD_SIM.id,
                OrderSide.BUY,
                Quantity.from_int(100000),
                Price.from_str("1.00000"),
            )

            submit_order = SubmitOrder(
                self.trader_id,
                strategy.id,
                PositionId.null(),
                order,
                self.uuid_factory.generate(),
                self.clock.timestamp_ns(),
            )

            self.exec_engine.execute(submit_order)
            self.exec_engine.process(TestStubs.event_order_submitted(order))
            self.exec_engine.process(TestStubs.event_order_accepted(order))

            report = OrderStatusReport(
                client_order_id=order.client_order_id,
                venue_order_id=VenueOrderId("1"),  # <-- from stub event
                order_state=OrderState.PARTIALLY_FILLED,
                filled_qty=Quantity.from_int(70000),
                timestamp_ns=0,
            )

            trade1 = ExecutionReport(
                client_order_id=order.client_order_id,
                venue_order_id=VenueOrderId("1"),
                execution_id=ExecutionId("1"),
                last_qty=Quantity.from_int(50000),
                last_px=Price.from_str("1.00000"),
                commission=Money(5.00, USD),
                liquidity_side=LiquiditySide.MAKER,
                ts_filled_ns=0,
                timestamp_ns=0,
            )

            trade2 = ExecutionReport(
                client_order_id=order.client_order_id,
                venue_order_id=VenueOrderId("1"),
                execution_id=ExecutionId("2"),
                last_qty=Quantity.from_int(20000),
                last_px=Price.from_str("1.00000"),
                commission=Money(2.00, USD),
                liquidity_side=LiquiditySide.MAKER,
                ts_filled_ns=0,
                timestamp_ns=0,
            )

            self.client.add_order_status_report(report)
            self.client.add_trades_list(VenueOrderId("1"), [trade1, trade2])

            await asyncio.sleep(0.01)

            # Act
            result = await self.exec_engine.reconcile_state(timeout_secs=10)
            self.exec_engine.stop()

            # Assert
            assert result
Exemple #24
0
    def test_flip_position_on_opposite_filled_same_position_buy(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order1 = strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.SELL,
            Quantity(100000),
        )

        order2 = strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(150000),
        )

        submit_order1 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order1,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        position_id = PositionId("P-000-AUD/USD.SIM-1")

        self.exec_engine.execute(submit_order1)
        self.exec_engine.process(TestStubs.event_order_submitted(order1))
        self.exec_engine.process(TestStubs.event_order_accepted(order1))
        self.exec_engine.process(
            TestStubs.event_order_filled(order1, AUDUSD_SIM, position_id))

        submit_order2 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            position_id,
            order2,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        # Act
        self.exec_engine.execute(submit_order2)
        self.exec_engine.process(TestStubs.event_order_submitted(order2))
        self.exec_engine.process(TestStubs.event_order_accepted(order2))
        self.exec_engine.process(
            TestStubs.event_order_filled(order2, AUDUSD_SIM, position_id))

        position_id_flipped = PositionId("P-000-AUD/USD.SIM-1F")

        # Assert
        position_flipped = self.cache.position(position_id_flipped)
        self.assertEqual(50000, position_flipped.relative_quantity)
        self.assertTrue(self.cache.position_exists(position_id))
        self.assertTrue(self.cache.position_exists(position_id_flipped))
        self.assertTrue(self.cache.is_position_closed(position_id))
        self.assertTrue(self.cache.is_position_open(position_id_flipped))
        self.assertIn(position_id, self.cache.position_ids())
        self.assertIn(position_id,
                      self.cache.position_ids(strategy_id=strategy.id))
        self.assertIn(position_id_flipped, self.cache.position_ids())
        self.assertIn(position_id_flipped,
                      self.cache.position_ids(strategy_id=strategy.id))
        self.assertEqual(2, self.cache.positions_total_count())
        self.assertEqual(1, self.cache.positions_open_count())
        self.assertEqual(1, self.cache.positions_closed_count())
Exemple #25
0
    def test_multiple_strategy_positions_one_active_one_closed(self):
        # Arrange
        self.exec_engine.start()

        strategy1 = TradingStrategy(order_id_tag="001")
        strategy1.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        strategy2 = TradingStrategy(order_id_tag="002")
        strategy2.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy1)
        self.exec_engine.register_strategy(strategy2)

        order1 = strategy1.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        order2 = strategy1.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.SELL,
            Quantity(100000),
            Price("1.00000"),
        )

        order3 = strategy2.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        submit_order1 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy1.id,
            PositionId.null(),
            order1,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        position_id1 = PositionId('P-1')

        submit_order2 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy1.id,
            position_id1,
            order2,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        submit_order3 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy2.id,
            PositionId.null(),
            order3,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        position_id2 = PositionId('P-2')

        # Act
        self.exec_engine.execute(submit_order1)
        self.exec_engine.process(TestStubs.event_order_submitted(order1))
        self.exec_engine.process(TestStubs.event_order_accepted(order1))
        self.exec_engine.process(
            TestStubs.event_order_filled(order1, AUDUSD_SIM, position_id1))

        self.exec_engine.execute(submit_order2)
        self.exec_engine.process(TestStubs.event_order_submitted(order2))
        self.exec_engine.process(TestStubs.event_order_accepted(order2))
        self.exec_engine.process(
            TestStubs.event_order_filled(order2, AUDUSD_SIM, position_id1))

        self.exec_engine.execute(submit_order3)
        self.exec_engine.process(TestStubs.event_order_submitted(order3))
        self.exec_engine.process(TestStubs.event_order_accepted(order3))
        self.exec_engine.process(
            TestStubs.event_order_filled(order3, AUDUSD_SIM, position_id2))

        # Assert
        # Already tested .is_position_active and .is_position_closed above
        self.assertTrue(self.cache.position_exists(position_id1))
        self.assertTrue(self.cache.position_exists(position_id2))
        self.assertIn(position_id1,
                      self.cache.position_ids(strategy_id=strategy1.id))
        self.assertIn(position_id2,
                      self.cache.position_ids(strategy_id=strategy2.id))
        self.assertIn(position_id1, self.cache.position_ids())
        self.assertIn(position_id2, self.cache.position_ids())
        self.assertEqual(
            0, len(self.cache.positions_open(strategy_id=strategy1.id)))
        self.assertEqual(
            1, len(self.cache.positions_open(strategy_id=strategy2.id)))
        self.assertEqual(1, len(self.cache.positions_open()))
        self.assertEqual(1, len(self.cache.positions_closed()))
        self.assertEqual(2, len(self.cache.positions()))
        self.assertNotIn(
            position_id1,
            self.cache.position_open_ids(strategy_id=strategy1.id))
        self.assertIn(position_id2,
                      self.cache.position_open_ids(strategy_id=strategy2.id))
        self.assertNotIn(position_id1, self.cache.position_open_ids())
        self.assertIn(position_id2, self.cache.position_open_ids())
        self.assertIn(position_id1,
                      self.cache.position_closed_ids(strategy_id=strategy1.id))
        self.assertNotIn(
            position_id2,
            self.cache.position_closed_ids(strategy_id=strategy2.id))
        self.assertIn(position_id1, self.cache.position_closed_ids())
        self.assertNotIn(position_id2, self.cache.position_closed_ids())
        self.assertEqual(2, self.cache.positions_total_count())
        self.assertEqual(1, self.cache.positions_open_count())
        self.assertEqual(1, self.cache.positions_closed_count())
Exemple #26
0
    def test_close_position_on_order_fill(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order1 = strategy.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
            Price("1.00000"),
        )

        order2 = strategy.order_factory.stop_market(
            AUDUSD_SIM.symbol,
            OrderSide.SELL,
            Quantity(100000),
            Price("1.00000"),
        )

        submit_order1 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order1,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        position_id = PositionId("P-1")

        self.exec_engine.execute(submit_order1)
        self.exec_engine.process(TestStubs.event_order_submitted(order1))
        self.exec_engine.process(TestStubs.event_order_accepted(order1))
        self.exec_engine.process(
            TestStubs.event_order_filled(order1, AUDUSD_SIM, position_id))

        submit_order2 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            position_id,
            order2,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        # Act
        self.exec_engine.execute(submit_order2)
        self.exec_engine.process(TestStubs.event_order_submitted(order2))
        self.exec_engine.process(TestStubs.event_order_accepted(order2))
        self.exec_engine.process(
            TestStubs.event_order_filled(order2, AUDUSD_SIM, position_id))

        # # Assert
        self.assertTrue(self.cache.position_exists(position_id))
        self.assertFalse(self.cache.is_position_open(position_id))
        self.assertTrue(self.cache.is_position_closed(position_id))
        self.assertEqual(position_id, self.cache.position(position_id).id)
        self.assertEqual(position_id,
                         self.cache.positions(strategy_id=strategy.id)[0].id)
        self.assertEqual(position_id, self.cache.positions()[0].id)
        self.assertEqual(
            0, len(self.cache.positions_open(strategy_id=strategy.id)))
        self.assertEqual(0, len(self.cache.positions_open()))
        self.assertEqual(
            position_id,
            self.cache.positions_closed(strategy_id=strategy.id)[0].id)
        self.assertEqual(position_id, self.cache.positions_closed()[0].id)
        self.assertNotIn(position_id,
                         self.cache.position_open_ids(strategy_id=strategy.id))
        self.assertNotIn(position_id, self.cache.position_open_ids())
        self.assertEqual(1, self.cache.positions_total_count())
        self.assertEqual(0, self.cache.positions_open_count())
        self.assertEqual(1, self.cache.positions_closed_count())
Exemple #27
0
    def test_add_to_existing_position_on_order_fill(self):
        # Arrange
        self.exec_engine.start()

        strategy = TradingStrategy(order_id_tag="001")
        strategy.register_trader(
            TraderId("TESTER", "000"),
            self.clock,
            self.logger,
        )

        self.exec_engine.register_strategy(strategy)

        order1 = strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        order2 = strategy.order_factory.market(
            AUDUSD_SIM.symbol,
            OrderSide.BUY,
            Quantity(100000),
        )

        submit_order1 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            PositionId.null(),
            order1,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        self.exec_engine.execute(submit_order1)
        self.exec_engine.process(TestStubs.event_order_submitted(order1))
        self.exec_engine.process(TestStubs.event_order_accepted(order1))
        self.exec_engine.process(
            TestStubs.event_order_filled(order1, AUDUSD_SIM))

        expected_position_id = PositionId(
            "O-19700101-000000-000-001-1")  # Stubbed from order id?

        submit_order2 = SubmitOrder(
            self.venue,
            self.trader_id,
            self.account_id,
            strategy.id,
            expected_position_id,
            order2,
            self.uuid_factory.generate(),
            self.clock.utc_now(),
        )

        # Act
        self.exec_engine.execute(submit_order2)
        self.exec_engine.process(TestStubs.event_order_submitted(order2))
        self.exec_engine.process(TestStubs.event_order_accepted(order2))
        self.exec_engine.process(
            TestStubs.event_order_filled(order2, AUDUSD_SIM,
                                         expected_position_id))

        # Assert
        self.assertTrue(
            self.cache.position_exists(
                TestStubs.event_order_filled(
                    order1,
                    AUDUSD_SIM,
                ).position_id))
        self.assertTrue(self.cache.is_position_open(expected_position_id))
        self.assertFalse(self.cache.is_position_closed(expected_position_id))
        self.assertEqual(Position,
                         type(self.cache.position(expected_position_id)))
        self.assertEqual(
            0, len(self.cache.positions_closed(strategy_id=strategy.id)))
        self.assertEqual(0, len(self.cache.positions_closed()))
        self.assertEqual(
            1, len(self.cache.positions_open(strategy_id=strategy.id)))
        self.assertEqual(1, len(self.cache.positions_open()))
        self.assertEqual(1, self.cache.positions_total_count())
        self.assertEqual(1, self.cache.positions_open_count())
        self.assertEqual(0, self.cache.positions_closed_count())
Exemple #28
0
    def test_update_positions(self):
        # Arrange
        state = AccountState(
            account_id=AccountId("BINANCE", "01234"),
            account_type=AccountType.CASH,
            base_currency=None,  # Multi-currency account
            reported=True,
            balances=[
                AccountBalance(
                    BTC,
                    Money(10.00000000, BTC),
                    Money(0.00000000, BTC),
                    Money(10.00000000, BTC),
                ),
                AccountBalance(
                    ETH,
                    Money(20.00000000, ETH),
                    Money(0.00000000, ETH),
                    Money(20.00000000, ETH),
                ),
            ],
            info={},
            event_id=uuid4(),
            updated_ns=0,
            timestamp_ns=0,
        )

        self.exec_engine.process(state)

        # Create a closed position
        order1 = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.BUY,
            Quantity.from_str("10.50000000"),
        )

        order2 = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.SELL,
            Quantity.from_str("10.50000000"),
        )

        self.exec_engine.cache.add_order(order1, PositionId.null())
        self.exec_engine.cache.add_order(order2, PositionId.null())

        # Push states to ACCEPTED
        order1.apply(TestStubs.event_order_submitted(order1))
        self.exec_engine.cache.update_order(order1)
        order1.apply(TestStubs.event_order_accepted(order1))
        self.exec_engine.cache.update_order(order1)

        fill1 = TestStubs.event_order_filled(
            order1,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-1"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("25000.00"),
        )

        fill2 = TestStubs.event_order_filled(
            order2,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-1"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("25000.00"),
        )

        position1 = Position(instrument=BTCUSDT_BINANCE, fill=fill1)
        position1.apply(fill2)

        order3 = self.order_factory.market(
            BTCUSDT_BINANCE.id,
            OrderSide.BUY,
            Quantity.from_str("10.00000000"),
        )

        fill3 = TestStubs.event_order_filled(
            order3,
            instrument=BTCUSDT_BINANCE,
            position_id=PositionId("P-2"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("25000.00"),
        )

        position2 = Position(instrument=BTCUSDT_BINANCE, fill=fill3)

        # Update the last quote
        last = QuoteTick(
            BTCUSDT_BINANCE.id,
            Price.from_str("25001.00"),
            Price.from_str("25002.00"),
            Quantity.from_int(1),
            Quantity.from_int(1),
            0,
            0,
        )

        # Act
        self.cache.add_position(position1)
        self.cache.add_position(position2)
        self.portfolio.initialize_positions()
        self.portfolio.update_tick(last)

        # Assert
        self.assertTrue(self.portfolio.is_net_long(BTCUSDT_BINANCE.id))
Exemple #29
0
    def test_opening_several_positions_updates_portfolio(self):
        # Arrange
        state = AccountState(
            account_id=AccountId("SIM", "01234"),
            account_type=AccountType.MARGIN,
            base_currency=USD,
            reported=True,
            balances=[
                AccountBalance(
                    USD,
                    Money(1_000_000, USD),
                    Money(0, USD),
                    Money(1_000_000, USD),
                ),
            ],
            info={},
            event_id=uuid4(),
            updated_ns=0,
            timestamp_ns=0,
        )

        self.exec_engine.process(state)

        last_audusd = QuoteTick(
            AUDUSD_SIM.id,
            Price.from_str("0.80501"),
            Price.from_str("0.80505"),
            Quantity.from_int(1),
            Quantity.from_int(1),
            0,
            0,
        )

        last_gbpusd = QuoteTick(
            GBPUSD_SIM.id,
            Price.from_str("1.30315"),
            Price.from_str("1.30317"),
            Quantity.from_int(1),
            Quantity.from_int(1),
            0,
            0,
        )

        self.cache.add_quote_tick(last_audusd)
        self.cache.add_quote_tick(last_gbpusd)
        self.portfolio.update_tick(last_audusd)
        self.portfolio.update_tick(last_gbpusd)

        order1 = self.order_factory.market(
            AUDUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        order2 = self.order_factory.market(
            GBPUSD_SIM.id,
            OrderSide.BUY,
            Quantity.from_int(100000),
        )

        self.exec_engine.cache.add_order(order1, PositionId.null())
        self.exec_engine.cache.add_order(order2, PositionId.null())

        fill1 = TestStubs.event_order_filled(
            order1,
            instrument=AUDUSD_SIM,
            position_id=PositionId("P-1"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("1.00000"),
        )

        fill2 = TestStubs.event_order_filled(
            order2,
            instrument=GBPUSD_SIM,
            position_id=PositionId("P-2"),
            strategy_id=StrategyId("S-1"),
            last_px=Price.from_str("1.00000"),
        )

        self.exec_engine.cache.update_order(order1)
        self.exec_engine.cache.update_order(order2)

        position1 = Position(instrument=AUDUSD_SIM, fill=fill1)
        position2 = Position(instrument=GBPUSD_SIM, fill=fill2)
        position_opened1 = TestStubs.event_position_opened(position1)
        position_opened2 = TestStubs.event_position_opened(position2)

        # Act
        self.cache.add_position(position1)
        self.cache.add_position(position2)
        self.portfolio.update_position(position_opened1)
        self.portfolio.update_position(position_opened2)

        # Assert
        self.assertEqual(
            {USD: Money(210816.00, USD)},
            self.portfolio.net_exposures(SIM),
        )
        self.assertEqual(
            {USD: Money(10816.00, USD)},
            self.portfolio.unrealized_pnls(SIM),
        )
        self.assertEqual({USD: Money(3912.06, USD)},
                         self.portfolio.maint_margins(SIM)),
        self.assertEqual(
            Money(80501.00, USD),
            self.portfolio.net_exposure(AUDUSD_SIM.id),
        )
        self.assertEqual(
            Money(130315.00, USD),
            self.portfolio.net_exposure(GBPUSD_SIM.id),
        )
        self.assertEqual(
            Money(-19499.00, USD),
            self.portfolio.unrealized_pnl(AUDUSD_SIM.id),
        )
        self.assertEqual(
            Money(30315.00, USD),
            self.portfolio.unrealized_pnl(GBPUSD_SIM.id),
        )
        self.assertEqual(Decimal(100000),
                         self.portfolio.net_position(AUDUSD_SIM.id))
        self.assertEqual(Decimal(100000),
                         self.portfolio.net_position(GBPUSD_SIM.id))
        self.assertTrue(self.portfolio.is_net_long(AUDUSD_SIM.id))
        self.assertFalse(self.portfolio.is_net_short(AUDUSD_SIM.id))
        self.assertFalse(self.portfolio.is_flat(AUDUSD_SIM.id))
        self.assertFalse(self.portfolio.is_completely_flat())
        async def run_test():
            # Arrange
            self.engine.start()

            strategy = TradingStrategy(order_id_tag="001")
            strategy.register_trader(
                TraderId("TESTER", "000"),
                self.clock,
                self.logger,
            )

            self.engine.register_strategy(strategy)

            order = strategy.order_factory.limit(
                AUDUSD_SIM.id,
                OrderSide.BUY,
                Quantity(100000),
                Price("1.00000"),
            )

            submit_order = SubmitOrder(
                AUDUSD_SIM.id,
                self.trader_id,
                self.account_id,
                strategy.id,
                PositionId.null(),
                order,
                self.uuid_factory.generate(),
                self.clock.timestamp_ns(),
            )

            self.engine.execute(submit_order)
            self.engine.process(TestStubs.event_order_submitted(order))
            self.engine.process(TestStubs.event_order_accepted(order))

            report = OrderStatusReport(
                client_order_id=order.client_order_id,
                venue_order_id=VenueOrderId("1"),  # <-- from stub event
                order_state=OrderState.FILLED,
                filled_qty=Quantity(100000),
                timestamp_ns=0,
            )

            trade1 = ExecutionReport(
                execution_id=ExecutionId("1"),
                client_order_id=order.client_order_id,
                venue_order_id=VenueOrderId("1"),
                last_qty=Decimal(50000),
                last_px=Decimal("1.00000"),
                commission_amount=Decimal("5.0"),
                commission_currency="USD",
                liquidity_side=LiquiditySide.MAKER,
                execution_ns=0,
                timestamp_ns=0,
            )

            trade2 = ExecutionReport(
                execution_id=ExecutionId("2"),
                client_order_id=order.client_order_id,
                venue_order_id=VenueOrderId("1"),
                last_qty=Decimal(50000),
                last_px=Decimal("1.00000"),
                commission_amount=Decimal("2.0"),
                commission_currency="USD",
                liquidity_side=LiquiditySide.MAKER,
                execution_ns=0,
                timestamp_ns=0,
            )

            self.client.add_order_status_report(report)
            self.client.add_trades_list(VenueOrderId("1"), [trade1, trade2])

            await asyncio.sleep(0.01)

            # Act
            result = await self.engine.reconcile_state()
            self.engine.stop()

            # Assert
            assert result