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))
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))
async def _replace_position(self, hb_id: str, token_id: str, trading_pair: str, fee_tier: Decimal, base_amount: Decimal, quote_amount: Decimal, lower_price: Decimal, upper_price: Decimal): """ Calls add position end point to create a new range position. :param hb_id: Internal Hummingbot id :param trading_pair: The market trading pair of the pool :param fee_tier: The expected fee :param base_amount: The amount of base token to put into the pool :param lower_price: The lower bound of the price range :param upper_price: The upper bound of the price range """ base_amount = self.quantize_order_amount(trading_pair, base_amount) quote_amount = self.quantize_order_amount(trading_pair, quote_amount) lower_price = self.quantize_order_price(trading_pair, lower_price) upper_price = self.quantize_order_price(trading_pair, upper_price) base, quote = trading_pair.split("-") 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) new_hb_id = f"{trading_pair}-{get_tracking_nonce()}" self.start_tracking_position(new_hb_id, trading_pair, fee_tier, base_amount, quote_amount, lower_price, upper_price) try: order_result = await self._api_request( "post", "eth/uniswap/v3/replace-position", { "tokenId": token_id, "token0": base, "token1": quote, "fee": str(fee_tier), "lowerPrice": str(lower_price), "upperPrice": str(upper_price), "amount0": str(base_amount), "amount1": str(quote_amount), }) tracked_pos = self._in_flight_positions.get(new_hb_id) tracked_pos.token_id = order_result.get("tokenId") tracked_pos.gas_price = Decimal(str(order_result.get("gasPrice"))) tracked_pos.update_last_tx_hash(order_result.get("hash")) self.logger().info( f"Initiated replacement of position with ID - {token_id}.") except Exception as e: self.stop_tracking_order(hb_id) self.logger().network( f"Error replacing range position to Uniswap with ID - {token_id} " f"hb_id: {hb_id}", exc_info=True, app_warning_msg=str(e)) self.trigger_event( MarketEvent.RangePositionFailure, RangePositionFailureEvent(self.current_timestamp, hb_id))
async def _add_position(self, hb_id: str, trading_pair: str, fee_tier: str, base_amount: Decimal, quote_amount: Decimal, lower_price: Decimal, upper_price: Decimal, token_id: int): """ Calls add position end point to create/increase a range position. :param hb_id: Internal Hummingbot id :param trading_pair: The market trading pair of the pool :param fee_tier: The expected fee :param base_amount: The amount of base token to put into the pool :param lower_price: The lower bound of the price range :param upper_price: The upper bound of the price range :param token_id: The token id of position to be increased """ base_amount = self.quantize_order_amount(trading_pair, base_amount) quote_amount = self.quantize_order_amount(trading_pair, quote_amount) lower_price = self.quantize_order_price(trading_pair, lower_price) upper_price = self.quantize_order_price(trading_pair, upper_price) base, quote = trading_pair.split("-") api_params = {"token0": base, "token1": quote, "fee": fee_tier, "lowerPrice": str(lower_price), "upperPrice": str(upper_price), "amount0": str(base_amount), "amount1": str(quote_amount), "tokenId": token_id } self.start_tracking_position(hb_id, trading_pair, fee_tier, base_amount, quote_amount, lower_price, upper_price) try: order_result = await self._api_request("post", "eth/uniswap/v3/add-position", api_params) tracked_pos = self._in_flight_positions[hb_id] tx_hash = order_result["hash"] tracked_pos.update_last_tx_hash(tx_hash) tracked_pos.gas_price = order_result.get("gasPrice") tracked_pos.last_status = UniswapV3PositionStatus.PENDING_CREATE self.logger().info(f"Adding liquidity for {trading_pair}, hb_id: {hb_id}, tx_hash: {tx_hash} " f"amount: {base_amount} ({base}), " f"range: {lower_price} - {upper_price}") self.trigger_event( MarketEvent.RangePositionInitiated, RangePositionInitiatedEvent( timestamp=self.current_timestamp, hb_id=hb_id, tx_hash=tx_hash, trading_pair=trading_pair, fee_tier=fee_tier, lower_price=lower_price, upper_price=upper_price, base_amount=base_amount, quote_amount=quote_amount, gas_price=tracked_pos.gas_price, status=UniswapV3PositionStatus.PENDING_CREATE.name, ) ) except Exception as e: self.stop_tracking_order(hb_id) self.logger().network( f"Error submitting range position to Uniswap V3 for {trading_pair} " f"hb_id: {hb_id}," f"amount: {base_amount} ({base}) {quote_amount}) ({quote}), " f"range: {lower_price} - {upper_price}", exc_info=True, app_warning_msg=str(e) ) self.trigger_event(MarketEvent.RangePositionFailure, RangePositionFailureEvent(self.current_timestamp, hb_id))
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