Add get_option to expose ft_has via method

This commit is contained in:
Matthias 2022-08-21 17:48:13 +02:00
parent 87a3115073
commit f6d832c6d9
6 changed files with 22 additions and 16 deletions

View File

@ -81,7 +81,7 @@ def start_download_data(args: Dict[str, Any]) -> None:
data_format_trades=config['dataformat_trades'], data_format_trades=config['dataformat_trades'],
) )
else: else:
if not exchange._ft_has.get('ohlcv_has_history', True): if not exchange.get_option('ohlcv_has_history', True):
raise OperationalException( raise OperationalException(
f"Historic klines not available for {exchange.name}. " f"Historic klines not available for {exchange.name}. "
"Please use `--dl-trades` instead for this exchange " "Please use `--dl-trades` instead for this exchange "

View File

@ -302,8 +302,8 @@ def refresh_backtest_ohlcv_data(exchange: Exchange, pairs: List[str], timeframes
if trading_mode == 'futures': if trading_mode == 'futures':
# Predefined candletype (and timeframe) depending on exchange # Predefined candletype (and timeframe) depending on exchange
# Downloads what is necessary to backtest based on futures data. # Downloads what is necessary to backtest based on futures data.
tf_mark = exchange._ft_has['mark_ohlcv_timeframe'] tf_mark = exchange.get_option('mark_ohlcv_timeframe')
fr_candle_type = CandleType.from_string(exchange._ft_has['mark_ohlcv_price']) fr_candle_type = CandleType.from_string(exchange.get_option('mark_ohlcv_price'))
# All exchanges need FundingRate for futures trading. # All exchanges need FundingRate for futures trading.
# The timeframe is aligned to the mark-price timeframe. # The timeframe is aligned to the mark-price timeframe.
for funding_candle_type in (CandleType.FUNDING_RATE, fr_candle_type): for funding_candle_type in (CandleType.FUNDING_RATE, fr_candle_type):

View File

@ -674,6 +674,12 @@ class Exchange:
f"Freqtrade does not support {mm_value} {trading_mode.value} on {self.name}" 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: def exchange_has(self, endpoint: str) -> bool:
""" """
Checks if exchange implements a specific API endpoint. Checks if exchange implements a specific API endpoint.

View File

@ -267,7 +267,7 @@ class Backtesting:
funding_rates_dict = history.load_data( funding_rates_dict = history.load_data(
datadir=self.config['datadir'], datadir=self.config['datadir'],
pairs=self.pairlists.whitelist, pairs=self.pairlists.whitelist,
timeframe=self.exchange._ft_has['mark_ohlcv_timeframe'], timeframe=self.exchange.get_option('mark_ohlcv_timeframe'),
timerange=self.timerange, timerange=self.timerange,
startup_candles=0, startup_candles=0,
fail_without_data=True, fail_without_data=True,
@ -279,12 +279,12 @@ class Backtesting:
mark_rates_dict = history.load_data( mark_rates_dict = history.load_data(
datadir=self.config['datadir'], datadir=self.config['datadir'],
pairs=self.pairlists.whitelist, pairs=self.pairlists.whitelist,
timeframe=self.exchange._ft_has['mark_ohlcv_timeframe'], timeframe=self.exchange.get_option('mark_ohlcv_timeframe'),
timerange=self.timerange, timerange=self.timerange,
startup_candles=0, startup_candles=0,
fail_without_data=True, fail_without_data=True,
data_format=self.config.get('dataformat_ohlcv', 'json'), 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. # Combine data to avoid combining the data per trade.
unavailable_pairs = [] unavailable_pairs = []

View File

@ -73,7 +73,7 @@ class VolumePairList(IPairList):
if (not self._use_range and not ( if (not self._use_range and not (
self._exchange.exchange_has('fetchTickers') self._exchange.exchange_has('fetchTickers')
and self._exchange._ft_has["tickers_have_quoteVolume"])): and self._exchange.get_option("tickers_have_quoteVolume"))):
raise OperationalException( raise OperationalException(
"Exchange does not support dynamic whitelist in this configuration. " "Exchange does not support dynamic whitelist in this configuration. "
"Please edit your config and either remove Volumepairlist, " "Please edit your config and either remove Volumepairlist, "
@ -193,7 +193,7 @@ class VolumePairList(IPairList):
) in candles else None ) in candles else None
# in case of candle data calculate typical price and quoteVolume for candle # in case of candle data calculate typical price and quoteVolume for candle
if pair_candles is not None and not pair_candles.empty: 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['typical_price'] = (pair_candles['high'] + pair_candles['low']
+ pair_candles['close']) / 3 + pair_candles['close']) / 3

View File

@ -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) 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' assert api_mock.fetch_l2_order_book.call_args_list[0][0][0] == 'ETH/BTC'
# Not all exchanges support all limits for orderbook # 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 assert api_mock.fetch_l2_order_book.call_args_list[0][0][1] == val
else: 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 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) ex = Kraken(default_conf)
assert ex._ft_has != Exchange._ft_has_default assert ex._ft_has != Exchange._ft_has_default
assert ex._ft_has['trades_pagination'] == 'id' assert ex.get_option('trades_pagination') == 'id'
assert ex._ft_has['trades_pagination_arg'] == 'since' assert ex.get_option('trades_pagination_arg') == 'since'
# Binance defines different values # Binance defines different values
ex = Binance(default_conf) ex = Binance(default_conf)
assert ex._ft_has != Exchange._ft_has_default assert ex._ft_has != Exchange._ft_has_default
assert ex._ft_has['stoploss_on_exchange'] assert ex.get_option('stoploss_on_exchange')
assert ex._ft_has['order_time_in_force'] == ['gtc', 'fok', 'ioc'] assert ex.get_option('order_time_in_force') == ['gtc', 'fok', 'ioc']
assert ex._ft_has['trades_pagination'] == 'id' assert ex.get_option('trades_pagination') == 'id'
assert ex._ft_has['trades_pagination_arg'] == 'fromId' assert ex.get_option('trades_pagination_arg') == 'fromId'
conf = copy.deepcopy(default_conf) conf = copy.deepcopy(default_conf)
conf['exchange']['_ft_has_params'] = {"DeadBeef": 20, conf['exchange']['_ft_has_params'] = {"DeadBeef": 20,