diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index 36a86bece..ce26d39ab 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -81,7 +81,7 @@ def start_download_data(args: Dict[str, Any]) -> None: data_format_trades=config['dataformat_trades'], ) else: - if not exchange._ft_has.get('ohlcv_has_history', True): + if not exchange.get_option('ohlcv_has_history', True): raise OperationalException( f"Historic klines not available for {exchange.name}. " "Please use `--dl-trades` instead for this exchange " diff --git a/freqtrade/data/history/history_utils.py b/freqtrade/data/history/history_utils.py index cba1b60db..04d0bf6d3 100644 --- a/freqtrade/data/history/history_utils.py +++ b/freqtrade/data/history/history_utils.py @@ -302,8 +302,8 @@ def refresh_backtest_ohlcv_data(exchange: Exchange, pairs: List[str], timeframes if trading_mode == 'futures': # Predefined candletype (and timeframe) depending on exchange # Downloads what is necessary to backtest based on futures data. - tf_mark = exchange._ft_has['mark_ohlcv_timeframe'] - fr_candle_type = CandleType.from_string(exchange._ft_has['mark_ohlcv_price']) + tf_mark = exchange.get_option('mark_ohlcv_timeframe') + fr_candle_type = CandleType.from_string(exchange.get_option('mark_ohlcv_price')) # All exchanges need FundingRate for futures trading. # The timeframe is aligned to the mark-price timeframe. for funding_candle_type in (CandleType.FUNDING_RATE, fr_candle_type): diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 7ef6858a5..a2944c784 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -674,6 +674,12 @@ class Exchange: f"Freqtrade does not support {mm_value} {trading_mode.value} on {self.name}" ) + def get_option(self, param: str, default: Any = None) -> Any: + """ + Get parameter value from _ft_has + """ + return self._ft_has.get(param, default) + def exchange_has(self, endpoint: str) -> bool: """ Checks if exchange implements a specific API endpoint. diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 12536c333..e32eae533 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -267,7 +267,7 @@ class Backtesting: funding_rates_dict = history.load_data( datadir=self.config['datadir'], pairs=self.pairlists.whitelist, - timeframe=self.exchange._ft_has['mark_ohlcv_timeframe'], + timeframe=self.exchange.get_option('mark_ohlcv_timeframe'), timerange=self.timerange, startup_candles=0, fail_without_data=True, @@ -279,12 +279,12 @@ class Backtesting: mark_rates_dict = history.load_data( datadir=self.config['datadir'], pairs=self.pairlists.whitelist, - timeframe=self.exchange._ft_has['mark_ohlcv_timeframe'], + timeframe=self.exchange.get_option('mark_ohlcv_timeframe'), timerange=self.timerange, startup_candles=0, fail_without_data=True, data_format=self.config.get('dataformat_ohlcv', 'json'), - candle_type=CandleType.from_string(self.exchange._ft_has["mark_ohlcv_price"]) + candle_type=CandleType.from_string(self.exchange.get_option("mark_ohlcv_price")) ) # Combine data to avoid combining the data per trade. unavailable_pairs = [] diff --git a/freqtrade/plugins/pairlist/VolumePairList.py b/freqtrade/plugins/pairlist/VolumePairList.py index e364e1a69..8138a5fb6 100644 --- a/freqtrade/plugins/pairlist/VolumePairList.py +++ b/freqtrade/plugins/pairlist/VolumePairList.py @@ -73,7 +73,7 @@ class VolumePairList(IPairList): if (not self._use_range and not ( self._exchange.exchange_has('fetchTickers') - and self._exchange._ft_has["tickers_have_quoteVolume"])): + and self._exchange.get_option("tickers_have_quoteVolume"))): raise OperationalException( "Exchange does not support dynamic whitelist in this configuration. " "Please edit your config and either remove Volumepairlist, " @@ -193,7 +193,7 @@ class VolumePairList(IPairList): ) in candles else None # in case of candle data calculate typical price and quoteVolume for candle if pair_candles is not None and not pair_candles.empty: - if self._exchange._ft_has["ohlcv_volume_currency"] == "base": + if self._exchange.get_option("ohlcv_volume_currency") == "base": pair_candles['typical_price'] = (pair_candles['high'] + pair_candles['low'] + pair_candles['close']) / 3 diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index ec259d703..4f9c92efc 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2352,10 +2352,10 @@ def test_fetch_l2_order_book(default_conf, mocker, order_book_l2, exchange_name) order_book = exchange.fetch_l2_order_book(pair='ETH/BTC', limit=val) assert api_mock.fetch_l2_order_book.call_args_list[0][0][0] == 'ETH/BTC' # Not all exchanges support all limits for orderbook - if not exchange._ft_has['l2_limit_range'] or val in exchange._ft_has['l2_limit_range']: + if not exchange.get_option('l2_limit_range') or val in exchange.get_option('l2_limit_range'): assert api_mock.fetch_l2_order_book.call_args_list[0][0][1] == val else: - next_limit = exchange.get_next_limit_in_list(val, exchange._ft_has['l2_limit_range']) + next_limit = exchange.get_next_limit_in_list(val, exchange.get_option('l2_limit_range')) assert api_mock.fetch_l2_order_book.call_args_list[0][0][1] == next_limit @@ -3311,16 +3311,16 @@ def test_merge_ft_has_dict(default_conf, mocker): ex = Kraken(default_conf) assert ex._ft_has != Exchange._ft_has_default - assert ex._ft_has['trades_pagination'] == 'id' - assert ex._ft_has['trades_pagination_arg'] == 'since' + assert ex.get_option('trades_pagination') == 'id' + assert ex.get_option('trades_pagination_arg') == 'since' # Binance defines different values ex = Binance(default_conf) assert ex._ft_has != Exchange._ft_has_default - assert ex._ft_has['stoploss_on_exchange'] - assert ex._ft_has['order_time_in_force'] == ['gtc', 'fok', 'ioc'] - assert ex._ft_has['trades_pagination'] == 'id' - assert ex._ft_has['trades_pagination_arg'] == 'fromId' + assert ex.get_option('stoploss_on_exchange') + assert ex.get_option('order_time_in_force') == ['gtc', 'fok', 'ioc'] + assert ex.get_option('trades_pagination') == 'id' + assert ex.get_option('trades_pagination_arg') == 'fromId' conf = copy.deepcopy(default_conf) conf['exchange']['_ft_has_params'] = {"DeadBeef": 20,