From 2533d3b42064037523a23d041eae88d235ea5651 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Mon, 18 Oct 2021 01:37:42 -0600 Subject: [PATCH] Added get_funding_rate_history method to exchange --- freqtrade/exchange/exchange.py | 46 ++++++++++++++++++++++++++++++- freqtrade/exchange/gateio.py | 12 ++++++++ freqtrade/optimize/backtesting.py | 6 ++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 70ed6f184..2192005b5 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -75,6 +75,7 @@ class Exchange: # funding_fee_times is currently unused, but should ideally be used to properly # schedule refresh times funding_fee_times: List[int] = [] # hours of the day + funding_rate_history: Dict = {} _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ # TradingMode.SPOT always supported and not required in this list @@ -1636,13 +1637,17 @@ class Exchange: raise OperationalException(e) from e def _get_mark_price(self, pair: str, date: datetime) -> float: + """ + Get's the mark price for a pair at a specific date and time in the past + """ + # TODO-lev: Can maybe use self._api.fetchFundingRate, or get the most recent candlestick raise OperationalException(f'_get_mark_price has not been implemented on {self.name}') def _get_funding_rate(self, pair: str, when: datetime): """ Get's the funding_rate for a pair at a specific date and time in the past """ - # TODO-lev: implement + # TODO-lev: Maybe use self._api.fetchFundingRate or fetchFundingRateHistory with length 1 raise OperationalException(f"get_funding_rate has not been implemented for {self.name}") def _get_funding_fee( @@ -1749,6 +1754,45 @@ class Exchange: return fees + def get_funding_rate_history( + self, + start: int, + end: int + ) -> Dict: + ''' + :param start: timestamp in ms of the beginning time + :param end: timestamp in ms of the end time + ''' + if not self.exchange_has("fetchFundingRateHistory"): + raise ExchangeError( + f"CCXT has not implemented fetchFundingRateHistory for {self.name}; " + f"therefore, backtesting for {self.name} is currently unavailable" + ) + + try: + funding_history: Dict = {} + for pair, market in self.markets.items(): + if market['swap']: + response = self._api.fetch_funding_rate_history( + pair, + limit=1000, + since=start, + params={ + 'endTime': end + } + ) + funding_history[pair] = {} + for fund in response: + funding_history[pair][fund['timestamp']] = fund['funding_rate'] + return funding_history + except ccxt.DDoSProtection as e: + raise DDosProtection(e) from e + except (ccxt.NetworkError, ccxt.ExchangeError) as e: + raise TemporaryError( + f'Could not set margin mode due to {e.__class__.__name__}. Message: {e}') from e + except ccxt.BaseError as e: + raise OperationalException(e) from e + def is_exchange_known_ccxt(exchange_name: str, ccxt_module: CcxtModuleType = None) -> bool: return exchange_name in ccxt_exchanges(ccxt_module) diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index 33006d4a5..f025ed4dd 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -33,3 +33,15 @@ class Gateio(Exchange): if any(v == 'market' for k, v in order_types.items()): raise OperationalException( f'Exchange {self.name} does not support market orders.') + + def get_funding_rate_history( + self, + start: int, + end: int + ) -> Dict: + ''' + :param start: timestamp in ms of the beginning time + :param end: timestamp in ms of the end time + ''' + # TODO-lev: Has a max limit into the past of 333 days + return super().get_funding_rate_history(start, end) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index aaf875a94..a5f63c396 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -3,6 +3,7 @@ """ This module contains the backtesting logic """ +import ccxt import logging from collections import defaultdict from copy import deepcopy @@ -125,6 +126,11 @@ class Backtesting: self.progress = BTProgress() self.abort = False + + self.funding_rate_history = getattr(ccxt, self._exchange_name).load_funding_rate_history( + self.timerange.startts, + self.timerange.stopts + ) self.init_backtest() def __del__(self):