示例#1
0
    def test_from_json_does_not_fail_when_order_fills_not_present(self):
        order_json = {
            "client_order_id": self.client_order_id,
            "exchange_order_id": self.exchange_order_id,
            "trading_pair": self.trading_pair,
            "order_type": OrderType.LIMIT.name,
            "trade_type": TradeType.BUY.name,
            "price": "1.0",
            "amount": "1000.0",
            "executed_amount_base": "0",
            "executed_amount_quote": "0",
            "fee_asset": None,
            "fee_paid": "0",
            "last_state": "0",
            "leverage": "1",
            "position": PositionAction.NIL.value,
            "creation_timestamp": 1640001112
        }

        expected_order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            exchange_order_id=self.exchange_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
        )

        order_from_json = InFlightOrder.from_json(order_json)
        self.assertEqual(expected_order, order_from_json)
        self.assertFalse(order_from_json.completely_filled_event.is_set())
示例#2
0
    def test_completed_order_recovered_from_json_has_completed_event_updated(self):
        order_json = {
            "client_order_id": self.client_order_id,
            "exchange_order_id": self.exchange_order_id,
            "trading_pair": self.trading_pair,
            "order_type": OrderType.LIMIT.name,
            "trade_type": TradeType.BUY.name,
            "price": "1.0",
            "amount": "1000.0",
            "executed_amount_base": "1000.0",
            "executed_amount_quote": "1100.0",
            "fee_asset": None,
            "fee_paid": "0",
            "last_state": "0",
            "leverage": "1",
            "position": "NIL",
            "creation_timestamp": 1640001112.0,
        }

        expected_order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            exchange_order_id=self.exchange_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
        )
        expected_order.executed_amount_base = Decimal("1000")
        expected_order.executed_amount_quote = Decimal("1100")

        order_from_json = InFlightOrder.from_json(order_json)
        self.assertEqual(expected_order, order_from_json)
        self.assertTrue(order_from_json.completely_filled_event.is_set())
    def test_from_json(self):
        order_json = {
            "client_order_id": self.client_order_id,
            "exchange_order_id": self.exchange_order_id,
            "trading_pair": self.trading_pair,
            "order_type": OrderType.LIMIT.name,
            "trade_type": TradeType.BUY.name,
            "price": "1.0",
            "amount": "1000.0",
            "executed_amount_base": "0",
            "executed_amount_quote": "0",
            "fee_asset": None,
            "fee_paid": "0",
            "last_state": "0",
            "leverage": "1",
            "position": PositionAction.NIL.value,
        }

        expected_order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            exchange_order_id=self.exchange_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )

        order_from_json = InFlightOrder.from_json(order_json)
        self.assertEqual(expected_order, order_from_json)
    def test_restore_tracking_states_only_registers_open_orders(self):
        orders = []
        orders.append(
            InFlightOrder(
                client_order_id="OID1",
                exchange_order_id="EOID1",
                trading_pair=self.trading_pair,
                order_type=OrderType.LIMIT,
                trade_type=TradeType.BUY,
                amount=Decimal("1000.0"),
                creation_timestamp=1640001112.223,
                price=Decimal("1.0"),
            ))
        orders.append(
            InFlightOrder(client_order_id="OID2",
                          exchange_order_id="EOID2",
                          trading_pair=self.trading_pair,
                          order_type=OrderType.LIMIT,
                          trade_type=TradeType.BUY,
                          amount=Decimal("1000.0"),
                          creation_timestamp=1640001112.223,
                          price=Decimal("1.0"),
                          initial_state=OrderState.CANCELED))
        orders.append(
            InFlightOrder(client_order_id="OID3",
                          exchange_order_id="EOID3",
                          trading_pair=self.trading_pair,
                          order_type=OrderType.LIMIT,
                          trade_type=TradeType.BUY,
                          amount=Decimal("1000.0"),
                          price=Decimal("1.0"),
                          creation_timestamp=1640001112.223,
                          initial_state=OrderState.FILLED))
        orders.append(
            InFlightOrder(client_order_id="OID4",
                          exchange_order_id="EOID4",
                          trading_pair=self.trading_pair,
                          order_type=OrderType.LIMIT,
                          trade_type=TradeType.BUY,
                          amount=Decimal("1000.0"),
                          price=Decimal("1.0"),
                          creation_timestamp=1640001112.223,
                          initial_state=OrderState.FAILED))

        tracking_states = {
            order.client_order_id: order.to_json()
            for order in orders
        }

        self.tracker.restore_tracking_states(tracking_states)

        self.assertIn("OID1", self.tracker.active_orders)
        self.assertNotIn("OID2", self.tracker.all_orders)
        self.assertNotIn("OID3", self.tracker.all_orders)
        self.assertNotIn("OID4", self.tracker.all_orders)
    def test_restore_tracking_states_only_registers_open_orders(self):
        orders = []
        orders.append(
            InFlightOrder(
                client_order_id="OID1",
                exchange_order_id="EOID1",
                trading_pair=self.trading_pair,
                order_type=OrderType.LIMIT,
                trade_type=TradeType.BUY,
                amount=Decimal("1000.0"),
                price=Decimal("1.0"),
                creation_timestamp=1640001112.223,
            ))
        orders.append(
            InFlightOrder(client_order_id="OID2",
                          exchange_order_id="EOID2",
                          trading_pair=self.trading_pair,
                          order_type=OrderType.LIMIT,
                          trade_type=TradeType.BUY,
                          amount=Decimal("1000.0"),
                          price=Decimal("1.0"),
                          creation_timestamp=1640001112.223,
                          initial_state=BitmexPerpetualOrderStatus.Canceled))
        orders.append(
            InFlightOrder(client_order_id="OID3",
                          exchange_order_id="EOID3",
                          trading_pair=self.trading_pair,
                          order_type=OrderType.LIMIT,
                          trade_type=TradeType.BUY,
                          amount=Decimal("1000.0"),
                          price=Decimal("1.0"),
                          creation_timestamp=1640001112.223,
                          initial_state=BitmexPerpetualOrderStatus.Filled))
        orders.append(
            InFlightOrder(client_order_id="OID4",
                          exchange_order_id="EOID4",
                          trading_pair=self.trading_pair,
                          order_type=OrderType.LIMIT,
                          trade_type=TradeType.BUY,
                          amount=Decimal("1000.0"),
                          price=Decimal("1.0"),
                          creation_timestamp=1640001112.223,
                          initial_state=BitmexPerpetualOrderStatus.FAILURE))

        tracking_states = {
            order.client_order_id: order.to_json()
            for order in orders
        }

        self.exchange.restore_tracking_states(tracking_states)

        self.assertIn("OID1", self.exchange.in_flight_orders)
        self.assertNotIn("OID2", self.exchange.in_flight_orders)
        self.assertNotIn("OID3", self.exchange.in_flight_orders)
        self.assertNotIn("OID4", self.exchange.in_flight_orders)
示例#6
0
    def test_from_json(self):
        fee = AddedToCostTradeFee(
            percent=Decimal("0.5"),
            percent_token=self.quote_asset
        )
        trade_update = TradeUpdate(
            trade_id="12345",
            client_order_id=self.client_order_id,
            exchange_order_id="EOID1",
            trading_pair=self.trading_pair,
            fill_timestamp=1640001112,
            fill_price=Decimal("1000.11"),
            fill_base_amount=Decimal("2"),
            fill_quote_amount=Decimal("2000.22"),
            fee=fee,
        )

        order_json = {
            "client_order_id": self.client_order_id,
            "exchange_order_id": self.exchange_order_id,
            "trading_pair": self.trading_pair,
            "order_type": OrderType.LIMIT.name,
            "trade_type": TradeType.BUY.name,
            "price": "1.0",
            "amount": "1000.0",
            "executed_amount_base": "0",
            "executed_amount_quote": "0",
            "fee_asset": None,
            "fee_paid": "0",
            "last_state": "0",
            "leverage": "1",
            "position": "NIL",
            "creation_timestamp": 1640001112.0,
            "order_fills": {"1": trade_update.to_json()}
        }

        expected_order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            exchange_order_id=self.exchange_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
        )

        order_from_json = InFlightOrder.from_json(order_json)
        self.assertEqual(expected_order, order_from_json)
        self.assertFalse(order_from_json.completely_filled_event.is_set())

        self.assertIn("1", order_from_json.order_fills)
        self.assertEqual(trade_update, order_from_json.order_fills["1"])
示例#7
0
 def start_tracking_order(self, order_id: str,
                          exchange_order_id: Optional[str],
                          trading_pair: str, trade_type: TradeType,
                          price: Decimal, amount: Decimal,
                          order_type: OrderType):
     """
     Starts tracking an order by adding it to the order tracker.
     :param order_id: the order identifier
     :param exchange_order_id: the identifier for the order in the exchange
     :param trading_pair: the token pair for the operation
     :param trade_type: the type of order (buy or sell)
     :param price: the price for the order
     :param amount: the amount for the order
     :order type: type of execution for the order (MARKET, LIMIT, LIMIT_MAKER)
     """
     self._order_tracker.start_tracking_order(
         InFlightOrder(
             client_order_id=order_id,
             exchange_order_id=exchange_order_id,
             trading_pair=trading_pair,
             order_type=order_type,
             trade_type=trade_type,
             amount=amount,
             price=price,
         ))
    def test_update_with_order_update_open_order(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )

        open_order_update: OrderUpdate = OrderUpdate(
            client_order_id=self.client_order_id,
            exchange_order_id=self.exchange_order_id,
            trading_pair=self.trading_pair,
            update_timestamp=1,
            new_state=OrderState.OPEN,
        )

        self.assertTrue(order.update_with_order_update(open_order_update))
        self.assertEqual(Decimal("0"), order.executed_amount_base)
        self.assertEqual(Decimal("0"), order.executed_amount_quote)
        self.assertIsNone(order.fee_asset)
        self.assertEqual(Decimal("0"), order.cumulative_fee_paid)
        self.assertEqual(Decimal("0"), order.last_filled_price)
        self.assertEqual(Decimal("0"), order.last_filled_amount)
        self.assertEqual(Decimal("0"), order.last_fee_paid)
        self.assertEqual(1, order.last_update_timestamp)
    def test_to_json(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )

        order_json = order.to_json()

        self.assertIsInstance(order_json, dict)

        self.assertEqual(order_json["client_order_id"], order.client_order_id)
        self.assertEqual(order_json["exchange_order_id"], order.exchange_order_id)
        self.assertEqual(order_json["trading_pair"], order.trading_pair)
        self.assertEqual(order_json["order_type"], order.order_type.name)
        self.assertEqual(order_json["trade_type"], order.trade_type.name)
        self.assertEqual(order_json["price"], str(order.price))
        self.assertEqual(order_json["amount"], str(order.amount))
        self.assertEqual(order_json["executed_amount_base"], str(order.executed_amount_base))
        self.assertEqual(order_json["executed_amount_quote"], str(order.executed_amount_quote))
        self.assertEqual(order_json["fee_asset"], order.fee_asset)
        self.assertEqual(order_json["fee_paid"], str(order.cumulative_fee_paid))
        self.assertEqual(order_json["last_state"], str(order.current_state.value))
        self.assertEqual(order_json["leverage"], str(order.leverage))
        self.assertEqual(order_json["position"], order.position.value)
示例#10
0
 def start_tracking_order(
         self,
         order_id: str,
         trading_pair: str,
         trade_type: TradeType,
         price: Decimal,
         amount: Decimal,
         order_type: OrderType,
         exchange_order_id: Optional[str] = None,
 ):
     """
     Starts tracking an order by simply adding it into InFlightOrderTracker.
     """
     self._in_flight_order_tracker.start_tracking_order(
         InFlightOrder(
             client_order_id=order_id,
             exchange_order_id=exchange_order_id,
             trading_pair=trading_pair,
             order_type=order_type,
             trade_type=trade_type,
             amount=amount,
             price=price,
             creation_timestamp=self.current_timestamp
         )
     )
    def test_to_limit_order(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )

        expected_limit_order: LimitOrder = LimitOrder(
            client_order_id=order.client_order_id,
            trading_pair=order.trading_pair,
            is_buy=True,
            base_currency=self.base_asset,
            quote_currency=self.quote_asset,
            price=Decimal("1.0"),
            quantity=Decimal("1000.0"),
            filled_quantity=Decimal("0"),
        )

        limit_order = order.to_limit_order()

        self.assertIsInstance(limit_order, LimitOrder)

        self.assertEqual(limit_order.client_order_id, expected_limit_order.client_order_id)
        self.assertEqual(limit_order.trading_pair, expected_limit_order.trading_pair)
        self.assertEqual(limit_order.is_buy, expected_limit_order.is_buy)
        self.assertEqual(limit_order.base_currency, expected_limit_order.base_currency)
        self.assertEqual(limit_order.quote_currency, expected_limit_order.quote_currency)
        self.assertEqual(limit_order.price, expected_limit_order.price)
        self.assertEqual(limit_order.quantity, expected_limit_order.quantity)
        self.assertEqual(limit_order.filled_quantity, expected_limit_order.filled_quantity)
        self.assertEqual(limit_order.creation_timestamp, expected_limit_order.creation_timestamp)
        self.assertEqual(limit_order.status, expected_limit_order.status)
    def test_update_with_order_update_client_order_id_mismatch(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )

        mismatch_order_update: OrderUpdate = OrderUpdate(
            client_order_id="mismatchClientOrderId",
            exchange_order_id="mismatchExchangeOrderId",
            trading_pair=self.trading_pair,
            update_timestamp=1,
            new_state=OrderState.OPEN,
            fill_price=Decimal("1.0"),
            executed_amount_base=Decimal("1000.0"),
            executed_amount_quote=Decimal("1000.0"),
            fee_asset=self.base_asset,
            cumulative_fee_paid=self.trade_fee_percent * Decimal("1000.0"),
        )

        self.assertFalse(order.update_with_order_update(mismatch_order_update))
        self.assertEqual(Decimal("0"), order.executed_amount_base)
        self.assertEqual(Decimal("0"), order.executed_amount_quote)
        self.assertIsNone(order.fee_asset)
        self.assertEqual(Decimal("0"), order.cumulative_fee_paid)
        self.assertEqual(Decimal("0"), order.last_filled_price)
        self.assertEqual(Decimal("0"), order.last_filled_amount)
        self.assertEqual(Decimal("0"), order.last_fee_paid)
        self.assertEqual(-1, order.last_update_timestamp)
示例#13
0
    def test_update_with_trade_update_duplicate_trade_update(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
        )

        trade_update: TradeUpdate = TradeUpdate(
            trade_id="someTradeId",
            client_order_id=self.client_order_id,
            exchange_order_id=self.exchange_order_id,
            trading_pair=self.trading_pair,
            fill_price=Decimal("1.0"),
            fill_base_amount=Decimal("500.0"),
            fill_quote_amount=Decimal("500.0"),
            fee=AddedToCostTradeFee(
                flat_fees=[TokenAmount(token=self.quote_asset, amount=self.trade_fee_percent * Decimal("500.0"))]),
            fill_timestamp=1,
        )

        self.assertTrue(order.update_with_trade_update(trade_update))
        self.assertEqual(order.executed_amount_base, trade_update.fill_base_amount)
        self.assertEqual(order.executed_amount_quote, trade_update.fill_quote_amount)
        self.assertEqual(order.last_update_timestamp, trade_update.fill_timestamp)
        self.assertEqual(1, len(order.order_fills))
        self.assertIn(trade_update.trade_id, order.order_fills)

        # Ignores duplicate trade update
        self.assertFalse(order.update_with_trade_update(trade_update))
示例#14
0
    def test_process_order_update_trigger_order_cancelled_event(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            exchange_order_id="someExchangeOrderId",
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
            initial_state=OrderState.OPEN,
        )

        self.tracker.start_tracking_order(order)

        order_cancelled_update: OrderUpdate = OrderUpdate(
            client_order_id=order.client_order_id,
            exchange_order_id=order.exchange_order_id,
            trading_pair=self.trading_pair,
            update_timestamp=1,
            new_state=OrderState.CANCELLED,
        )

        update_future = self.tracker.process_order_update(order_cancelled_update)
        self.async_run_with_timeout(update_future)

        self.assertTrue(self._is_logged("INFO", f"Successfully cancelled order {order.client_order_id}."))
        self.assertEqual(0, len(self.tracker.active_orders))
        self.assertEqual(1, len(self.tracker.cached_orders))
        self.assertEqual(1, len(self.order_cancelled_logger.event_log))

        event_triggered = self.order_cancelled_logger.event_log[0]
        self.assertIsInstance(event_triggered, OrderCancelledEvent)
        self.assertEqual(event_triggered.exchange_order_id, order.exchange_order_id)
        self.assertEqual(event_triggered.order_id, order.client_order_id)
示例#15
0
    def test_trade_update_does_not_change_exchange_order_id(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
        )

        trade_update: TradeUpdate = TradeUpdate(
            trade_id="someTradeId",
            client_order_id=self.client_order_id,
            exchange_order_id=self.exchange_order_id,
            trading_pair=self.trading_pair,
            fill_price=Decimal("1.0"),
            fill_base_amount=Decimal("500.0"),
            fill_quote_amount=Decimal("500.0"),
            fee=AddedToCostTradeFee(
                flat_fees=[TokenAmount(token=self.quote_asset, amount=self.trade_fee_percent * Decimal("500.0"))]),
            fill_timestamp=1,
        )

        self.assertTrue(order.update_with_trade_update(trade_update))
        self.assertIsNone(order.exchange_order_id)
        self.assertFalse(order.exchange_order_id_update_event.is_set())
    def test_update_with_trade_update_trade_update_with_trade_fee_percent(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )

        trade_update: TradeUpdate = TradeUpdate(
            trade_id="someTradeId",
            client_order_id=self.client_order_id,
            exchange_order_id=self.exchange_order_id,
            trading_pair=self.trading_pair,
            fill_price=Decimal("1.0"),
            fill_base_amount=Decimal("500.0"),
            fill_quote_amount=Decimal("500.0"),
            fee_asset=self.base_asset,
            trade_fee_percent=self.trade_fee_percent,
            fill_timestamp=1,
        )

        self.assertTrue(order.update_with_trade_update(trade_update))
        self.assertIsNotNone(order.exchange_order_id)
        self.assertTrue(order.exchange_order_id_update_event.is_set())
        self.assertEqual(order.executed_amount_base, trade_update.fill_base_amount)
        self.assertEqual(order.executed_amount_quote, trade_update.fill_quote_amount)
        self.assertEqual(order.fee_asset, trade_update.fee_asset)
        self.assertEqual(order.cumulative_fee_paid, self.trade_fee_percent * Decimal("500.0"))
        self.assertEqual(order.last_filled_price, trade_update.fill_price)
        self.assertEqual(order.last_filled_amount, trade_update.fill_base_amount)
        self.assertEqual(order.last_update_timestamp, trade_update.fill_timestamp)
        self.assertEqual(1, len(order.order_fills))
        self.assertIn(trade_update.trade_id, order.order_fills)
    def test_process_order_update_trigger_order_creation_event_without_client_order_id(
            self):
        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            exchange_order_id=
            "someExchangeOrderId",  # exchange_order_id is provided when initialized. See AscendEx.
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
        )
        self.tracker.start_tracking_order(order)

        order_creation_update: OrderUpdate = OrderUpdate(
            # client_order_id=order.client_order_id,  # client_order_id purposefully ommited
            exchange_order_id="someExchangeOrderId",
            trading_pair=self.trading_pair,
            update_timestamp=1,
            new_state=OrderState.OPEN,
        )

        update_future = self.tracker.process_order_update(
            order_creation_update)
        self.async_run_with_timeout(update_future)

        updated_order: InFlightOrder = self.tracker.fetch_tracked_order(
            order.client_order_id)

        # Check order update has been successfully applied
        self.assertEqual(updated_order.exchange_order_id,
                         order_creation_update.exchange_order_id)
        self.assertTrue(updated_order.exchange_order_id_update_event.is_set())
        self.assertEqual(updated_order.current_state,
                         order_creation_update.new_state)
        self.assertTrue(updated_order.is_open)

        # Check that Logger has logged the correct log
        self.assertTrue(
            self._is_logged(
                "INFO",
                f"Created {order.order_type.name} {order.trade_type.name} order {order.client_order_id} for "
                f"{order.amount} {order.trading_pair}.",
            ))

        # Check that Buy/SellOrderCreatedEvent has been triggered.
        self.assertEqual(1, len(self.buy_order_created_logger.event_log))
        event_logged = self.buy_order_created_logger.event_log[0]

        self.assertEqual(event_logged.amount, order.amount)
        self.assertEqual(event_logged.exchange_order_id,
                         order_creation_update.exchange_order_id)
        self.assertEqual(event_logged.order_id, order.client_order_id)
        self.assertEqual(event_logged.price, order.price)
        self.assertEqual(event_logged.trading_pair, order.trading_pair)
        self.assertEqual(event_logged.type, order.order_type)
示例#18
0
 def restore_tracking_states(self, tracking_states: Dict[str, any]):
     """
     Restore in-flight orders from saved tracking states.
     :param tracking_states: a dictionary associating order ids with the serialized order (JSON format).
     """
     for serialized_order in tracking_states.values():
         order = InFlightOrder.from_json(serialized_order)
         if order.is_open:
             self.start_tracking_order(order)
    def test_updating_order_states_with_both_process_order_update_and_process_trade_update(
            self):
        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
        )
        self.tracker.start_tracking_order(order)

        order_creation_update: OrderUpdate = OrderUpdate(
            client_order_id=order.client_order_id,
            exchange_order_id="someExchangeOrderId",
            trading_pair=self.trading_pair,
            update_timestamp=1,
            new_state=OrderState.OPEN,
        )

        update_future = self.tracker.process_order_update(
            order_creation_update)
        self.async_run_with_timeout(update_future)

        open_order: InFlightOrder = self.tracker.fetch_tracked_order(
            order.client_order_id)

        # Check order_creation_update has been successfully applied
        self.assertEqual(open_order.exchange_order_id,
                         order_creation_update.exchange_order_id)
        self.assertTrue(open_order.exchange_order_id_update_event.is_set())
        self.assertEqual(open_order.current_state,
                         order_creation_update.new_state)
        self.assertTrue(open_order.is_open)
        self.assertEqual(0, len(open_order.order_fills))

        trade_filled_price: Decimal = order.price
        trade_filled_amount: Decimal = order.amount
        fee_paid: Decimal = self.trade_fee_percent * trade_filled_amount
        trade_update: TradeUpdate = TradeUpdate(
            trade_id=1,
            client_order_id=order.client_order_id,
            exchange_order_id=order.exchange_order_id,
            trading_pair=order.trading_pair,
            fill_price=trade_filled_price,
            fill_base_amount=trade_filled_amount,
            fill_quote_amount=trade_filled_price * trade_filled_amount,
            fee=AddedToCostTradeFee(flat_fees=[
                TokenAmount(token=self.quote_asset, amount=fee_paid)
            ]),
            fill_timestamp=2,
        )

        self.tracker.process_trade_update(trade_update)
        self.assertEqual(1, len(self.tracker.active_orders))
        self.assertEqual(0, len(self.tracker.cached_orders))
示例#20
0
    def test_process_trade_update_does_not_trigger_filled_event_update_status_when_completely_filled(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            exchange_order_id="someExchangeOrderId",
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
            initial_state=OrderState.OPEN,
        )
        self.tracker.start_tracking_order(order)

        fee_paid: Decimal = self.trade_fee_percent * order.amount
        trade_update: TradeUpdate = TradeUpdate(
            trade_id=1,
            client_order_id=order.client_order_id,
            exchange_order_id=order.exchange_order_id,
            trading_pair=order.trading_pair,
            fill_price=order.price,
            fill_base_amount=order.amount,
            fill_quote_amount=order.price * order.amount,
            fee=AddedToCostTradeFee(flat_fees=[TokenAmount(token=self.quote_asset, amount=fee_paid)]),
            fill_timestamp=1,
        )

        self.tracker.process_trade_update(trade_update)

        fetched_order: InFlightOrder = self.tracker.fetch_order(order.client_order_id)
        self.assertTrue(fetched_order.is_filled)
        self.assertIn(fetched_order.client_order_id, self.tracker.active_orders)
        self.assertNotIn(fetched_order.client_order_id, self.tracker.cached_orders)

        self.assertTrue(
            self._is_logged(
                "INFO",
                f"The {order.trade_type.name.upper()} order {order.client_order_id} amounting to "
                f"{order.amount}/{order.amount} {order.base_asset} has been filled.",
            )
        )

        self.assertEqual(1, len(self.order_filled_logger.event_log))
        self.assertEqual(0, len(self.buy_order_completed_logger.event_log))

        order_filled_event: OrderFilledEvent = self.order_filled_logger.event_log[0]
        self.assertIsNotNone(order_filled_event)

        self.assertEqual(order_filled_event.order_id, order.client_order_id)
        self.assertEqual(order_filled_event.price, trade_update.fill_price)
        self.assertEqual(order_filled_event.amount, trade_update.fill_base_amount)
        self.assertEqual(
            order_filled_event.trade_fee, AddedToCostTradeFee(flat_fees=[TokenAmount(self.quote_asset, fee_paid)])
        )
    def test_cached_order_ttl_not_exceeded(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )
        self.tracker._cached_orders[order.client_order_id] = order

        self.assertIn(order.client_order_id, self.tracker._cached_orders)
    def test_process_order_update_trigger_order_creation_event(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )
        self.tracker.start_tracking_order(order)

        order_creation_update: OrderUpdate = OrderUpdate(
            client_order_id=order.client_order_id,
            exchange_order_id="someExchangeOrderId",
            trading_pair=self.trading_pair,
            update_timestamp=1,
            new_state=OrderState.OPEN,
        )

        self.tracker.process_order_update(order_creation_update)

        updated_order: InFlightOrder = self.tracker.fetch_tracked_order(
            order.client_order_id)

        # Check order update has been successfully applied
        self.assertEqual(updated_order.exchange_order_id,
                         order_creation_update.exchange_order_id)
        self.assertTrue(updated_order.exchange_order_id_update_event.is_set())
        self.assertEqual(updated_order.current_state,
                         order_creation_update.new_state)
        self.assertTrue(updated_order.is_open)

        # Check that Logger has logged the correct log
        self.assertTrue(
            self._is_logged(
                "INFO",
                f"Created {order.order_type.name} {order.trade_type.name} order {order.client_order_id} for "
                f"{order.amount} {order.trading_pair}.",
            ))

        # Check that Buy/SellOrderCreatedEvent has been triggered.
        self.assertEqual(1, len(self.connector.event_logs))
        event_logged = self.connector.event_logs[0]

        self.assertIsInstance(event_logged, BuyOrderCreatedEvent)
        self.assertEqual(event_logged.amount, order.amount)
        self.assertEqual(event_logged.exchange_order_id,
                         order_creation_update.exchange_order_id)
        self.assertEqual(event_logged.order_id, order.client_order_id)
        self.assertEqual(event_logged.price, order.price)
        self.assertEqual(event_logged.trading_pair, order.trading_pair)
        self.assertEqual(event_logged.type, order.order_type)
示例#23
0
    def test_to_json(self):
        fee = AddedToCostTradeFee(percent=Decimal("0.5"),
                                  percent_token=self.quote_asset)
        trade_update = TradeUpdate(
            trade_id="12345",
            client_order_id=self.client_order_id,
            exchange_order_id="EOID1",
            trading_pair=self.trading_pair,
            fill_timestamp=1640001112,
            fill_price=Decimal("1000.11"),
            fill_base_amount=Decimal("2"),
            fill_quote_amount=Decimal("2000.22"),
            fee=fee,
        )

        order: InFlightOrder = InFlightOrder(
            client_order_id=self.client_order_id,
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
        )
        order.order_fills["1"] = trade_update

        order_json = order.to_json()

        self.assertIsInstance(order_json, dict)

        self.assertEqual(order_json["client_order_id"], order.client_order_id)
        self.assertEqual(order_json["exchange_order_id"],
                         order.exchange_order_id)
        self.assertEqual(order_json["trading_pair"], order.trading_pair)
        self.assertEqual(order_json["order_type"], order.order_type.name)
        self.assertEqual(order_json["trade_type"], order.trade_type.name)
        self.assertEqual(order_json["price"], str(order.price))
        self.assertEqual(order_json["amount"], str(order.amount))
        self.assertEqual(order_json["executed_amount_base"],
                         str(order.executed_amount_base))
        self.assertEqual(order_json["executed_amount_quote"],
                         str(order.executed_amount_quote))
        self.assertEqual(order_json["last_state"],
                         str(order.current_state.value))
        self.assertEqual(order_json["leverage"], str(order.leverage))
        self.assertEqual(order_json["position"], order.position.value)
        self.assertEqual(order_json["creation_timestamp"],
                         order.creation_timestamp)
        self.assertEqual(order_json["order_fills"],
                         {"1": trade_update.to_json()})
    def test_process_trade_update_trigger_filled_event_flat_fee(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            exchange_order_id="someExchangeOrderId",
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
            initial_state=OrderState.OPEN,
        )
        self.tracker.start_tracking_order(order)

        trade_filled_price: Decimal = Decimal("0.5")
        trade_filled_amount: Decimal = order.amount / Decimal("2.0")
        fee_paid: Decimal = self.trade_fee_percent * trade_filled_amount
        trade_update: TradeUpdate = TradeUpdate(
            trade_id=1,
            client_order_id=order.client_order_id,
            exchange_order_id=order.exchange_order_id,
            trading_pair=order.trading_pair,
            fill_price=trade_filled_price,
            fill_base_amount=trade_filled_amount,
            fill_quote_amount=trade_filled_price * trade_filled_amount,
            fee_asset=self.base_asset,
            fee_paid=fee_paid,
            fill_timestamp=1,
        )

        self.tracker.process_trade_update(trade_update)

        self.assertTrue(
            self._is_logged(
                "INFO",
                f"The {order.trade_type.name.upper()} order {order.client_order_id} amounting to "
                f"{trade_filled_amount}/{order.amount} {order.base_asset} has been filled.",
            ))

        self.assertEqual(1, len(self.connector.event_logs))
        order_filled_event: OrderFilledEvent = self.connector.event_logs[0]

        self.assertEqual(order_filled_event.order_id, order.client_order_id)
        self.assertEqual(order_filled_event.price, trade_update.fill_price)
        self.assertEqual(order_filled_event.amount,
                         trade_update.fill_base_amount)
        self.assertEqual(
            order_filled_event.trade_fee,
            AddedToCostTradeFee(
                flat_fees=[TokenAmount(self.base_asset, fee_paid)]))
    def test_cached_order_ttl_exceeded(self):
        tracker = ClientOrderTracker(self.connector)
        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )
        tracker._cached_orders[order.client_order_id] = order

        self.ev_loop.run_until_complete(asyncio.sleep(0.2))

        self.assertNotIn(order.client_order_id, tracker.cached_orders)
    def test_start_tracking_order(self):
        self.assertEqual(0, len(self.tracker.active_orders))

        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )

        self.tracker.start_tracking_order(order)

        self.assertEqual(1, len(self.tracker.active_orders))
示例#27
0
    def test_fetch_order_does_not_match_orders_with_undefined_exchange_id(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
        )
        self.tracker.start_tracking_order(order)
        self.assertEqual(1, len(self.tracker.active_orders))

        fetched_order = self.tracker.fetch_order("invalid_order_id")

        self.assertIsNone(fetched_order)
    def test_fetch_cached_order(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            price=Decimal("1.0"),
        )
        self.tracker._cached_orders[order.client_order_id] = order
        self.assertEqual(1, len(self.tracker.cached_orders))

        fetched_order: InFlightOrder = self.tracker.fetch_cached_order(
            order.client_order_id)

        self.assertTrue(fetched_order == order)
示例#29
0
    def test_fetch_order_by_client_order_id(self):
        order: InFlightOrder = InFlightOrder(
            client_order_id="someClientOrderId",
            trading_pair=self.trading_pair,
            order_type=OrderType.LIMIT,
            trade_type=TradeType.BUY,
            amount=Decimal("1000.0"),
            creation_timestamp=1640001112.0,
            price=Decimal("1.0"),
        )
        self.tracker.start_tracking_order(order)
        self.assertEqual(1, len(self.tracker.active_orders))

        fetched_order: InFlightOrder = self.tracker.fetch_order(order.client_order_id)

        self.assertTrue(fetched_order == order)
示例#30
0
    def test_cached_order_max_cache_size(self):
        for i in range(ClientOrderTracker.MAX_CACHE_SIZE + 1):
            order: InFlightOrder = InFlightOrder(
                client_order_id=f"someClientOrderId_{i}",
                trading_pair=self.trading_pair,
                order_type=OrderType.LIMIT,
                trade_type=TradeType.BUY,
                amount=Decimal("1000.0"),
                creation_timestamp=1640001112.0,
                price=Decimal("1.0"),
            )
            self.tracker._cached_orders[order.client_order_id] = order

        self.assertEqual(ClientOrderTracker.MAX_CACHE_SIZE, len(self.tracker.cached_orders))

        # First entry gets removed when the no. of cached order exceeds MAX_CACHE_SIZE
        self.assertNotIn("someClientOrderId_0", self.tracker._cached_orders)