From db540dc99078fce9ca48652f472ca43fba8cf0ee Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 20 Feb 2022 14:21:22 +0100 Subject: [PATCH] Orders should also store fee if in receiving currency --- freqtrade/freqtradebot.py | 10 ++++++---- freqtrade/persistence/models.py | 16 +++++++++++++--- tests/test_freqtradebot.py | 10 ++++++++-- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index f2b076532..e44193f21 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1357,8 +1357,8 @@ class FreqtradeBot(LoggingMixin): # Handling of this will happen in check_handle_timedout. return True - order = self.handle_order_fee(trade, order) order_obj = trade.select_order_by_order_id(order_id) + order = self.handle_order_fee(trade, order_obj, order) if not order_obj: # TODO: this can't happen! raise OperationalException(f"order-obj for {order_id} not found!") @@ -1415,14 +1415,16 @@ class FreqtradeBot(LoggingMixin): return real_amount return amount - def handle_order_fee(self, trade: Trade, order: Dict[str, Any]) -> Dict[str, Any]: + def handle_order_fee(self, trade: Trade, order_obj: Order, order: Dict[str, Any]) -> Dict[str, Any]: # Try update amount (binance-fix) try: new_amount = self.get_real_amount(trade, order) if not isclose(safe_value_fallback(order, 'filled', 'amount'), new_amount, abs_tol=constants.MATH_CLOSE_PREC): - order['amount'] = new_amount - order.pop('filled', None) + # TODO: ?? + # order['amount'] = new_amount + order_obj.ft_fee_base = trade.amount - new_amount + # order.pop('filled', None) except DependencyException as exception: logger.warning("Could not update trade amount: %s", exception) return order diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 731d57262..0ee50d1c7 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -132,6 +132,8 @@ class Order(_DECL_BASE): order_filled_date = Column(DateTime, nullable=True) order_update_date = Column(DateTime, nullable=True) + ft_fee_base = Column(Float, nullable=True) + @property def order_date_utc(self) -> datetime: """ Order-date with UTC timezoneinfo""" @@ -143,7 +145,15 @@ class Order(_DECL_BASE): @property def safe_filled(self) -> float: - return self.filled or self.amount + return self.filled or self.amount or 0.0 + + @property + def safe_fee_base(self) -> float: + return self.ft_fee_base or 0.0 + + @property + def safe_amount_after_fee(self) -> float: + return self.safe_filled - self.safe_fee_base def __repr__(self): @@ -477,7 +487,7 @@ class LocalTrade(): if order.ft_order_side == 'buy': # Update open rate and actual amount self.open_rate = order.safe_price - self.amount = order.safe_filled + self.amount = order.safe_amount_after_fee if self.is_open: logger.info(f'{order.order_type.upper()}_BUY has been fulfilled for {self}.') self.open_order_id = None @@ -637,7 +647,7 @@ class LocalTrade(): (o.status not in NON_OPEN_EXCHANGE_STATES)): continue - tmp_amount = o.amount + tmp_amount = o.safe_amount_after_fee tmp_price = o.average or o.price if o.filled is not None: tmp_amount = o.filled diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 3effce2f5..735a95231 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1729,9 +1729,14 @@ def test_update_trade_state_withorderdict(default_conf_usdt, trades_for_order, l ) freqtrade.update_trade_state(trade, order_id, limit_buy_order_usdt) assert trade.amount != amount - assert trade.amount == limit_buy_order_usdt['amount'] + log_text = r'Applying fee on amount for .*' if has_rounding_fee: - assert log_has_re(r'Applying fee on amount for .*', caplog) + assert pytest.approx(trade.amount) == 29.992 + assert log_has_re(log_text, caplog) + else: + assert pytest.approx(trade.amount) == limit_buy_order_usdt['amount'] + assert not log_has_re(log_text, caplog) + def test_update_trade_state_exception(mocker, default_conf_usdt, @@ -2319,6 +2324,7 @@ def test_check_handle_timedout_partial_fee(default_conf_usdt, ticker_usdt, open_ limit_buy_order_old_partial_canceled, mocker) -> None: rpc_mock = patch_RPCManager(mocker) limit_buy_order_old_partial['id'] = open_trade.open_order_id + limit_buy_order_old_partial_canceled['id'] = open_trade.open_order_id cancel_order_mock = MagicMock(return_value=limit_buy_order_old_partial_canceled) mocker.patch('freqtrade.wallets.Wallets.get_free', MagicMock(return_value=0)) patch_exchange(mocker)