From ef3a1ea8f251dd1723bc4a3ef9d8e16175c410f8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 8 Jan 2022 11:01:14 +0100 Subject: [PATCH] Split funding fee calculation from Download --- freqtrade/exchange/exchange.py | 34 ++++++++++++++++++++++++++---- tests/exchange/test_ccxt_compat.py | 2 +- tests/exchange/test_exchange.py | 8 +++---- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index d8ccc9972..e94521706 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1900,7 +1900,7 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - def _calculate_funding_fees( + def _fetch_and_calculate_funding_fees( self, pair: str, amount: float, @@ -1908,7 +1908,8 @@ class Exchange: close_date: Optional[datetime] = None ) -> float: """ - calculates the sum of all funding fees that occurred for a pair during a futures trade + Fetches and calculates the sum of all funding fees that occurred for a pair + during a futures trade. 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 @@ -1923,7 +1924,6 @@ class Exchange: self._ft_has['mark_ohlcv_timeframe']) open_date = timeframe_to_prev_date(timeframe, open_date) - fees: float = 0 if not close_date: close_date = datetime.now(timezone.utc) open_timestamp = int(open_date.timestamp()) * 1000 @@ -1942,6 +1942,32 @@ class Exchange: funding_rates = candle_histories[funding_comb] mark_rates = candle_histories[mark_comb] + return self._calculate_funding_fees( + funding_rates=funding_rates, + mark_rates=mark_rates, + amount=amount, + open_date=open_date, + close_date=close_date + ) + + def _calculate_funding_fees( + self, + funding_rates: DataFrame, + mark_rates: DataFrame, + amount: float, + open_date: datetime, + close_date: Optional[datetime] = None + ) -> float: + """ + calculates the sum of all funding fees that occurred for a pair during a futures trade + :param funding_rates: Dataframe containing Funding rates (Type FUNDING_RATE) + :param mark_rates: Dataframe containing Mark rates (Type mark_ohlcv_price) + :param amount: The quantity of the trade + :param open_date: The date and time that the trade started + :param close_date: The date and time that the trade ended + """ + fees: float = 0 + df = funding_rates.merge(mark_rates, on='date', how="inner", suffixes=["_fund", "_mark"]) if not df.empty: df = df[(df['date'] >= open_date) & (df['date'] <= close_date)] @@ -1959,7 +1985,7 @@ class Exchange: """ if self.trading_mode == TradingMode.FUTURES: if self._config['dry_run']: - funding_fees = self._calculate_funding_fees(pair, amount, open_date) + funding_fees = self._fetch_and_calculate_funding_fees(pair, amount, open_date) else: funding_fees = self._get_funding_fees_from_exchange(pair, open_date) return funding_fees diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index b3ebfd747..37551b3c5 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -280,7 +280,7 @@ class TestCCXTExchange(): pair = EXCHANGES[exchangename].get('futures_pair', EXCHANGES[exchangename]['pair']) since = datetime.now(timezone.utc) - timedelta(days=5) - funding_fee = exchange._calculate_funding_fees(pair, 20, open_date=since) + funding_fee = exchange._fetch_and_calculate_funding_fees(pair, 20, open_date=since) assert isinstance(funding_fee, float) # assert funding_fee > 0 diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index e1f93f62d..29bee6a39 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -3588,7 +3588,7 @@ def test__get_funding_fee( # ('kraken', "2021-09-01 00:00:00", "2021-09-01 08:00:00", 50.0, -0.0024895), ('ftx', 0, 9, "2021-09-01 00:00:00", "2021-09-01 08:00:00", 50.0, 0.0016680000000000002), ]) -def test__calculate_funding_fees( +def test__fetch_and_calculate_funding_fees( mocker, default_conf, funding_rate_history_hourly, @@ -3651,7 +3651,7 @@ 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._fetch_and_calculate_funding_fees('ADA/USDT', amount, d1, d2) assert pytest.approx(funding_fees) == expected_fees @@ -3659,7 +3659,7 @@ def test__calculate_funding_fees( ('binance', -0.0009140999999999999), ('gateio', -0.0009140999999999999), ]) -def test__calculate_funding_fees_datetime_called( +def test__fetch_and_calculate_funding_fees_datetime_called( mocker, default_conf, funding_rate_history_octohourly, @@ -3679,7 +3679,7 @@ 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._fetch_and_calculate_funding_fees('ADA/USDT', 30.0, d1) assert funding_fees == expected_fees