Ejemplo n.º 1
0
 async def _remove_position(self, hb_id: str, token_id: str, reducePercent: Decimal):
     """
     Calls add position end point to create/increase a range position.
     :param hb_id: Internal Hummingbot id
     :param token_id: The token id of position to be increased
     :param reducePercent: The percentage of liquidity to remove from position with the specified token id
     """
     tracked_pos = self._in_flight_positions.get(hb_id)
     await tracked_pos.get_last_tx_hash()
     tracked_pos.last_status = UniswapV3PositionStatus.PENDING_REMOVE
     tracked_pos.update_last_tx_hash(None)
     try:
         result = await self._api_request("post",
                                          "eth/uniswap/v3/remove-position",
                                          {"tokenId": token_id, "reducePercent": reducePercent})
         hash = result.get("hash")
         action = "removal of" if reducePercent == Decimal("100.0") else \
                  f"{reducePercent}% reduction of liquidity for"
         self.logger().info(f"Initiated {action} of position with ID - {token_id}.")
         tracked_pos.update_last_tx_hash(hash)
         self.trigger_event(MarketEvent.RangePositionUpdated,
                            RangePositionUpdatedEvent(self.current_timestamp, tracked_pos.hb_id,
                                                      tracked_pos.last_tx_hash, tracked_pos.token_id,
                                                      tracked_pos.base_amount, tracked_pos.quote_amount,
                                                      tracked_pos.last_status.name))
     except Exception as e:
         # self.stop_tracking_position(hb_id)
         self.logger().network(
             f"Error removing range position, token_id: {token_id}, hb_id: {hb_id}",
             exc_info=True,
             app_warning_msg=str(e)
         )
         self.trigger_event(MarketEvent.RangePositionFailure,
                            RangePositionFailureEvent(self.current_timestamp, hb_id))
Ejemplo n.º 2
0
 async def _remove_position(self, hb_id: str, token_id: str):
     tracked_pos = self._in_flight_positions.get(hb_id)
     await tracked_pos.get_last_tx_hash()
     tracked_pos.last_status = UniswapV3PositionStatus.PENDING_REMOVE
     tracked_pos.update_last_tx_hash(None)
     try:
         result = await self._api_request("post",
                                          "eth/uniswap/v3/remove-position",
                                          {"tokenId": token_id})
         hash = result.get("hash")
         self.logger().info(
             f"Initiated removal of position with ID - {token_id}.")
         tracked_pos.update_last_tx_hash(hash)
         self.trigger_event(
             MarketEvent.RangePositionUpdated,
             RangePositionUpdatedEvent(
                 self.current_timestamp, tracked_pos.hb_id,
                 tracked_pos.last_tx_hash, tracked_pos.token_id,
                 tracked_pos.base_amount, tracked_pos.quote_amount,
                 tracked_pos.last_status.name))
     except Exception as e:
         # self.stop_tracking_position(hb_id)
         self.logger().network(
             f"Error removing range position, token_id: {token_id}, hb_id: {hb_id}",
             exc_info=True,
             app_warning_msg=str(e))
         self.trigger_event(
             MarketEvent.RangePositionFailure,
             RangePositionFailureEvent(self.current_timestamp, hb_id))
Ejemplo n.º 3
0
 async def update_lp_order(self, update_result: Dict[str, any], tracked_pos: UniswapV3InFlightPosition):
     """
     Unlike swap orders, lp orders only stop tracking when a remove position is detected.
     """
     if update_result.get("confirmed", False):
         if update_result["receipt"].get("status", 0) == 1:
             transaction_results = await self._api_request("post",
                                                           "eth/uniswap/v3/result",
                                                           {"logs": json.dumps(update_result["receipt"]["logs"]),
                                                            "pair": tracked_pos.trading_pair})
             for result in transaction_results["info"]:
                 if result["name"] == "IncreaseLiquidity" and tracked_pos.last_status == UniswapV3PositionStatus.PENDING_CREATE:
                     token_id, amount0, amount1 = self.parse_liquidity_events(result["events"],
                                                                              transaction_results["baseDecimal"],
                                                                              transaction_results["quoteDecimal"])
                     tracked_pos.token_id = token_id
                     tracked_pos.base_amount = amount0
                     tracked_pos.quote_amount = amount1
                     tracked_pos.last_status = UniswapV3PositionStatus.OPEN
                     self.logger().info(f"Liquidity added for tokenID - {token_id}.")
                     self.trigger_event(MarketEvent.RangePositionUpdated,
                                        RangePositionUpdatedEvent(self.current_timestamp,
                                                                  tracked_pos.hb_id,
                                                                  tracked_pos.last_tx_hash,
                                                                  tracked_pos.token_id,
                                                                  tracked_pos.base_amount,
                                                                  tracked_pos.quote_amount,
                                                                  tracked_pos.last_status.name
                                                                  ))
                     self.trigger_event(MarketEvent.RangePositionCreated,
                                        RangePositionCreatedEvent(self.current_timestamp,
                                                                  tracked_pos.hb_id,
                                                                  tracked_pos.last_tx_hash,
                                                                  tracked_pos.token_id,
                                                                  tracked_pos.trading_pair,
                                                                  tracked_pos.fee_tier,
                                                                  tracked_pos.lower_price,
                                                                  tracked_pos.upper_price,
                                                                  tracked_pos.base_amount,
                                                                  tracked_pos.quote_amount,
                                                                  tracked_pos.last_status.name,
                                                                  tracked_pos.gas_price
                                                                  ))
                 elif result["name"] == "DecreaseLiquidity" and tracked_pos.last_status == UniswapV3PositionStatus.PENDING_REMOVE:
                     token_id, amount0, amount1 = self.parse_liquidity_events(result["events"],
                                                                              transaction_results["baseDecimal"],
                                                                              transaction_results["quoteDecimal"])
                     tracked_pos.token_id = token_id
                     tracked_pos.last_status = UniswapV3PositionStatus.REMOVED
                     self.logger().info(f"Liquidity decreased for tokenID - {token_id}.")
                     self.trigger_event(MarketEvent.RangePositionUpdated,
                                        RangePositionUpdatedEvent(self.current_timestamp,
                                                                  tracked_pos.hb_id,
                                                                  tracked_pos.last_tx_hash,
                                                                  tracked_pos.token_id,
                                                                  tracked_pos.base_amount,
                                                                  tracked_pos.quote_amount,
                                                                  tracked_pos.last_status.name
                                                                  ))
                     self.trigger_event(MarketEvent.RangePositionRemoved,
                                        RangePositionRemovedEvent(self.current_timestamp, tracked_pos.hb_id,
                                                                  tracked_pos.token_id))
                     self.stop_tracking_position(tracked_pos.hb_id)
                 elif result["name"] == "Collect":
                     pass
                     # not sure how to handle this at the moment
                     # token_id, amount0, amount1 = self.parse_liquidity_events(result["events"])
                     # tracked_order.update_exchange_order_id(token_id)
                     # self.logger().info(f"Liquidity removed for tokenID - {token_id}.")
         else:
             self.logger().info(
                 f"Error updating range position, token_id: {tracked_pos.token_id}, hb_id: {tracked_pos.hb_id}"
             )
             self.trigger_event(MarketEvent.RangePositionFailure,
                                RangePositionFailureEvent(self.current_timestamp, tracked_pos.hb_id))
             self.stop_tracking_position(tracked_pos.hb_id)
             tracked_pos.last_status = UniswapV3PositionStatus.FAILED
Ejemplo n.º 4
0
    async def _update_order_status(self):
        """
        Calls REST API to get status update for each in-flight order.
        """
        tasks, tracked_orders, tracked_positions, open_positions = [], [], [], []
        if len(self._in_flight_orders) > 0:
            tracked_orders = list(self._in_flight_orders.values())
            for tracked_order in tracked_orders:
                order_id = await tracked_order.get_exchange_order_id()
                tasks.append(
                    self._api_request("post", "eth/poll",
                                      {"txHash": order_id}))
        if len(self._in_flight_positions) > 0:
            tracked_positions = [
                pos for pos in self._in_flight_positions.values()
                if pos.last_status.is_pending()
            ]  # We only want to poll update for pending positions
            open_positions = [
                pos for pos in self._in_flight_positions.values()
                if pos.last_status.is_active()
            ]
            for tracked_pos in tracked_positions:
                last_hash = await tracked_pos.get_last_tx_hash()
                tasks.append(
                    self._api_request("post", "eth/poll",
                                      {"txHash": last_hash}))
        if tasks:
            update_results = await safe_gather(*tasks, return_exceptions=True)
            for update_result, tracked_item in zip(
                    update_results, tracked_orders + tracked_positions):
                self.logger().debug(
                    f"Polling for order status updates of {len(tasks)} orders."
                )
                if isinstance(update_result, Exception):
                    raise update_result
                if "txHash" not in update_result:
                    self.logger().info(
                        f"Update_order_status txHash not in resp: {update_result}"
                    )
                    continue
                if isinstance(tracked_item, UniswapInFlightOrder):
                    await self.update_swap_order(update_result, tracked_item)
                else:
                    await self.update_lp_order(update_result, tracked_item)

        # update info for each positions as well
        tasks = []
        if len(open_positions) > 0:
            for tracked_pos in open_positions:
                tasks.append(self.get_position(tracked_pos.token_id))
        if tasks:
            position_results = await safe_gather(*tasks,
                                                 return_exceptions=True)
            for update_result, tracked_item in zip(position_results,
                                                   open_positions):
                if not isinstance(update_result, Exception) and len(
                        update_result.get("position", {})) > 0:
                    tracked_item.lower_price = Decimal(
                        update_result["position"].get("lowerPrice", "0"))
                    tracked_item.upper_price = Decimal(
                        update_result["position"].get("upperPrice", "0"))
                    amount0 = Decimal(update_result["position"].get(
                        "amount0", "0"))
                    amount1 = Decimal(update_result["position"].get(
                        "amount1", "0"))
                    unclaimedToken0 = Decimal(update_result["position"].get(
                        "unclaimedToken0", "0"))
                    unclaimedToken1 = Decimal(update_result["position"].get(
                        "unclaimedToken1", "0"))
                    if amount0 == amount1 == unclaimedToken0 == unclaimedToken1 == s_decimal_0:
                        self.logger().info(
                            f"Detected that position with id: {tracked_item.token_id} is closed."
                        )
                        tracked_item.last_status = UniswapV3PositionStatus.REMOVED  # this will prevent it from being restored on next import
                        self.trigger_event(
                            MarketEvent.RangePositionUpdated,
                            RangePositionUpdatedEvent(
                                self.current_timestamp, tracked_item.hb_id,
                                tracked_item.last_tx_hash,
                                tracked_item.token_id,
                                tracked_item.base_amount,
                                tracked_item.quote_amount,
                                tracked_item.last_status.name))
                        self.trigger_event(
                            MarketEvent.RangePositionRemoved,
                            RangePositionRemovedEvent(self.current_timestamp,
                                                      tracked_item.hb_id,
                                                      tracked_item.token_id))
                        self.stop_tracking_position(tracked_item.hb_id)

                    else:
                        if tracked_item.trading_pair.split(
                                "-")[0] == update_result["position"]["token0"]:
                            tracked_item.current_base_amount = amount0
                            tracked_item.current_quote_amount = amount1
                            tracked_item.unclaimed_base_amount = unclaimedToken0
                            tracked_item.unclaimed_quote_amount = unclaimedToken1
                        else:
                            tracked_item.current_base_amount = amount1
                            tracked_item.current_quote_amount = amount0
                            tracked_item.unclaimed_base_amount = unclaimedToken1
                            tracked_item.unclaimed_quote_amount = unclaimedToken0