From f8d30abd79fec7948e4ce7376e144c2f97bea739 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 10 Nov 2021 19:43:36 +0100 Subject: [PATCH] Handle order returns that contain trades directly binance market orders - and potentially other exchanges --- freqtrade/freqtradebot.py | 13 ++++++++----- tests/conftest.py | 40 ++++++++++++++++++++++++++++++++++++++ tests/test_freqtradebot.py | 25 ++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 4e004a6ab..db0453cd7 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1381,14 +1381,17 @@ 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) + return self.fee_detection_from_trades(trade, order, order_amount, order.get('trades', [])) - def fee_detection_from_trades(self, trade: Trade, order: Dict, order_amount: float) -> float: + def fee_detection_from_trades(self, trade: Trade, order: Dict, order_amount: float, + trades: List) -> float: """ - fee-detection fallback to Trades. Parses result of fetch_my_trades to get correct fee. + fee-detection fallback to Trades. + Either uses provided trades list or the result of fetch_my_trades to get correct fee. """ - trades = self.exchange.get_trades_for_order(self.exchange.get_order_id_conditional(order), - trade.pair, trade.open_date) + if not trades: + trades = self.exchange.get_trades_for_order( + self.exchange.get_order_id_conditional(order), trade.pair, trade.open_date) if len(trades) == 0: logger.info("Applying fee on amount for %s failed: myTrade-Dict empty found", trade) diff --git a/tests/conftest.py b/tests/conftest.py index 698c464ed..751cb5f9f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2221,6 +2221,46 @@ def market_buy_order_usdt(): } +@pytest.fixture +def market_buy_order_usdt_doublefee(market_buy_order_usdt): + order = deepcopy(market_buy_order_usdt) + order['fee'] = None + # Market orders filled with 2 trades can have fees in different currencies + # assuming the account runs out of BNB. + order['fees'] = [ + {'cost': 0.00025125, 'currency': 'BNB'}, + {'cost': 0.05030681, 'currency': 'USDT'}, + ] + order['trades'] = [{ + 'timestamp': None, + 'datetime': None, + 'symbol': 'ETH/USDT', + 'id': None, + 'order': '123', + 'type': 'market', + 'side': 'sell', + 'takerOrMaker': None, + 'price': 2.01, + 'amount': 25.0, + 'cost': 50.25, + 'fee': {'cost': 0.00025125, 'currency': 'BNB'} + }, { + 'timestamp': None, + 'datetime': None, + 'symbol': 'ETH/USDT', + 'id': None, + 'order': '123', + 'type': 'market', + 'side': 'sell', + 'takerOrMaker': None, + 'price': 2.0, + 'amount': 5, + 'cost': 10, + 'fee': {'cost': 0.0100306, 'currency': 'USDT'} + }] + return order + + @pytest.fixture def market_sell_order_usdt(): return { diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 0e49590a4..1f9b1d6b3 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3634,6 +3634,31 @@ def test_get_real_amount_invalid_order(default_conf_usdt, trades_for_order, buy_ assert freqtrade.get_real_amount(trade, limit_buy_order_usdt) == amount +def test_get_real_amount_fees_order(default_conf_usdt, market_buy_order_usdt_doublefee, + fee, mocker): + + tfo_mock = mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[]) + mocker.patch('freqtrade.exchange.Exchange.get_valid_pair_combination', return_value='BNB/USDT') + mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', return_value={'last': 200}) + trade = Trade( + pair='LTC/USDT', + amount=30.0, + exchange='binance', + fee_open=fee.return_value, + fee_close=fee.return_value, + open_rate=0.245441, + open_order_id="123456" + ) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) + + # Amount does not change + assert trade.fee_open == 0.0025 + assert freqtrade.get_real_amount(trade, market_buy_order_usdt_doublefee) == 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 + + def test_get_real_amount_wrong_amount(default_conf_usdt, trades_for_order, buy_order_fee, fee, mocker): limit_buy_order_usdt = deepcopy(buy_order_fee)