diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 16864f814..1c2b7208f 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1428,14 +1428,14 @@ class FreqtradeBot(LoggingMixin): def handle_order_fee(self, trade: Trade, order_obj: Order, order: Dict[str, Any]) -> None: # Try update amount (binance-fix) try: - new_amount = self.get_real_amount(trade, order) + new_amount = self.get_real_amount(trade, order, order_obj) if not isclose(safe_value_fallback(order, 'filled', 'amount'), new_amount, abs_tol=constants.MATH_CLOSE_PREC): order_obj.ft_fee_base = trade.amount - new_amount except DependencyException as exception: logger.warning("Could not update trade amount: %s", exception) - def get_real_amount(self, trade: Trade, order: Dict) -> float: + def get_real_amount(self, trade: Trade, order: Dict, order_obj: Order) -> float: """ Detect and update trade fee. Calls trade.update_fee() upon correct detection. @@ -1453,7 +1453,7 @@ class FreqtradeBot(LoggingMixin): # 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) - logger.info(f"Fee for Trade {trade} [{order.get('side')}]: " + 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: # Reject all fees that report as > 2%. @@ -1465,17 +1465,18 @@ class FreqtradeBot(LoggingMixin): return self.apply_fee_conditional(trade, trade_base_currency, amount=order_amount, fee_abs=fee_cost) return order_amount - return self.fee_detection_from_trades(trade, order, order_amount, order.get('trades', [])) + return self.fee_detection_from_trades( + trade, order, order_obj, order_amount, order.get('trades', [])) - def fee_detection_from_trades(self, trade: Trade, order: Dict, order_amount: float, - trades: List) -> float: + def fee_detection_from_trades(self, trade: Trade, order: Dict, order_obj: Order, + order_amount: float, trades: List) -> float: """ fee-detection fallback to Trades. Either uses provided trades list or the result of fetch_my_trades to get correct fee. """ if not trades: trades = self.exchange.get_trades_for_order( - self.exchange.get_order_id_conditional(order), trade.pair, trade.open_date) + self.exchange.get_order_id_conditional(order), trade.pair, order_obj.order_date) if len(trades) == 0: logger.info("Applying fee on amount for %s failed: myTrade-Dict empty found", trade) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 1aeb56cdd..bafed8488 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3568,9 +3568,9 @@ def test_get_real_amount_quote(default_conf_usdt, trades_for_order, buy_order_fe open_order_id="123456" ) freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) - + order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy') # Amount is reduced by "fee" - assert freqtrade.get_real_amount(trade, buy_order_fee) == amount - (amount * 0.001) + assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == amount - (amount * 0.001) assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, ' 'open_rate=0.24544100, open_since=closed) (from 8.0 to 7.992).', caplog) @@ -3594,8 +3594,9 @@ def test_get_real_amount_quote_dust(default_conf_usdt, trades_for_order, buy_ord freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) walletmock.reset_mock() + order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy') # Amount is kept as is - assert freqtrade.get_real_amount(trade, buy_order_fee) == amount + assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == amount assert walletmock.call_count == 1 assert log_has_re(r'Fee amount for Trade.* was in base currency ' '- Eating Fee 0.008 into dust', caplog) @@ -3616,8 +3617,9 @@ def test_get_real_amount_no_trade(default_conf_usdt, buy_order_fee, caplog, mock ) freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) + order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy') # Amount is reduced by "fee" - assert freqtrade.get_real_amount(trade, buy_order_fee) == amount + assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == amount assert log_has('Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, ' 'open_rate=0.24544100, open_since=closed) failed: myTrade-Dict empty found', caplog) @@ -3668,7 +3670,8 @@ def test_get_real_amount( mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', side_effect=ExchangeError) caplog.clear() - assert freqtrade.get_real_amount(trade, buy_order) == amount - fee_reduction_amount + order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy') + assert freqtrade.get_real_amount(trade, buy_order, order_obj) == amount - fee_reduction_amount if expected_log: assert log_has(expected_log, caplog) @@ -3715,7 +3718,8 @@ def test_get_real_amount_multi( # Amount is reduced by "fee" expected_amount = amount - (amount * fee_reduction_amount) - assert freqtrade.get_real_amount(trade, buy_order_fee) == expected_amount + order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy') + assert freqtrade.get_real_amount(trade, buy_order_fee, order_obj) == expected_amount assert log_has( ( 'Applying fee on amount for Trade(id=None, pair=LTC/ETH, amount=8.00000000, ' @@ -3750,8 +3754,9 @@ def test_get_real_amount_invalid_order(default_conf_usdt, trades_for_order, buy_ ) freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) + order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy') # Amount does not change - assert freqtrade.get_real_amount(trade, limit_buy_order_usdt) == amount + assert freqtrade.get_real_amount(trade, limit_buy_order_usdt, order_obj) == amount def test_get_real_amount_fees_order(default_conf_usdt, market_buy_order_usdt_doublefee, @@ -3773,7 +3778,8 @@ def test_get_real_amount_fees_order(default_conf_usdt, market_buy_order_usdt_dou # Amount does not change assert trade.fee_open == 0.0025 - assert freqtrade.get_real_amount(trade, market_buy_order_usdt_doublefee) == 30.0 + order_obj = Order.parse_from_ccxt_object(market_buy_order_usdt_doublefee, 'LTC/ETH', 'buy') + assert freqtrade.get_real_amount(trade, market_buy_order_usdt_doublefee, order_obj) == 30.0 assert tfo_mock.call_count == 0 # Fetch fees from trades dict if available to get "proper" values assert round(trade.fee_open, 4) == 0.001 @@ -3797,9 +3803,10 @@ def test_get_real_amount_wrong_amount(default_conf_usdt, trades_for_order, buy_o ) freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) + order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy') # Amount does not change with pytest.raises(DependencyException, match=r"Half bought\? Amounts don't match"): - freqtrade.get_real_amount(trade, limit_buy_order_usdt) + freqtrade.get_real_amount(trade, limit_buy_order_usdt, order_obj) def test_get_real_amount_wrong_amount_rounding(default_conf_usdt, trades_for_order, buy_order_fee, @@ -3821,9 +3828,10 @@ def test_get_real_amount_wrong_amount_rounding(default_conf_usdt, trades_for_ord ) freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) + order_obj = Order.parse_from_ccxt_object(buy_order_fee, 'LTC/ETH', 'buy') # Amount changes by fee amount. assert isclose( - freqtrade.get_real_amount(trade, limit_buy_order_usdt), + freqtrade.get_real_amount(trade, limit_buy_order_usdt, order_obj), amount - (amount * 0.001), abs_tol=MATH_CLOSE_PREC, ) @@ -3847,7 +3855,8 @@ def test_get_real_amount_open_trade(default_conf_usdt, fee, mocker): 'side': 'buy', } freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) - assert freqtrade.get_real_amount(trade, order) == amount + order_obj = Order.parse_from_ccxt_object(order, 'LTC/ETH', 'buy') + assert freqtrade.get_real_amount(trade, order, order_obj) == amount @pytest.mark.parametrize('amount,fee_abs,wallet,amount_exp', [