diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index d3c60c256..7fd0e5f43 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -93,8 +93,9 @@ class Exchange(object): logger.info('Instance is running with dry_run enabled') exchange_config = config['exchange'] - self._api = self._init_ccxt(exchange_config) - self._api_async = self._init_ccxt(exchange_config, ccxt_async) + self._api = self._init_ccxt(exchange_config, ccxt_kwargs=exchange_config.get('ccxt_config')) + self._api_async = self._init_ccxt(exchange_config, ccxt_async, + ccxt_kwargs=exchange_config.get('ccxt_async_config')) logger.info('Using Exchange "%s"', self.name) @@ -114,7 +115,8 @@ class Exchange(object): if self._api_async and inspect.iscoroutinefunction(self._api_async.close): asyncio.get_event_loop().run_until_complete(self._api_async.close()) - def _init_ccxt(self, exchange_config: dict, ccxt_module=ccxt) -> ccxt.Exchange: + def _init_ccxt(self, exchange_config: dict, ccxt_module=ccxt, + ccxt_kwargs: dict = None) -> ccxt.Exchange: """ Initialize ccxt with given config and return valid ccxt instance. @@ -124,14 +126,20 @@ class Exchange(object): if name not in ccxt_module.exchanges: raise OperationalException(f'Exchange {name} is not supported') - try: - api = getattr(ccxt_module, name.lower())({ + + ex_config = { 'apiKey': exchange_config.get('key'), 'secret': exchange_config.get('secret'), 'password': exchange_config.get('password'), 'uid': exchange_config.get('uid', ''), 'enableRateLimit': exchange_config.get('ccxt_rate_limit', True) - }) + } + if ccxt_kwargs: + logger.info('Applying additional ccxt config: %s', ccxt_kwargs) + ex_config.update(ccxt_kwargs) + try: + + api = getattr(ccxt_module, name.lower())(ex_config) except (KeyError, AttributeError): raise OperationalException(f'Exchange {name} is not supported') diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index d9d68c3b8..93cd1e546 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -1,5 +1,6 @@ # pragma pylint: disable=missing-docstring, C0103, bad-continuation, global-statement # pragma pylint: disable=protected-access +import copy import logging from datetime import datetime from random import randint @@ -56,6 +57,32 @@ def test_init(default_conf, mocker, caplog): assert log_has('Instance is running with dry_run enabled', caplog.record_tuples) +def test_init_ccxt_kwargs(default_conf, mocker, caplog): + mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) + caplog.set_level(logging.INFO) + conf = copy.deepcopy(default_conf) + conf['exchange']['ccxt_async_config'] = {'aiohttp_trust_env': True} + ex = Exchange(conf) + assert log_has("Applying additional ccxt config: {'aiohttp_trust_env': True}", + caplog.record_tuples) + assert ex._api_async.aiohttp_trust_env + assert not ex._api.aiohttp_trust_env + + # Reset logging and config + caplog.clear() + conf = copy.deepcopy(default_conf) + conf['exchange']['ccxt_config'] = {'TestKWARG': 11} + ex = Exchange(conf) + assert not log_has("Applying additional ccxt config: {'aiohttp_trust_env': True}", + caplog.record_tuples) + assert not ex._api_async.aiohttp_trust_env + assert hasattr(ex._api, 'TestKWARG') + assert ex._api.TestKWARG == 11 + assert not hasattr(ex._api_async, 'TestKWARG') + assert log_has("Applying additional ccxt config: {'TestKWARG': 11}", + caplog.record_tuples) + + def test_destroy(default_conf, mocker, caplog): caplog.set_level(logging.DEBUG) get_patched_exchange(mocker, default_conf)