mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-11-29 08:33:07 +00:00
Simplify load_exchange interface
This commit is contained in:
@@ -52,7 +52,7 @@ def start_download_data(args: Dict[str, Any]) -> None:
|
|||||||
pairs_not_available: List[str] = []
|
pairs_not_available: List[str] = []
|
||||||
|
|
||||||
# Init exchange
|
# Init exchange
|
||||||
exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False)
|
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
||||||
markets = [p for p, m in exchange.markets.items() if market_is_active(m)
|
markets = [p for p, m in exchange.markets.items() if market_is_active(m)
|
||||||
or config.get('include_inactive')]
|
or config.get('include_inactive')]
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ def start_convert_trades(args: Dict[str, Any]) -> None:
|
|||||||
"Please check the documentation on how to configure this.")
|
"Please check the documentation on how to configure this.")
|
||||||
|
|
||||||
# Init exchange
|
# Init exchange
|
||||||
exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False)
|
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
||||||
# Manual validations of relevant settings
|
# Manual validations of relevant settings
|
||||||
if not config['exchange'].get('skip_pair_validation', False):
|
if not config['exchange'].get('skip_pair_validation', False):
|
||||||
exchange.validate_pairs(config['pairs'])
|
exchange.validate_pairs(config['pairs'])
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ def start_list_timeframes(args: Dict[str, Any]) -> None:
|
|||||||
config['timeframe'] = None
|
config['timeframe'] = None
|
||||||
|
|
||||||
# Init exchange
|
# Init exchange
|
||||||
exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False)
|
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
||||||
|
|
||||||
if args['print_one_column']:
|
if args['print_one_column']:
|
||||||
print('\n'.join(exchange.timeframes))
|
print('\n'.join(exchange.timeframes))
|
||||||
@@ -133,7 +133,7 @@ def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None:
|
|||||||
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
|
||||||
|
|
||||||
# Init exchange
|
# Init exchange
|
||||||
exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False)
|
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
||||||
|
|
||||||
# By default only active pairs/markets are to be shown
|
# By default only active pairs/markets are to be shown
|
||||||
active_only = not args.get('list_pairs_all', False)
|
active_only = not args.get('list_pairs_all', False)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ def start_test_pairlist(args: Dict[str, Any]) -> None:
|
|||||||
from freqtrade.plugins.pairlistmanager import PairListManager
|
from freqtrade.plugins.pairlistmanager import PairListManager
|
||||||
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
|
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
|
||||||
|
|
||||||
exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False)
|
exchange = ExchangeResolver.load_exchange(config, validate=False)
|
||||||
|
|
||||||
quote_currencies = args.get('quote_currencies')
|
quote_currencies = args.get('quote_currencies')
|
||||||
if not quote_currencies:
|
if not quote_currencies:
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
validate_config_consistency(config)
|
validate_config_consistency(config)
|
||||||
|
|
||||||
self.exchange = ExchangeResolver.load_exchange(
|
self.exchange = ExchangeResolver.load_exchange(
|
||||||
self.config['exchange']['name'], self.config, load_leverage_tiers=True)
|
self.config, load_leverage_tiers=True)
|
||||||
|
|
||||||
init_db(self.config['db_url'])
|
init_db(self.config['db_url'])
|
||||||
|
|
||||||
|
|||||||
@@ -89,8 +89,7 @@ class Backtesting:
|
|||||||
self.rejected_df: Dict[str, Dict] = {}
|
self.rejected_df: Dict[str, Dict] = {}
|
||||||
|
|
||||||
self._exchange_name = self.config['exchange']['name']
|
self._exchange_name = self.config['exchange']['name']
|
||||||
self.exchange = ExchangeResolver.load_exchange(
|
self.exchange = ExchangeResolver.load_exchange(self.config, load_leverage_tiers=True)
|
||||||
self._exchange_name, self.config, load_leverage_tiers=True)
|
|
||||||
self.dataprovider = DataProvider(self.config, self.exchange)
|
self.dataprovider = DataProvider(self.config, self.exchange)
|
||||||
|
|
||||||
if self.config.get('strategy_list'):
|
if self.config.get('strategy_list'):
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class EdgeCli:
|
|||||||
# Ensure using dry-run
|
# Ensure using dry-run
|
||||||
self.config['dry_run'] = True
|
self.config['dry_run'] = True
|
||||||
self.config['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
|
self.config['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
|
||||||
self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config)
|
self.exchange = ExchangeResolver.load_exchange(self.config)
|
||||||
self.strategy = StrategyResolver.load_strategy(self.config)
|
self.strategy = StrategyResolver.load_strategy(self.config)
|
||||||
self.strategy.dp = DataProvider(config, self.exchange)
|
self.strategy.dp = DataProvider(config, self.exchange)
|
||||||
|
|
||||||
|
|||||||
@@ -633,7 +633,7 @@ def load_and_plot_trades(config: Config):
|
|||||||
"""
|
"""
|
||||||
strategy = StrategyResolver.load_strategy(config)
|
strategy = StrategyResolver.load_strategy(config)
|
||||||
|
|
||||||
exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config)
|
exchange = ExchangeResolver.load_exchange(config)
|
||||||
IStrategy.dp = DataProvider(config, exchange)
|
IStrategy.dp = DataProvider(config, exchange)
|
||||||
strategy.ft_bot_start()
|
strategy.ft_bot_start()
|
||||||
strategy.bot_loop_start(datetime.now(timezone.utc))
|
strategy.bot_loop_start(datetime.now(timezone.utc))
|
||||||
@@ -678,7 +678,7 @@ def plot_profit(config: Config) -> None:
|
|||||||
if 'timeframe' not in config:
|
if 'timeframe' not in config:
|
||||||
raise OperationalException('Timeframe must be set in either config or via --timeframe.')
|
raise OperationalException('Timeframe must be set in either config or via --timeframe.')
|
||||||
|
|
||||||
exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config)
|
exchange = ExchangeResolver.load_exchange(config)
|
||||||
plot_elements = init_plotscript(config, list(exchange.markets))
|
plot_elements = init_plotscript(config, list(exchange.markets))
|
||||||
trades = plot_elements['trades']
|
trades = plot_elements['trades']
|
||||||
# Filter trades to relevant pairs
|
# Filter trades to relevant pairs
|
||||||
|
|||||||
@@ -19,13 +19,14 @@ class ExchangeResolver(IResolver):
|
|||||||
object_type = Exchange
|
object_type = Exchange
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_exchange(exchange_name: str, config: Config, validate: bool = True,
|
def load_exchange(config: Config, validate: bool = True,
|
||||||
load_leverage_tiers: bool = False) -> Exchange:
|
load_leverage_tiers: bool = False) -> Exchange:
|
||||||
"""
|
"""
|
||||||
Load the custom class from config parameter
|
Load the custom class from config parameter
|
||||||
:param exchange_name: name of the Exchange to load
|
:param exchange_name: name of the Exchange to load
|
||||||
:param config: configuration dictionary
|
:param config: configuration dictionary
|
||||||
"""
|
"""
|
||||||
|
exchange_name: str = config['exchange']['name']
|
||||||
# Map exchange name to avoid duplicate classes for identical exchanges
|
# Map exchange name to avoid duplicate classes for identical exchanges
|
||||||
exchange_name = MAP_EXCHANGE_CHILDCLASS.get(exchange_name, exchange_name)
|
exchange_name = MAP_EXCHANGE_CHILDCLASS.get(exchange_name, exchange_name)
|
||||||
exchange_name = exchange_name.title()
|
exchange_name = exchange_name.title()
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ def get_exchange(config=Depends(get_config)):
|
|||||||
if not ApiServer._exchange:
|
if not ApiServer._exchange:
|
||||||
from freqtrade.resolvers import ExchangeResolver
|
from freqtrade.resolvers import ExchangeResolver
|
||||||
ApiServer._exchange = ExchangeResolver.load_exchange(
|
ApiServer._exchange = ExchangeResolver.load_exchange(
|
||||||
config['exchange']['name'], config, load_leverage_tiers=False)
|
config, load_leverage_tiers=False)
|
||||||
return ApiServer._exchange
|
return ApiServer._exchange
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ def get_patched_exchange(mocker, config, api_mock=None, id='binance',
|
|||||||
patch_exchange(mocker, api_mock, id, mock_markets, mock_supported_modes)
|
patch_exchange(mocker, api_mock, id, mock_markets, mock_supported_modes)
|
||||||
config['exchange']['name'] = id
|
config['exchange']['name'] = id
|
||||||
try:
|
try:
|
||||||
exchange = ExchangeResolver.load_exchange(id, config, load_leverage_tiers=True)
|
exchange = ExchangeResolver.load_exchange(config, load_leverage_tiers=True)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
exchange = Exchange(config)
|
exchange = Exchange(config)
|
||||||
return exchange
|
return exchange
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ def exchange(request, exchange_conf):
|
|||||||
exchange_conf, EXCHANGES[request.param].get('use_ci_proxy', False))
|
exchange_conf, EXCHANGES[request.param].get('use_ci_proxy', False))
|
||||||
exchange_conf['exchange']['name'] = request.param
|
exchange_conf['exchange']['name'] = request.param
|
||||||
exchange_conf['stake_currency'] = EXCHANGES[request.param]['stake_currency']
|
exchange_conf['stake_currency'] = EXCHANGES[request.param]['stake_currency']
|
||||||
exchange = ExchangeResolver.load_exchange(request.param, exchange_conf, validate=True)
|
exchange = ExchangeResolver.load_exchange(exchange_conf, validate=True)
|
||||||
|
|
||||||
yield exchange, request.param
|
yield exchange, request.param
|
||||||
|
|
||||||
|
|||||||
@@ -228,27 +228,30 @@ def test_exchange_resolver(default_conf, mocker, caplog):
|
|||||||
mocker.patch(f'{EXMS}.validate_timeframes')
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
||||||
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
||||||
mocker.patch(f'{EXMS}.validate_pricing')
|
mocker.patch(f'{EXMS}.validate_pricing')
|
||||||
|
default_conf['exchange']['name'] = 'zaif'
|
||||||
exchange = ExchangeResolver.load_exchange('zaif', default_conf)
|
exchange = ExchangeResolver.load_exchange(default_conf)
|
||||||
assert isinstance(exchange, Exchange)
|
assert isinstance(exchange, Exchange)
|
||||||
assert log_has_re(r"No .* specific subclass found. Using the generic class instead.", caplog)
|
assert log_has_re(r"No .* specific subclass found. Using the generic class instead.", caplog)
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
|
|
||||||
exchange = ExchangeResolver.load_exchange('Bittrex', default_conf)
|
default_conf['exchange']['name'] = 'Bittrex'
|
||||||
|
exchange = ExchangeResolver.load_exchange(default_conf)
|
||||||
assert isinstance(exchange, Exchange)
|
assert isinstance(exchange, Exchange)
|
||||||
assert isinstance(exchange, Bittrex)
|
assert isinstance(exchange, Bittrex)
|
||||||
assert not log_has_re(r"No .* specific subclass found. Using the generic class instead.",
|
assert not log_has_re(r"No .* specific subclass found. Using the generic class instead.",
|
||||||
caplog)
|
caplog)
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
|
|
||||||
exchange = ExchangeResolver.load_exchange('kraken', default_conf)
|
default_conf['exchange']['name'] = 'kraken'
|
||||||
|
exchange = ExchangeResolver.load_exchange(default_conf)
|
||||||
assert isinstance(exchange, Exchange)
|
assert isinstance(exchange, Exchange)
|
||||||
assert isinstance(exchange, Kraken)
|
assert isinstance(exchange, Kraken)
|
||||||
assert not isinstance(exchange, Binance)
|
assert not isinstance(exchange, Binance)
|
||||||
assert not log_has_re(r"No .* specific subclass found. Using the generic class instead.",
|
assert not log_has_re(r"No .* specific subclass found. Using the generic class instead.",
|
||||||
caplog)
|
caplog)
|
||||||
|
|
||||||
exchange = ExchangeResolver.load_exchange('binance', default_conf)
|
default_conf['exchange']['name'] = 'binance'
|
||||||
|
exchange = ExchangeResolver.load_exchange(default_conf)
|
||||||
assert isinstance(exchange, Exchange)
|
assert isinstance(exchange, Exchange)
|
||||||
assert isinstance(exchange, Binance)
|
assert isinstance(exchange, Binance)
|
||||||
assert not isinstance(exchange, Kraken)
|
assert not isinstance(exchange, Kraken)
|
||||||
@@ -257,7 +260,8 @@ def test_exchange_resolver(default_conf, mocker, caplog):
|
|||||||
caplog)
|
caplog)
|
||||||
|
|
||||||
# Test mapping
|
# Test mapping
|
||||||
exchange = ExchangeResolver.load_exchange('binanceus', default_conf)
|
default_conf['exchange']['name'] = 'binanceus'
|
||||||
|
exchange = ExchangeResolver.load_exchange(default_conf)
|
||||||
assert isinstance(exchange, Exchange)
|
assert isinstance(exchange, Exchange)
|
||||||
assert isinstance(exchange, Binance)
|
assert isinstance(exchange, Binance)
|
||||||
assert not isinstance(exchange, Kraken)
|
assert not isinstance(exchange, Kraken)
|
||||||
@@ -990,19 +994,20 @@ def test_validate_pricing(default_conf, mocker):
|
|||||||
mocker.patch(f'{EXMS}.validate_timeframes')
|
mocker.patch(f'{EXMS}.validate_timeframes')
|
||||||
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
mocker.patch(f'{EXMS}.validate_stakecurrency')
|
||||||
mocker.patch(f'{EXMS}.name', 'Binance')
|
mocker.patch(f'{EXMS}.name', 'Binance')
|
||||||
ExchangeResolver.load_exchange('binance', default_conf)
|
default_conf['exchange']['name'] = 'binance'
|
||||||
|
ExchangeResolver.load_exchange(default_conf)
|
||||||
has.update({'fetchTicker': False})
|
has.update({'fetchTicker': False})
|
||||||
with pytest.raises(OperationalException, match="Ticker pricing not available for .*"):
|
with pytest.raises(OperationalException, match="Ticker pricing not available for .*"):
|
||||||
ExchangeResolver.load_exchange('binance', default_conf)
|
ExchangeResolver.load_exchange(default_conf)
|
||||||
|
|
||||||
has.update({'fetchTicker': True})
|
has.update({'fetchTicker': True})
|
||||||
|
|
||||||
default_conf['exit_pricing']['use_order_book'] = True
|
default_conf['exit_pricing']['use_order_book'] = True
|
||||||
ExchangeResolver.load_exchange('binance', default_conf)
|
ExchangeResolver.load_exchange(default_conf)
|
||||||
has.update({'fetchL2OrderBook': False})
|
has.update({'fetchL2OrderBook': False})
|
||||||
|
|
||||||
with pytest.raises(OperationalException, match="Orderbook not available for .*"):
|
with pytest.raises(OperationalException, match="Orderbook not available for .*"):
|
||||||
ExchangeResolver.load_exchange('binance', default_conf)
|
ExchangeResolver.load_exchange(default_conf)
|
||||||
|
|
||||||
has.update({'fetchL2OrderBook': True})
|
has.update({'fetchL2OrderBook': True})
|
||||||
|
|
||||||
@@ -1011,7 +1016,7 @@ def test_validate_pricing(default_conf, mocker):
|
|||||||
default_conf['margin_mode'] = MarginMode.ISOLATED
|
default_conf['margin_mode'] = MarginMode.ISOLATED
|
||||||
|
|
||||||
with pytest.raises(OperationalException, match="Ticker pricing not available for .*"):
|
with pytest.raises(OperationalException, match="Ticker pricing not available for .*"):
|
||||||
ExchangeResolver.load_exchange('binance', default_conf)
|
ExchangeResolver.load_exchange(default_conf)
|
||||||
|
|
||||||
|
|
||||||
def test_validate_ordertypes(default_conf, mocker):
|
def test_validate_ordertypes(default_conf, mocker):
|
||||||
@@ -1091,12 +1096,13 @@ def test_validate_ordertypes_stop_advanced(default_conf, mocker, exchange_name,
|
|||||||
'stoploss_on_exchange': True,
|
'stoploss_on_exchange': True,
|
||||||
'stoploss_price_type': stopadv,
|
'stoploss_price_type': stopadv,
|
||||||
}
|
}
|
||||||
|
default_conf['exchange']['name'] = exchange_name
|
||||||
if expected:
|
if expected:
|
||||||
ExchangeResolver.load_exchange(exchange_name, default_conf)
|
ExchangeResolver.load_exchange(default_conf)
|
||||||
else:
|
else:
|
||||||
with pytest.raises(OperationalException,
|
with pytest.raises(OperationalException,
|
||||||
match=r'On exchange stoploss price type is not supported for .*'):
|
match=r'On exchange stoploss price type is not supported for .*'):
|
||||||
ExchangeResolver.load_exchange(exchange_name, default_conf)
|
ExchangeResolver.load_exchange(default_conf)
|
||||||
|
|
||||||
|
|
||||||
def test_validate_order_types_not_in_config(default_conf, mocker):
|
def test_validate_order_types_not_in_config(default_conf, mocker):
|
||||||
|
|||||||
Reference in New Issue
Block a user