Merge pull request #1926 from hroff-1902/check-exchange
Enhance check_exchange()
This commit is contained in:
commit
a0415aea83
@ -13,7 +13,8 @@ from jsonschema import Draft4Validator, validators
|
|||||||
from jsonschema.exceptions import ValidationError, best_match
|
from jsonschema.exceptions import ValidationError, best_match
|
||||||
|
|
||||||
from freqtrade import OperationalException, constants
|
from freqtrade import OperationalException, constants
|
||||||
from freqtrade.exchange import is_exchange_supported, supported_exchanges
|
from freqtrade.exchange import (is_exchange_bad, is_exchange_available,
|
||||||
|
is_exchange_officially_supported, available_exchanges)
|
||||||
from freqtrade.misc import deep_merge_dicts
|
from freqtrade.misc import deep_merge_dicts
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.state import RunMode
|
||||||
|
|
||||||
@ -388,22 +389,40 @@ class Configuration(object):
|
|||||||
|
|
||||||
return self.config
|
return self.config
|
||||||
|
|
||||||
def check_exchange(self, config: Dict[str, Any]) -> bool:
|
def check_exchange(self, config: Dict[str, Any], check_for_bad: bool = True) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if the exchange name in the config file is supported by Freqtrade
|
Check if the exchange name in the config file is supported by Freqtrade
|
||||||
:return: True or raised an exception if the exchange if not supported
|
:param check_for_bad: if True, check the exchange against the list of known 'bad'
|
||||||
|
exchanges
|
||||||
|
:return: False if exchange is 'bad', i.e. is known to work with the bot with
|
||||||
|
critical issues or does not work at all, crashes, etc. True otherwise.
|
||||||
|
raises an exception if the exchange if not supported by ccxt
|
||||||
|
and thus is not known for the Freqtrade at all.
|
||||||
"""
|
"""
|
||||||
|
logger.info("Checking exchange...")
|
||||||
|
|
||||||
exchange = config.get('exchange', {}).get('name').lower()
|
exchange = config.get('exchange', {}).get('name').lower()
|
||||||
if not is_exchange_supported(exchange):
|
if not is_exchange_available(exchange):
|
||||||
|
|
||||||
exception_msg = f'Exchange "{exchange}" not supported.\n' \
|
|
||||||
f'The following exchanges are supported: ' \
|
|
||||||
f'{", ".join(supported_exchanges())}'
|
|
||||||
|
|
||||||
logger.critical(exception_msg)
|
|
||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
exception_msg
|
f'Exchange "{exchange}" is not supported by ccxt '
|
||||||
|
f'and therefore not available for the bot.\n'
|
||||||
|
f'The following exchanges are supported by ccxt: '
|
||||||
|
f'{", ".join(available_exchanges())}'
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.debug('Exchange "%s" supported', exchange)
|
if check_for_bad and is_exchange_bad(exchange):
|
||||||
|
logger.warning(f'Exchange "{exchange}" is known to not work with the bot yet. '
|
||||||
|
f'Use it only for development and testing purposes.')
|
||||||
|
return False
|
||||||
|
|
||||||
|
if is_exchange_officially_supported(exchange):
|
||||||
|
logger.info(f'Exchange "{exchange}" is officially supported '
|
||||||
|
f'by the Freqtrade development team.')
|
||||||
|
else:
|
||||||
|
logger.warning(f'Exchange "{exchange}" is supported by ccxt '
|
||||||
|
f'and therefore available for the bot but not officially supported '
|
||||||
|
f'by the Freqtrade development team. '
|
||||||
|
f'It may work flawlessly (please report back) or have serious issues. '
|
||||||
|
f'Use it at your own discretion.')
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
from freqtrade.exchange.exchange import Exchange # noqa: F401
|
from freqtrade.exchange.exchange import Exchange # noqa: F401
|
||||||
from freqtrade.exchange.exchange import (is_exchange_supported, # noqa: F401
|
from freqtrade.exchange.exchange import (is_exchange_bad, # noqa: F401
|
||||||
supported_exchanges)
|
is_exchange_available,
|
||||||
|
is_exchange_officially_supported,
|
||||||
|
available_exchanges)
|
||||||
from freqtrade.exchange.exchange import (timeframe_to_seconds, # noqa: F401
|
from freqtrade.exchange.exchange import (timeframe_to_seconds, # noqa: F401
|
||||||
timeframe_to_minutes,
|
timeframe_to_minutes,
|
||||||
timeframe_to_msecs)
|
timeframe_to_msecs)
|
||||||
|
@ -156,8 +156,8 @@ class Exchange(object):
|
|||||||
# Find matching class for the given exchange name
|
# Find matching class for the given exchange name
|
||||||
name = exchange_config['name']
|
name = exchange_config['name']
|
||||||
|
|
||||||
if not is_exchange_supported(name, ccxt_module):
|
if not is_exchange_available(name, ccxt_module):
|
||||||
raise OperationalException(f'Exchange {name} is not supported')
|
raise OperationalException(f'Exchange {name} is not supported by ccxt')
|
||||||
|
|
||||||
ex_config = {
|
ex_config = {
|
||||||
'apiKey': exchange_config.get('key'),
|
'apiKey': exchange_config.get('key'),
|
||||||
@ -722,11 +722,19 @@ class Exchange(object):
|
|||||||
raise OperationalException(e)
|
raise OperationalException(e)
|
||||||
|
|
||||||
|
|
||||||
def is_exchange_supported(exchange: str, ccxt_module=None) -> bool:
|
def is_exchange_bad(exchange: str) -> bool:
|
||||||
return exchange in supported_exchanges(ccxt_module)
|
return exchange in ['bitmex']
|
||||||
|
|
||||||
|
|
||||||
def supported_exchanges(ccxt_module=None) -> List[str]:
|
def is_exchange_available(exchange: str, ccxt_module=None) -> bool:
|
||||||
|
return exchange in available_exchanges(ccxt_module)
|
||||||
|
|
||||||
|
|
||||||
|
def is_exchange_officially_supported(exchange: str) -> bool:
|
||||||
|
return exchange in ['bittrex', 'binance']
|
||||||
|
|
||||||
|
|
||||||
|
def available_exchanges(ccxt_module=None) -> List[str]:
|
||||||
return ccxt_module.exchanges if ccxt_module is not None else ccxt.exchanges
|
return ccxt_module.exchanges if ccxt_module is not None else ccxt.exchanges
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ from freqtrade.arguments import Arguments
|
|||||||
from freqtrade.configuration import Configuration, set_loggers
|
from freqtrade.configuration import Configuration, set_loggers
|
||||||
from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL
|
from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL
|
||||||
from freqtrade.state import RunMode
|
from freqtrade.state import RunMode
|
||||||
from freqtrade.tests.conftest import log_has
|
from freqtrade.tests.conftest import log_has, log_has_re
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
@ -470,21 +470,52 @@ def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None:
|
|||||||
def test_check_exchange(default_conf, caplog) -> None:
|
def test_check_exchange(default_conf, caplog) -> None:
|
||||||
configuration = Configuration(Namespace())
|
configuration = Configuration(Namespace())
|
||||||
|
|
||||||
# Test a valid exchange
|
# Test an officially supported by Freqtrade team exchange
|
||||||
default_conf.get('exchange').update({'name': 'BITTREX'})
|
default_conf.get('exchange').update({'name': 'BITTREX'})
|
||||||
assert configuration.check_exchange(default_conf)
|
assert configuration.check_exchange(default_conf)
|
||||||
|
assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.",
|
||||||
|
caplog.record_tuples)
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
# Test a valid exchange
|
# Test an officially supported by Freqtrade team exchange
|
||||||
default_conf.get('exchange').update({'name': 'binance'})
|
default_conf.get('exchange').update({'name': 'binance'})
|
||||||
assert configuration.check_exchange(default_conf)
|
assert configuration.check_exchange(default_conf)
|
||||||
|
assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.",
|
||||||
|
caplog.record_tuples)
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
# Test a invalid exchange
|
# Test an available exchange, supported by ccxt
|
||||||
|
default_conf.get('exchange').update({'name': 'kraken'})
|
||||||
|
assert configuration.check_exchange(default_conf)
|
||||||
|
assert log_has_re(r"Exchange .* is supported by ccxt and .* not officially supported "
|
||||||
|
r"by the Freqtrade development team\. .*",
|
||||||
|
caplog.record_tuples)
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
|
# Test a 'bad' exchange, which known to have serious problems
|
||||||
|
default_conf.get('exchange').update({'name': 'bitmex'})
|
||||||
|
assert not configuration.check_exchange(default_conf)
|
||||||
|
assert log_has_re(r"Exchange .* is known to not work with the bot yet\. "
|
||||||
|
r"Use it only for development and testing purposes\.",
|
||||||
|
caplog.record_tuples)
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
|
# Test a 'bad' exchange with check_for_bad=False
|
||||||
|
default_conf.get('exchange').update({'name': 'bitmex'})
|
||||||
|
assert configuration.check_exchange(default_conf, False)
|
||||||
|
assert log_has_re(r"Exchange .* is supported by ccxt and .* not officially supported "
|
||||||
|
r"by the Freqtrade development team\. .*",
|
||||||
|
caplog.record_tuples)
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
|
# Test an invalid exchange
|
||||||
default_conf.get('exchange').update({'name': 'unknown_exchange'})
|
default_conf.get('exchange').update({'name': 'unknown_exchange'})
|
||||||
configuration.config = default_conf
|
configuration.config = default_conf
|
||||||
|
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
OperationalException,
|
OperationalException,
|
||||||
match=r'.*Exchange "unknown_exchange" not supported.*'
|
match=r'.*Exchange "unknown_exchange" is not supported by ccxt '
|
||||||
|
r'and therefore not available for the bot.*'
|
||||||
):
|
):
|
||||||
configuration.check_exchange(default_conf)
|
configuration.check_exchange(default_conf)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user