def _get_fee(self, base_currency: str, quote_currency: str, order_type: OrderType, order_side: TradeType, amount: Decimal, price: Decimal = s_decimal_NaN, is_maker: Optional[bool] = None) -> AddedToCostTradeFee: is_maker = is_maker or (order_type is OrderType.LIMIT_MAKER) trading_pair = combine_to_hb_trading_pair(base=base_currency, quote=quote_currency) if trading_pair in self._trading_fees: fees_data = self._trading_fees[trading_pair] fee_value = Decimal( fees_data["makerFeeRate"]) if is_maker else Decimal( fees_data["takerFeeRate"]) fee = AddedToCostTradeFee(percent=fee_value) else: fee = build_trade_fee( self.name, is_maker, base_currency=base_currency, quote_currency=quote_currency, order_type=order_type, order_side=order_side, amount=amount, price=price, ) return fee
def get_fee(self, base_currency: str, quote_currency: str, order_type: OrderType, order_side: TradeType, amount: Decimal, price: Decimal = s_decimal_NaN, is_maker: Optional[bool] = None) -> TradeFeeBase: """ Calculates the estimated fee an order would pay based on the connector configuration :param base_currency: the order base currency :param quote_currency: the order quote currency :param order_type: the type of order (MARKET, LIMIT, LIMIT_MAKER) :param order_side: if the order is for buying or selling :param amount: the order amount :param price: the order price :return: the estimated fee for the order """ """ To get trading fee, this function is simplified by using fee override configuration. Most parameters to this function are ignore except order_type. Use OrderType.LIMIT_MAKER to specify you want trading fee for maker order. """ is_maker = order_type is OrderType.LIMIT_MAKER trade_base_fee = build_trade_fee(exchange=self.name, is_maker=is_maker, order_side=order_side, order_type=order_type, amount=amount, price=price, base_currency=base_currency, quote_currency=quote_currency) return trade_base_fee
def _get_fee(self, exchange: 'ExchangeBase') -> TradeFeeBase: trading_pair = self.trading_pair price = self.price base, quote = split_hb_trading_pair(trading_pair) fee = build_trade_fee( exchange.name, self.is_maker, base, quote, self.order_type, self.order_side, self.amount, price, ) return fee
def _get_fee(self, base_currency: str, quote_currency: str, order_type: OrderType, order_side: TradeType, amount: Decimal, price: Decimal = s_decimal_NaN, is_maker: Optional[bool] = None) -> TradeFeeBase: """ Calculates the estimated fee an order would pay based on the connector configuration :param base_currency: the order base currency :param quote_currency: the order quote currency :param order_type: the type of order (MARKET, LIMIT, LIMIT_MAKER) :param order_side: if the order is for buying or selling :param amount: the order amount :param price: the order price :param is_maker: if we take into account maker fee (True) or taker fee (None, False) :return: the estimated fee for the order """ trading_pair = combine_to_hb_trading_pair(base=base_currency, quote=quote_currency) fee_schema = self._trading_fees.get(trading_pair, None) if fee_schema is None: self.logger().warning( f"For trading pair = {trading_pair} there is no fee schema loaded, using presets!" ) fee = build_trade_fee(exchange=self.name, is_maker=is_maker, base_currency=base_currency, quote_currency=quote_currency, order_type=order_type, order_side=order_side, amount=amount, price=price) else: if fee_schema.type == LatokenTakeType.PROPORTION or fee_schema.take == LatokenCommissionType.PERCENT: pass # currently not implemented but is nice to have in next release(s) percent = fee_schema.maker_fee if order_type is OrderType.LIMIT_MAKER or ( is_maker is not None and is_maker) else fee_schema.taker_fee fee = AddedToCostTradeFee( percent=percent ) if order_side == TradeType.BUY else DeductedFromReturnsTradeFee( percent=percent) return fee
def get_fee(self, base_currency: str, quote_currency: str, order_type: OrderType, order_side: TradeType, amount: Decimal, price: Decimal = s_decimal_NaN, is_maker: Optional[bool] = None) -> AddedToCostTradeFee: """ Calculates the fee to pay based on the fee information provided by the exchange for the account and the token pair. If exchange info is not available it calculates the estimated fee an order would pay based on the connector configuration :param base_currency: the order base currency :param quote_currency: the order quote currency :param order_type: the type of order (MARKET, LIMIT, LIMIT_MAKER) :param order_side: if the order is for buying or selling :param amount: the order amount :param price: the order price :param is_maker: True if the order is a maker order, False if it is a taker order :return: the calculated or estimated fee """ is_maker = is_maker or (order_type is OrderType.LIMIT_MAKER) trading_pair = combine_to_hb_trading_pair(base=base_currency, quote=quote_currency) if trading_pair in self._trading_fees: fees_data = self._trading_fees[trading_pair] fee_value = Decimal(fees_data["makerFeeRate"]) if is_maker else Decimal(fees_data["takerFeeRate"]) fee = AddedToCostTradeFee(percent=fee_value) else: fee = build_trade_fee( self.name, is_maker, base_currency=base_currency, quote_currency=quote_currency, order_type=order_type, order_side=order_side, amount=amount, price=price, ) return fee
def _get_fee(self, base_currency: str, quote_currency: str, order_type: OrderType, order_side: TradeType, amount: Decimal, price: Decimal = s_decimal_NaN, is_maker: Optional[bool] = None) -> TradeFeeBase: is_maker = is_maker or (order_type is OrderType.LIMIT_MAKER) fee = build_trade_fee( self.name, is_maker, base_currency=base_currency, quote_currency=quote_currency, order_type=order_type, order_side=order_side, amount=amount, price=price, ) return fee
def profit_pct( self, rate_source: Optional[RateOracle] = None, account_for_fee: bool = False, ) -> 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 """ if not rate_source: rate_source = RateOracle.get_instance() buy_side: ArbProposalSide = self.first_side if self.first_side.is_buy else self.second_side sell_side: ArbProposalSide = self.first_side if not self.first_side.is_buy else self.second_side base_conversion_pair: str = f"{sell_side.market_info.base_asset}-{buy_side.market_info.base_asset}" quote_conversion_pair: str = f"{sell_side.market_info.quote_asset}-{buy_side.market_info.quote_asset}" sell_base_to_buy_base_rate: Decimal = Decimal(1) sell_quote_to_buy_quote_rate: Decimal = rate_source.rate(quote_conversion_pair) buy_fee_amount: Decimal = s_decimal_0 sell_fee_amount: Decimal = s_decimal_0 result: Decimal = s_decimal_0 if sell_quote_to_buy_quote_rate and sell_base_to_buy_base_rate: if account_for_fee: buy_trade_fee: TradeFeeBase = build_trade_fee( exchange=buy_side.market_info.market.name, is_maker=False, base_currency=buy_side.market_info.base_asset, quote_currency=buy_side.market_info.quote_asset, order_type=OrderType.MARKET, order_side=TradeType.BUY, amount=buy_side.amount, price=buy_side.order_price, extra_flat_fees=buy_side.extra_flat_fees ) sell_trade_fee: TradeFeeBase = build_trade_fee( exchange=sell_side.market_info.market.name, is_maker=False, base_currency=sell_side.market_info.base_asset, quote_currency=sell_side.market_info.quote_asset, order_type=OrderType.MARKET, order_side=TradeType.SELL, amount=sell_side.amount, price=sell_side.order_price, extra_flat_fees=sell_side.extra_flat_fees ) buy_fee_amount: Decimal = buy_trade_fee.fee_amount_in_token( trading_pair=buy_side.market_info.trading_pair, price=buy_side.quote_price, order_amount=buy_side.amount, token=buy_side.market_info.quote_asset, rate_source=rate_source ) sell_fee_amount: Decimal = sell_trade_fee.fee_amount_in_token( trading_pair=sell_side.market_info.trading_pair, price=sell_side.quote_price, order_amount=sell_side.amount, token=sell_side.market_info.quote_asset, rate_source=rate_source ) buy_spent_net: Decimal = (buy_side.amount * buy_side.quote_price) + buy_fee_amount sell_gained_net: Decimal = (sell_side.amount * sell_side.quote_price) - sell_fee_amount sell_gained_net_in_buy_quote_currency: Decimal = ( sell_gained_net * sell_quote_to_buy_quote_rate / sell_base_to_buy_base_rate ) result: Decimal = ( ((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
def _update_inflight_order(self, tracked_order: BitmexInFlightOrder, event: Dict[str, Any]): trading_pair_multiplier = self._trading_pair_to_multipliers[ tracked_order.trading_pair] event["amount_remaining"] = Decimal(str( event["leavesQty"])) / trading_pair_multiplier.base_multiplier issuable_events: List[MarketEvent] = tracked_order.update(event) # Issue relevent events for (market_event, new_amount, new_price, new_fee) in issuable_events: base, quote = self.split_trading_pair(tracked_order.trading_pair) if market_event == MarketEvent.OrderFilled: self.trigger_event( ORDER_FILLED_EVENT, OrderFilledEvent( self.current_timestamp, tracked_order.client_order_id, tracked_order.trading_pair, tracked_order.trade_type, tracked_order.order_type, new_price, new_amount, build_trade_fee(self._domain, True, base, quote, tracked_order.order_type, tracked_order.trade_type, new_amount, new_price), tracked_order.client_order_id)) elif market_event == MarketEvent.OrderCancelled: self.logger().info( f"Successfully cancelled order {tracked_order.client_order_id}" ) self.stop_tracking_order(tracked_order.client_order_id) self.trigger_event( ORDER_CANCELLED_EVENT, OrderCancelledEvent(self.current_timestamp, tracked_order.client_order_id)) elif market_event == MarketEvent.BuyOrderCompleted: self.logger().info( f"The market buy order {tracked_order.client_order_id} has completed " f"according to user stream.") self.trigger_event( BUY_ORDER_COMPLETED_EVENT, BuyOrderCompletedEvent(self.current_timestamp, tracked_order.client_order_id, base, quote, tracked_order.executed_amount_base, tracked_order.executed_amount_quote, tracked_order.order_type, tracked_order.exchange_order_id)) elif market_event == MarketEvent.SellOrderCompleted: self.logger().info( f"The market sell order {tracked_order.client_order_id} has completed " f"according to user stream.") self.trigger_event( SELL_ORDER_COMPLETED_EVENT, SellOrderCompletedEvent( self.current_timestamp, tracked_order.client_order_id, base, quote, tracked_order.executed_amount_base, tracked_order.executed_amount_quote, tracked_order.order_type, tracked_order.exchange_order_id)) # Complete the order if relevent if tracked_order.is_done: self.stop_tracking_order(tracked_order.client_order_id)