diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 928429629..6f45b6f4c 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1606,7 +1606,7 @@ class Exchange: until=until, from_id=from_id)) @retrier - def get_funding_fees_from_exchange(self, pair: str, since: Union[datetime, int]) -> float: + def _get_funding_fees_from_exchange(self, pair: str, since: Union[datetime, int]) -> float: """ Returns the sum of all funding fees that were exchanged for a pair within a timeframe :param pair: (e.g. ADA/USDT) @@ -1794,7 +1794,7 @@ class Exchange: raise OperationalException(f'Could not fetch historical mark price candle (OHLCV) data ' f'for pair {pair}. Message: {e}') from e - def calculate_funding_fees( + def _calculate_funding_fees( self, pair: str, amount: float, @@ -1825,16 +1825,43 @@ class Exchange: funding_fee_dates = self._get_funding_fee_dates(open_date, close_date) for date in funding_fee_dates: timestamp = int(date.timestamp()) * 1000 - funding_rate = funding_rate_history[timestamp] - mark_price = mark_price_history[timestamp] - fees += self._get_funding_fee( - size=amount, - mark_price=mark_price, - funding_rate=funding_rate - ) + if timestamp in funding_rate_history: + funding_rate = funding_rate_history[timestamp] + else: + logger.warning( + f"Funding rate for {pair} at {date} not found in funding_rate_history" + f"Funding fee calculation may be incorrect" + ) + if timestamp in mark_price_history: + mark_price = mark_price_history[timestamp] + else: + logger.warning( + f"Mark price for {pair} at {date} not found in funding_rate_history" + f"Funding fee calculation may be incorrect" + ) + if funding_rate and mark_price: + fees += self._get_funding_fee( + size=amount, + mark_price=mark_price, + funding_rate=funding_rate + ) return fees + def get_funding_fees(self, pair: str, amount: float, open_date: datetime): + if self._config['dry_run']: + funding_fees = self._calculate_funding_fees( + pair, + amount, + open_date + ) + else: + funding_fees = self._get_funding_fees_from_exchange( + pair, + open_date + ) + return funding_fees + @retrier def get_funding_rate_history( self, diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index cfd3ae3fd..defc02a6c 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -270,17 +270,11 @@ class FreqtradeBot(LoggingMixin): if self.trading_mode == TradingMode.FUTURES: trades = Trade.get_open_trades() for trade in trades: - if self.config['dry_run']: - funding_fees = self.exchange.calculate_funding_fees( - trade.pair, - trade.amount, - trade.open_date - ) - else: - funding_fees = self.exchange.get_funding_fees_from_exchange( - trade.pair, - trade.open_date - ) + funding_fees = self.exchange.get_funding_fees( + trade.pair, + trade.amount, + trade.open_date + ) trade.funding_fees = funding_fees def startup_update_open_orders(self): @@ -712,7 +706,7 @@ class FreqtradeBot(LoggingMixin): fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker') open_date = datetime.now(timezone.utc) if self.trading_mode == TradingMode.FUTURES: - funding_fees = self.exchange.get_funding_fees_from_exchange(pair, open_date) + funding_fees = self.exchange.get_funding_fees(pair, amount, open_date) else: funding_fees = 0.0 diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 00b2897e9..611d09254 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -3058,7 +3058,7 @@ def test_calculate_backoff(retrycount, max_retries, expected): @pytest.mark.parametrize("exchange_name", ['binance', 'ftx']) -def test_get_funding_fees_from_exchange(default_conf, mocker, exchange_name): +def test__get_funding_fees_from_exchange(default_conf, mocker, exchange_name): api_mock = MagicMock() api_mock.fetch_funding_history = MagicMock(return_value=[ { @@ -3101,11 +3101,11 @@ def test_get_funding_fees_from_exchange(default_conf, mocker, exchange_name): date_time = datetime.strptime("2021-09-01T00:00:01.000Z", '%Y-%m-%dT%H:%M:%S.%fZ') unix_time = int(date_time.timestamp()) expected_fees = -0.001 # 0.14542341 + -0.14642341 - fees_from_datetime = exchange.get_funding_fees_from_exchange( + fees_from_datetime = exchange._get_funding_fees_from_exchange( pair='XRP/USDT', since=date_time ) - fees_from_unix_time = exchange.get_funding_fees_from_exchange( + fees_from_unix_time = exchange._get_funding_fees_from_exchange( pair='XRP/USDT', since=unix_time ) @@ -3118,7 +3118,7 @@ def test_get_funding_fees_from_exchange(default_conf, mocker, exchange_name): default_conf, api_mock, exchange_name, - "get_funding_fees_from_exchange", + "_get_funding_fees_from_exchange", "fetch_funding_history", pair="XRP/USDT", since=unix_time @@ -3519,7 +3519,7 @@ def test_get_funding_rate_history(mocker, default_conf, funding_rate_history): ('binance', "2021-09-01 00:00:00", "2021-09-01 07:59:59", 30.0, -0.0006647999999999999), ('binance', "2021-09-01 00:00:00", "2021-09-01 12:00:00", 30.0, -0.0009140999999999999), ('binance', "2021-09-01 00:00:01", "2021-09-01 08:00:00", 30.0, -0.0009140999999999999), - # TODO: Uncoment once calculate_funding_fees can pass time_in_ratio to exchange._get_funding_fee + # TODO: Uncoment once _calculate_funding_fees can pas time_in_ratio to exchange._get_funding_fee # ('kraken', "2021-09-01 00:00:00", "2021-09-01 08:00:00", 30.0, -0.0014937), # ('kraken', "2021-09-01 00:00:15", "2021-09-01 08:00:00", 30.0, -0.0008289), # ('kraken', "2021-09-01 01:00:14", "2021-09-01 08:00:00", 30.0, -0.0008289), @@ -3533,11 +3533,11 @@ def test_get_funding_rate_history(mocker, default_conf, funding_rate_history): ('gateio', "2021-09-01 00:00:00", "2021-09-01 12:00:00", 30.0, -0.0009140999999999999), ('gateio', "2021-09-01 00:00:01", "2021-09-01 08:00:00", 30.0, -0.0002493), ('binance', "2021-09-01 00:00:00", "2021-09-01 08:00:00", 50.0, -0.0015235000000000001), - # TODO: Uncoment once calculate_funding_fees can pass time_in_ratio to exchange._get_funding_fee + # TODO: Uncoment once _calculate_funding_fees can pas time_in_ratio to exchange._get_funding_fee # ('kraken', "2021-09-01 00:00:00", "2021-09-01 08:00:00", 50.0, -0.0024895), ('ftx', "2021-09-01 00:00:00", "2021-09-01 08:00:00", 50.0, 0.0016680000000000002), ]) -def test_calculate_funding_fees( +def test__calculate_funding_fees( mocker, default_conf, funding_rate_history, @@ -3592,18 +3592,18 @@ def test_calculate_funding_fees( type(api_mock).has = PropertyMock(return_value={'fetchFundingRateHistory': True}) exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange) - funding_fees = exchange.calculate_funding_fees('ADA/USDT', amount, d1, d2) + funding_fees = exchange._calculate_funding_fees('ADA/USDT', amount, d1, d2) assert funding_fees == expected_fees @pytest.mark.parametrize('name,expected_fees_8,expected_fees_10,expected_fees_12', [ ('binance', -0.0009140999999999999, -0.0009140999999999999, -0.0009140999999999999), - # TODO: Uncoment once calculate_funding_fees can pass time_in_ratio to exchange._get_funding_fee + # TODO: Uncoment once _calculate_funding_fees can pas time_in_ratio to exchange._get_funding_fee # ('kraken', -0.0014937, -0.0014937, 0.0045759), ('ftx', 0.0010008000000000003, 0.0021084, 0.0146691), ('gateio', -0.0009140999999999999, -0.0009140999999999999, -0.0009140999999999999), ]) -def test_calculate_funding_fees_datetime_called( +def test__calculate_funding_fees_datetime_called( mocker, default_conf, funding_rate_history, @@ -3624,11 +3624,11 @@ def test_calculate_funding_fees_datetime_called( d1 = datetime.strptime("2021-09-01 00:00:00 +0000", '%Y-%m-%d %H:%M:%S %z') time_machine.move_to("2021-09-01 08:00:00 +00:00") - funding_fees = exchange.calculate_funding_fees('ADA/USDT', 30.0, d1) + funding_fees = exchange._calculate_funding_fees('ADA/USDT', 30.0, d1) assert funding_fees == expected_fees_8 time_machine.move_to("2021-09-01 10:00:00 +00:00") - funding_fees = exchange.calculate_funding_fees('ADA/USDT', 30.0, d1) + funding_fees = exchange._calculate_funding_fees('ADA/USDT', 30.0, d1) assert funding_fees == expected_fees_10 time_machine.move_to("2021-09-01 12:00:00 +00:00") - funding_fees = exchange.calculate_funding_fees('ADA/USDT', 30.0, d1) + funding_fees = exchange._calculate_funding_fees('ADA/USDT', 30.0, d1) assert funding_fees == expected_fees_12