From 2499276fca84123700d34eb023a938651b57c111 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 6 Jul 2022 19:15:55 +0200 Subject: [PATCH] Refactor calculate_fee_rate to take separate parameters instead of an "Order" we passed in a trade object anyway --- freqtrade/exchange/exchange.py | 49 +++++++++++++++++++++------------ freqtrade/freqtradebot.py | 7 +++-- tests/exchange/test_exchange.py | 5 ++-- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 4febe5652..ced1c71fb 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1631,27 +1631,30 @@ class Exchange: and order['fee']['cost'] is not None ) - def calculate_fee_rate(self, order: Dict) -> Optional[float]: + def calculate_fee_rate( + self, fee: Dict, symbol: str, cost: float, amount: float) -> Optional[float]: """ Calculate fee rate if it's not given by the exchange. - :param order: Order or trade (one trade) dict + :param fee: ccxt Fee dict - must contain cost / currency / rate + :param symbol: Symbol of the order + :param cost: Total cost of the order + :param amount: Amount of the order """ - if order['fee'].get('rate') is not None: - return order['fee'].get('rate') - fee_curr = order['fee']['currency'] + if fee.get('rate') is not None: + return fee.get('rate') + fee_curr = fee['currency'] # Calculate fee based on order details - if fee_curr in self.get_pair_base_currency(order['symbol']): + if fee_curr in self.get_pair_base_currency(symbol): # Base currency - divide by amount - return round( - order['fee']['cost'] / safe_value_fallback2(order, order, 'filled', 'amount'), 8) - elif fee_curr in self.get_pair_quote_currency(order['symbol']): + return round(fee['cost'] / amount, 8) + elif fee_curr in self.get_pair_quote_currency(symbol): # Quote currency - divide by cost return round(self._contracts_to_amount( - order['symbol'], order['fee']['cost']) / order['cost'], - 8) if order['cost'] else None + symbol, fee['cost']) / cost, + 8) if cost else None else: # If Fee currency is a different currency - if not order['cost']: + if not cost: # If cost is None or 0.0 -> falsy, return None return None try: @@ -1664,18 +1667,28 @@ class Exchange: if not fee_to_quote_rate: return None return round((self._contracts_to_amount( - order['symbol'], order['fee']['cost']) * fee_to_quote_rate) / order['cost'], 8) + symbol, fee['cost']) * fee_to_quote_rate) / cost, 8) - def extract_cost_curr_rate(self, order: Dict) -> Tuple[float, str, Optional[float]]: + def extract_cost_curr_rate(self, fee: Dict, symbol: str, cost: float, + amount: float) -> Tuple[float, str, Optional[float]]: """ Extract tuple of cost, currency, rate. Requires order_has_fee to run first! - :param order: Order or trade (one trade) dict + :param fee: ccxt Fee dict - must contain cost / currency / rate + :param symbol: Symbol of the order + :param cost: Total cost of the order + :param amount: Amount of the order :return: Tuple with cost, currency, rate of the given fee dict """ - return (order['fee']['cost'], - order['fee']['currency'], - self.calculate_fee_rate(order)) + return (fee['cost'], + fee['currency'], + self.calculate_fee_rate( + fee, + symbol, + cost, + amount + ) + ) # Historic data diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index d1404807d..e0532a17d 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1742,7 +1742,8 @@ class FreqtradeBot(LoggingMixin): trade_base_currency = self.exchange.get_pair_base_currency(trade.pair) # use fee from order-dict if possible if self.exchange.order_has_fee(order): - fee_cost, fee_currency, fee_rate = self.exchange.extract_cost_curr_rate(order) + fee_cost, fee_currency, fee_rate = self.exchange.extract_cost_curr_rate( + order['fee'], order['symbol'], order['cost'], order_obj.safe_filled) logger.info(f"Fee for Trade {trade} [{order_obj.ft_order_side}]: " f"{fee_cost:.8g} {fee_currency} - rate: {fee_rate}") if fee_rate is None or fee_rate < 0.02: @@ -1780,7 +1781,9 @@ class FreqtradeBot(LoggingMixin): for exectrade in trades: amount += exectrade['amount'] if self.exchange.order_has_fee(exectrade): - fee_cost_, fee_currency, fee_rate_ = self.exchange.extract_cost_curr_rate(exectrade) + fee_cost_, fee_currency, fee_rate_ = self.exchange.extract_cost_curr_rate( + exectrade['fee'], exectrade['symbol'], exectrade['cost'], exectrade['amount'] + ) fee_cost += fee_cost_ if fee_rate_ is not None: fee_rate_array.append(fee_rate_) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 708a0e889..0dc1b1741 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -3544,7 +3544,7 @@ def test_order_has_fee(order, expected) -> None: def test_extract_cost_curr_rate(mocker, default_conf, order, expected) -> None: mocker.patch('freqtrade.exchange.Exchange.calculate_fee_rate', MagicMock(return_value=0.01)) ex = get_patched_exchange(mocker, default_conf) - assert ex.extract_cost_curr_rate(order) == expected + assert ex.extract_cost_curr_rate(order['fee'], order['symbol'], cost=20, amount=1) == expected @pytest.mark.parametrize("order,unknown_fee_rate,expected", [ @@ -3590,7 +3590,8 @@ def test_calculate_fee_rate(mocker, default_conf, order, expected, unknown_fee_r ex = get_patched_exchange(mocker, default_conf) - assert ex.calculate_fee_rate(order) == expected + assert ex.calculate_fee_rate(order['fee'], order['symbol'], + cost=order['cost'], amount=order['amount']) == expected @pytest.mark.parametrize('retrycount,max_retries,expected', [