diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 04861d2b2..5af8d2657 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1885,6 +1885,7 @@ class Exchange: self, pair: str, amount: float, + is_short: bool, open_date: datetime, close_date: Optional[datetime] = None ) -> float: @@ -1894,6 +1895,7 @@ class Exchange: Only used during dry-run or if the exchange does not provide a funding_rates endpoint. :param pair: The quote/base pair of the trade :param amount: The quantity of the trade + :param is_short: trade direction :param open_date: The date and time that the trade started :param close_date: The date and time that the trade ended """ @@ -1928,6 +1930,7 @@ class Exchange: return self.calculate_funding_fees( funding_mark_rates, amount=amount, + is_short=is_short, open_date=open_date, close_date=close_date ) @@ -1946,6 +1949,7 @@ class Exchange: self, df: DataFrame, amount: float, + is_short: bool, open_date: datetime, close_date: Optional[datetime] = None, time_in_ratio: Optional[float] = None @@ -1955,6 +1959,7 @@ class Exchange: :param df: Dataframe containing combined funding and mark rates as `open_fund` and `open_mark`. :param amount: The quantity of the trade + :param is_short: trade direction :param open_date: The date and time that the trade started :param close_date: The date and time that the trade ended :param time_in_ratio: Not used by most exchange classes @@ -1965,19 +1970,23 @@ class Exchange: df = df[(df['date'] >= open_date) & (df['date'] <= close_date)] fees = sum(df['open_fund'] * df['open_mark'] * amount) - return fees + # Negate fees for longs as funding_fees expects it this way based on live endpoints. + return fees if is_short else -fees - def get_funding_fees(self, pair: str, amount: float, open_date: datetime) -> float: + def get_funding_fees( + self, pair: str, amount: float, is_short: bool, open_date: datetime) -> float: """ Fetch funding fees, either from the exchange (live) or calculates them based on funding rate/mark price history :param pair: The quote/base pair of the trade + :param is_short: trade direction :param amount: Trade amount :param open_date: Open date of the trade """ if self.trading_mode == TradingMode.FUTURES: if self._config['dry_run']: - funding_fees = self._fetch_and_calculate_funding_fees(pair, amount, open_date) + funding_fees = self._fetch_and_calculate_funding_fees( + pair, amount, is_short, open_date) else: funding_fees = self._get_funding_fees_from_exchange(pair, open_date) return funding_fees diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index ef52cc797..10535a909 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -163,6 +163,7 @@ class Kraken(Exchange): self, df: DataFrame, amount: float, + is_short: bool, open_date: datetime, close_date: Optional[datetime] = None, time_in_ratio: Optional[float] = None @@ -176,6 +177,7 @@ class Kraken(Exchange): :param df: Dataframe containing combined funding and mark rates as `open_fund` and `open_mark`. :param amount: The quantity of the trade + :param is_short: trade direction :param open_date: The date and time that the trade started :param close_date: The date and time that the trade ended :param time_in_ratio: Not used by most exchange classes diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index ce9255854..7b7508854 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -273,9 +273,10 @@ class FreqtradeBot(LoggingMixin): trades = Trade.get_open_trades() for trade in trades: funding_fees = self.exchange.get_funding_fees( - trade.pair, - trade.amount, - trade.open_date + pair=trade.pair, + amount=trade.amount, + is_short=trade.is_short, + open_date=trade.open_date ) trade.funding_fees = funding_fees else: @@ -741,7 +742,8 @@ class FreqtradeBot(LoggingMixin): # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker') open_date = datetime.now(timezone.utc) - funding_fees = self.exchange.get_funding_fees(pair, amount, open_date) + funding_fees = self.exchange.get_funding_fees( + pair=pair, amount=amount, is_short=is_short, open_date=open_date) # This is a new trade if trade is None: trade = Trade( @@ -1379,9 +1381,10 @@ class FreqtradeBot(LoggingMixin): :return: True if it succeeds (supported) False (not supported) """ trade.funding_fees = self.exchange.get_funding_fees( - trade.pair, - trade.amount, - trade.open_date + pair=trade.pair, + amount=trade.amount, + is_short=trade.is_short, + open_date=trade.open_date, ) exit_type = 'sell' if sell_reason.sell_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS): diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 347aca907..bedb83d1a 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -495,6 +495,7 @@ class Backtesting: trade.funding_fees = self.exchange.calculate_funding_fees( self.futures_data[trade.pair], amount=trade.amount, + is_short=trade.is_short, open_date=trade.open_date_utc, close_date=sell_candle_time, ) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 498aad942..382847b21 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -3567,6 +3567,7 @@ def test_calculate_funding_fees( assert exchange.calculate_funding_fees( df, amount=size, + is_short=True, open_date=trade_date, close_date=trade_date, time_in_ratio=time_in_ratio, @@ -3577,6 +3578,7 @@ def test_calculate_funding_fees( kraken.calculate_funding_fees( df, amount=size, + is_short=True, open_date=trade_date, close_date=trade_date, time_in_ratio=time_in_ratio, @@ -3586,6 +3588,7 @@ def test_calculate_funding_fees( assert kraken.calculate_funding_fees( df, amount=size, + is_short=True, open_date=trade_date, close_date=trade_date, time_in_ratio=time_in_ratio, @@ -3681,7 +3684,8 @@ def test__fetch_and_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._fetch_and_calculate_funding_fees('ADA/USDT', amount, d1, d2) + # TODO-lev: test this for longs + funding_fees = exchange._fetch_and_calculate_funding_fees('ADA/USDT', amount, True, d1, d2) assert pytest.approx(funding_fees) == expected_fees @@ -3709,7 +3713,8 @@ def test__fetch_and_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._fetch_and_calculate_funding_fees('ADA/USDT', 30.0, d1) + # TODO-lev: test this for longs + funding_fees = exchange._fetch_and_calculate_funding_fees('ADA/USDT', 30.0, True, d1) assert funding_fees == expected_fees