コード例 #1
0
ファイル: data_types.py プロジェクト: sniperswang/hummingbot
    def profit_pct(self, account_for_fee: bool = False,
                   rate_source: Any = FixedRateSource(),
                   first_side_quote_eth_rate: Decimal = None,
                   second_side_quote_eth_rate: Decimal = None) -> Decimal:
        """
        Returns a profit in percentage value (e.g. 0.01 for 1% profitability)
        Assumes the base token is the same in both arbitrage sides
        """
        buy = self.first_side if self.first_side.is_buy else self.second_side
        sell = self.first_side if not self.first_side.is_buy else self.second_side
        base_conversion_pair = f"{sell.market_info.base_asset}-{buy.market_info.base_asset}"
        quote_conversion_pair = f"{sell.market_info.quote_asset}-{buy.market_info.quote_asset}"

        sell_base_to_buy_base_rate = Decimal(1)
        sell_quote_to_buy_quote_rate = rate_source.rate(quote_conversion_pair)

        buy_fee_amount = s_decimal_0
        sell_fee_amount = s_decimal_0
        result = s_decimal_0

        if sell_quote_to_buy_quote_rate and sell_base_to_buy_base_rate:
            if account_for_fee:
                buy_trade_fee = estimate_fee(buy.market_info.market.name, False)
                sell_trade_fee = estimate_fee(sell.market_info.market.name, False)
                buy_quote_eth_rate = (first_side_quote_eth_rate
                                      if self.first_side.is_buy
                                      else second_side_quote_eth_rate)
                sell_quote_eth_rate = (first_side_quote_eth_rate
                                       if not self.first_side.is_buy
                                       else second_side_quote_eth_rate)
                if buy_quote_eth_rate is not None and buy_trade_fee.flat_fees[0].token.upper() == "ETH":
                    buy_fee_amount = buy_trade_fee.flat_fees[0].amount / buy_quote_eth_rate
                else:
                    buy_fee_amount = buy_trade_fee.fee_amount_in_quote(buy.market_info.trading_pair,
                                                                       buy.quote_price, buy.amount)
                if sell_quote_eth_rate is not None and sell_trade_fee.flat_fees[0].token.upper() == "ETH":
                    sell_fee_amount = sell_trade_fee.flat_fees[0].amount / sell_quote_eth_rate
                else:
                    sell_fee_amount = sell_trade_fee.fee_amount_in_quote(sell.market_info.trading_pair,
                                                                         sell.quote_price,
                                                                         sell.amount)

            buy_spent_net = (buy.amount * buy.quote_price) + buy_fee_amount
            sell_gained_net = (sell.amount * sell.quote_price) - sell_fee_amount
            sell_gained_net_in_buy_quote_currency = (sell_gained_net * sell_quote_to_buy_quote_rate
                                                     / sell_base_to_buy_base_rate)

            result = (((sell_gained_net_in_buy_quote_currency - buy_spent_net) / buy_spent_net)
                      if buy_spent_net != s_decimal_0
                      else s_decimal_0)
        else:
            self.logger().warning("The arbitrage proposal profitability could not be calculated due to a missing rate"
                                  f" ({base_conversion_pair}={sell_base_to_buy_base_rate},"
                                  f" {quote_conversion_pair}={sell_quote_to_buy_quote_rate})")

        return result
コード例 #2
0
    def test_estimate_fee(self):
        """
        test the estimate_fee function
        """

        # test against centralized exchanges
        self.assertEqual(estimate_fee("kucoin", True),
                         TradeFee(percent=Decimal('0.001'), flat_fees=[]))
        self.assertEqual(estimate_fee("kucoin", False),
                         TradeFee(percent=Decimal('0.001'), flat_fees=[]))
        self.assertEqual(estimate_fee("binance", True),
                         TradeFee(percent=Decimal('0.001'), flat_fees=[]))
        self.assertEqual(estimate_fee("binance", False),
                         TradeFee(percent=Decimal('0.001'), flat_fees=[]))

        # test against decentralized exchanges
        self.assertEqual(estimate_fee("beaxy", True),
                         TradeFee(percent=Decimal('0.0015'), flat_fees=[]))
        self.assertEqual(estimate_fee("beaxy", False),
                         TradeFee(percent=Decimal('0.0025'), flat_fees=[]))

        # test against an exchange with flat fees
        self.assertEqual(
            estimate_fee("bamboo_relay", True),
            TradeFee(percent=Decimal(0), flat_fees=[('ETH', Decimal('0'))]))
        self.assertEqual(
            estimate_fee("bamboo_relay", False),
            TradeFee(percent=Decimal(0),
                     flat_fees=[('ETH', Decimal('0.00001'))]))

        # test against exchanges that do not exist in hummingbot.client.settings.CONNECTOR_SETTINGS
        self.assertRaisesRegex(Exception, "^Invalid connector", estimate_fee,
                               "does_not_exist", True)
        self.assertRaisesRegex(Exception, "Invalid connector", estimate_fee,
                               "does_not_exist", False)
コード例 #3
0
 async def _process_trade_message_rest(self, trade_msg: Dict[str, Any]):
     """
     Updates in-flight order and trigger order filled event for trade message received from REST API. Triggers order completed
     event if the total executed amount equals to the specified order amount.
     """
     for order in self._in_flight_orders.values():
         await order.get_exchange_order_id()
     track_order = [
         o for o in self._in_flight_orders.values()
         if str(trade_msg["order_id"]) == o.exchange_order_id
     ]
     if not track_order:
         return
     tracked_order = track_order[0]
     (delta_trade_amount, delta_trade_price,
      trade_id) = tracked_order.update_with_trade_update_rest(trade_msg)
     if not delta_trade_amount:
         return
     self.trigger_event(
         MarketEvent.OrderFilled,
         OrderFilledEvent(
             self.current_timestamp,
             tracked_order.client_order_id,
             tracked_order.trading_pair,
             tracked_order.trade_type,
             tracked_order.order_type,
             delta_trade_price,
             delta_trade_amount,
             # TradeFee(0.0, [(trade_msg["fee_coin_name"], Decimal(str(trade_msg["fees"])))]),
             estimate_fee.estimate_fee(
                 self.name, tracked_order.order_type
                 in [OrderType.LIMIT, OrderType.LIMIT_MAKER]),
             exchange_trade_id=trade_id))
     if math.isclose(
             tracked_order.executed_amount_base, tracked_order.amount
     ) or tracked_order.executed_amount_base >= tracked_order.amount:
         tracked_order.last_state = "FILLED"
         self.logger().info(
             f"The {tracked_order.trade_type.name} order "
             f"{tracked_order.client_order_id} has completed "
             f"according to trade status rest API.")
         event_tag = MarketEvent.BuyOrderCompleted if tracked_order.trade_type is TradeType.BUY \
             else MarketEvent.SellOrderCompleted
         event_class = BuyOrderCompletedEvent if tracked_order.trade_type is TradeType.BUY \
             else SellOrderCompletedEvent
         self.trigger_event(
             event_tag,
             event_class(self.current_timestamp,
                         tracked_order.client_order_id,
                         tracked_order.base_asset,
                         tracked_order.quote_asset, tracked_order.fee_asset,
                         tracked_order.executed_amount_base,
                         tracked_order.executed_amount_quote,
                         tracked_order.fee_paid, tracked_order.order_type))
         self.stop_tracking_order(tracked_order.client_order_id)
コード例 #4
0
 def profit_pct(self, account_for_fee: bool = False) -> Decimal:
     """
     Returns a profit in percentage value (e.g. 0.01 for 1% profitability)
     """
     buy = self.first_side if self.first_side.is_buy else self.second_side
     sell = self.first_side if not self.first_side.is_buy else self.second_side
     if buy.quote_price == 0:
         return s_decimal_nan
     if not account_for_fee:
         return (sell.quote_price - buy.quote_price) / buy.quote_price
     buy_trade_fee = estimate_fee(buy.market_info.market.name, False)
     sell_trade_fee = estimate_fee(sell.market_info.market.name, False)
     buy_fee_amount = buy_trade_fee.fee_amount_in_quote(
         buy.market_info.trading_pair, buy.quote_price, buy.amount)
     sell_fee_amount = sell_trade_fee.fee_amount_in_quote(
         sell.market_info.trading_pair, sell.quote_price, sell.amount)
     sell_gained_net = (sell.amount * sell.quote_price) - sell_fee_amount
     buy_spent_net = (buy.amount * buy.quote_price) + buy_fee_amount
     return (
         sell_gained_net - buy_spent_net
     ) / buy_spent_net if buy_spent_net != s_decimal_0 else s_decimal_nan
コード例 #5
0
    def test_estimate_fee(self):
        """
        test the estimate_fee function
        """

        # test against centralized exchanges
        self.assertEqual(
            estimate_fee("kucoin", True),
            AddedToCostTradeFee(percent=Decimal('0.001'), flat_fees=[]))
        self.assertEqual(
            estimate_fee("kucoin", False),
            AddedToCostTradeFee(percent=Decimal('0.001'), flat_fees=[]))
        self.assertEqual(
            estimate_fee("binance", True),
            DeductedFromReturnsTradeFee(percent=Decimal('0.001'),
                                        flat_fees=[]))
        self.assertEqual(
            estimate_fee("binance", False),
            DeductedFromReturnsTradeFee(percent=Decimal('0.001'),
                                        flat_fees=[]))

        # test against decentralized exchanges
        self.assertEqual(
            estimate_fee("beaxy", True),
            AddedToCostTradeFee(percent=Decimal('0.0015'), flat_fees=[]))
        self.assertEqual(
            estimate_fee("beaxy", False),
            AddedToCostTradeFee(percent=Decimal('0.0025'), flat_fees=[]))

        # test against exchanges that do not exist in hummingbot.client.settings.CONNECTOR_SETTINGS
        self.assertRaisesRegex(Exception, "^Invalid connector", estimate_fee,
                               "does_not_exist", True)
        self.assertRaisesRegex(Exception, "Invalid connector", estimate_fee,
                               "does_not_exist", False)
コード例 #6
0
    def profit_pct(self,
                   account_for_fee: bool = False,
                   first_side_quote_eth_rate: Decimal = None,
                   second_side_quote_eth_rate: Decimal = None) -> Decimal:
        """
        Returns a profit in percentage value (e.g. 0.01 for 1% profitability)
        """
        buy = self.first_side if self.first_side.is_buy else self.second_side
        sell = self.first_side if not self.first_side.is_buy else self.second_side
        if buy.quote_price == 0:
            return s_decimal_0
        if not account_for_fee:
            return (sell.quote_price - buy.quote_price) / buy.quote_price
        buy_trade_fee = estimate_fee(buy.market_info.market.name, False)
        sell_trade_fee = estimate_fee(sell.market_info.market.name, False)
        buy_quote_eth_rate = first_side_quote_eth_rate if self.first_side.is_buy else second_side_quote_eth_rate
        sell_quote_eth_rate = first_side_quote_eth_rate if not self.first_side.is_buy else second_side_quote_eth_rate
        if buy_quote_eth_rate is not None and buy_trade_fee.flat_fees[0][
                0].upper() == "ETH":
            buy_fee_amount = buy_trade_fee.flat_fees[0][1] / buy_quote_eth_rate
        else:
            buy_fee_amount = buy_trade_fee.fee_amount_in_quote(
                buy.market_info.trading_pair, buy.quote_price, buy.amount)
        if sell_quote_eth_rate is not None and sell_trade_fee.flat_fees[0][
                0].upper() == "ETH":
            sell_fee_amount = sell_trade_fee.flat_fees[0][
                1] / sell_quote_eth_rate
        else:
            sell_fee_amount = sell_trade_fee.fee_amount_in_quote(
                sell.market_info.trading_pair, sell.quote_price, sell.amount)

        # buy_fee_amount = buy_trade_fee.fee_amount_in_quote(buy.market_info.trading_pair,
        #                                                    buy.quote_price, buy.amount)
        # sell_fee_amount = sell_trade_fee.fee_amount_in_quote(sell.market_info.trading_pair, sell.quote_price,
        #                                                      sell.amount)

        sell_gained_net = (sell.amount * sell.quote_price) - sell_fee_amount
        buy_spent_net = (buy.amount * buy.quote_price) + buy_fee_amount
        return ((sell_gained_net - buy_spent_net) /
                buy_spent_net) if buy_spent_net != s_decimal_0 else s_decimal_0
コード例 #7
0
    def _process_rest_trade_details(self, order_detail_msg: Any):
        for trade_msg in order_detail_msg['detail']:
            """
            Updates in-flight order and trigger order filled event for trade message received. Triggers order completed
            event if the total executed amount equals to the specified order amount.
            """
            # for order in self._in_flight_orders.values():
            #     await order.get_exchange_order_id()
            tracked_order = self.find_exchange_order(trade_msg['order_id'])
            if tracked_order is None:
                return

            updated = tracked_order.update_with_rest_order_detail(trade_msg)
            if not updated:
                return

            self.trigger_event(
                MarketEvent.OrderFilled,
                OrderFilledEvent(
                    self.current_timestamp,
                    tracked_order.client_order_id,
                    tracked_order.trading_pair,
                    tracked_order.trade_type,
                    tracked_order.order_type,
                    Decimal(str(trade_msg["executed_price"])),
                    Decimal(str(trade_msg["executed_amount"])),
                    estimate_fee(
                        self.name, tracked_order.order_type
                        in [OrderType.LIMIT, OrderType.LIMIT_MAKER]),
                    # TradeFee(0.0, [(trade_msg["fee_currency"], Decimal(str(trade_msg["fee"])))]),
                    exchange_trade_id=trade_msg["tid"]))
            if math.isclose(tracked_order.executed_amount_base, tracked_order.amount) or \
                    tracked_order.executed_amount_base >= tracked_order.amount:
                tracked_order.last_state = "FILLED"
                self.logger().info(
                    f"The {tracked_order.trade_type.name} order "
                    f"{tracked_order.client_order_id} has completed "
                    f"according to order status API.")
                event_tag = MarketEvent.BuyOrderCompleted if tracked_order.trade_type is TradeType.BUY \
                    else MarketEvent.SellOrderCompleted
                event_class = BuyOrderCompletedEvent if tracked_order.trade_type is TradeType.BUY \
                    else SellOrderCompletedEvent
                self.trigger_event(
                    event_tag,
                    event_class(self.current_timestamp,
                                tracked_order.client_order_id,
                                tracked_order.base_asset,
                                tracked_order.quote_asset,
                                tracked_order.executed_amount_base,
                                tracked_order.executed_amount_quote,
                                tracked_order.order_type))
                self.stop_tracking_order(tracked_order.client_order_id)
コード例 #8
0
    def apply_budget_constraint(self, proposals: List[Proposal]):
        balances = self._token_balances.copy()
        for proposal in proposals:
            if balances[proposal.base()] < proposal.sell.size:
                proposal.sell.size = balances[proposal.base()]
            proposal.sell.size = self._exchange.quantize_order_amount(proposal.market, proposal.sell.size)
            balances[proposal.base()] -= proposal.sell.size

            quote_size = proposal.buy.size * proposal.buy.price
            quote_size = balances[proposal.quote()] if balances[proposal.quote()] < quote_size else quote_size
            buy_fee = estimate_fee(self._exchange.name, True)
            buy_size = quote_size / (proposal.buy.price * (Decimal("1") + buy_fee.percent))
            proposal.buy.size = self._exchange.quantize_order_amount(proposal.market, buy_size)
            balances[proposal.quote()] -= quote_size
コード例 #9
0
    def _process_order_message_traded(self, order_msg):
        tracked_order: DigifinexInFlightOrder = self.find_exchange_order(
            order_msg['id'])
        if tracked_order is None:
            return

        (delta_trade_amount,
         delta_trade_price) = tracked_order.update_with_order_update(order_msg)
        if not delta_trade_amount:
            return

        self.trigger_event(
            MarketEvent.OrderFilled,
            OrderFilledEvent(
                self.current_timestamp,
                tracked_order.client_order_id,
                tracked_order.trading_pair,
                tracked_order.trade_type,
                tracked_order.order_type,
                delta_trade_price,
                delta_trade_amount,
                estimate_fee(
                    self.name, tracked_order.order_type
                    in [OrderType.LIMIT, OrderType.LIMIT_MAKER]),
                # TradeFee(0.0, [(trade_msg["fee_currency"], Decimal(str(trade_msg["fee"])))]),
                exchange_trade_id=str(int(self._time() * 1e6))))
        if math.isclose(tracked_order.executed_amount_base, tracked_order.amount) or \
                tracked_order.executed_amount_base >= tracked_order.amount:
            tracked_order.last_state = "2"
            self.logger().info(
                f"The {tracked_order.trade_type.name} order "
                f"{tracked_order.client_order_id} has completed "
                f"according to order status API.")
            event_tag = MarketEvent.BuyOrderCompleted if tracked_order.trade_type is TradeType.BUY \
                else MarketEvent.SellOrderCompleted
            event_class = BuyOrderCompletedEvent if tracked_order.trade_type is TradeType.BUY \
                else SellOrderCompletedEvent
            self.trigger_event(
                event_tag,
                event_class(self.current_timestamp,
                            tracked_order.client_order_id,
                            tracked_order.base_asset,
                            tracked_order.quote_asset,
                            tracked_order.executed_amount_base,
                            tracked_order.executed_amount_quote,
                            tracked_order.order_type))
            self.stop_tracking_order(tracked_order.client_order_id)
コード例 #10
0
 def get_fee(self, base_currency: str, quote_currency: str, order_type: object, order_side: object,
             amount: object, price: object):
     is_maker = order_type is OrderType.LIMIT
     return estimate_fee("binance_perpetual", is_maker)
コード例 #11
0
    async def _update_order_status(self):
        """
        Calls REST API to get status update for each in-flight order.
        """
        if len(self._in_flight_orders) > 0:
            tracked_orders = list(self._in_flight_orders.values())

            tasks = []
            for tracked_order in tracked_orders:
                order_id = await tracked_order.get_exchange_order_id()
                tasks.append(self._api_request("post",
                                               "perpfi/receipt",
                                               {"txHash": order_id}))
            update_results = await safe_gather(*tasks, return_exceptions=True)
            for update_result in update_results:
                self.logger().info(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 update_result["confirmed"] is True:
                    if update_result["receipt"]["status"] == 1:
                        fee = estimate_fee("perpetual_finance", False)
                        fee = TradeFee(fee.percent, [("XDAI", Decimal(str(update_result["receipt"]["gasUsed"])))])
                        self.trigger_event(
                            MarketEvent.OrderFilled,
                            OrderFilledEvent(
                                self.current_timestamp,
                                tracked_order.client_order_id,
                                tracked_order.trading_pair,
                                tracked_order.trade_type,
                                tracked_order.order_type,
                                Decimal(str(tracked_order.price)),
                                Decimal(str(tracked_order.amount)),
                                fee,
                                exchange_trade_id=order_id,
                                leverage=self._leverage[tracked_order.trading_pair],
                                position=tracked_order.position
                            )
                        )
                        tracked_order.last_state = "FILLED"
                        self.logger().info(f"The {tracked_order.trade_type.name} order "
                                           f"{tracked_order.client_order_id} has completed "
                                           f"according to order status API.")
                        event_tag = MarketEvent.BuyOrderCompleted if tracked_order.trade_type is TradeType.BUY \
                            else MarketEvent.SellOrderCompleted
                        event_class = BuyOrderCompletedEvent if tracked_order.trade_type is TradeType.BUY \
                            else SellOrderCompletedEvent
                        self.trigger_event(event_tag,
                                           event_class(self.current_timestamp,
                                                       tracked_order.client_order_id,
                                                       tracked_order.base_asset,
                                                       tracked_order.quote_asset,
                                                       tracked_order.fee_asset,
                                                       tracked_order.executed_amount_base,
                                                       tracked_order.executed_amount_quote,
                                                       float(fee.fee_amount_in_quote(tracked_order.trading_pair,
                                                                                     Decimal(str(tracked_order.price)),
                                                                                     Decimal(str(tracked_order.amount)))),  # this ignores the gas fee, which is fine for now
                                                       tracked_order.order_type))
                        self.stop_tracking_order(tracked_order.client_order_id)
                    else:
                        self.logger().info(
                            f"The market order {tracked_order.client_order_id} has failed according to order status API. ")
                        self.trigger_event(MarketEvent.OrderFailure,
                                           MarketOrderFailureEvent(
                                               self.current_timestamp,
                                               tracked_order.client_order_id,
                                               tracked_order.order_type
                                           ))
                        self.stop_tracking_order(tracked_order.client_order_id)