diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index de1310751..07ab4d3c6 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -1,6 +1,7 @@ # pragma pylint: disable=W0603 """ Cryptocurrency Exchanges support """ import logging +import inspect from random import randint from typing import List, Dict, Tuple, Any, Optional from datetime import datetime @@ -87,6 +88,14 @@ class Exchange(object): # Check if timeframe is available self.validate_timeframes(config['ticker_interval']) + def __del__(self): + """ + Destructor - clean up async stuff + """ + logger.debug("Exchange object destroyed, closing async loop") + 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: """ Initialize ccxt with given config and return valid diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index f6b6b105f..f379ee689 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -51,6 +51,12 @@ def test_init(default_conf, mocker, caplog): assert log_has('Instance is running with dry_run enabled', caplog.record_tuples) +def test_destroy(default_conf, mocker, caplog): + caplog.set_level(logging.DEBUG) + get_patched_exchange(mocker, default_conf) + assert log_has('Exchange object destroyed, closing async loop', caplog.record_tuples) + + def test_init_exception(default_conf, mocker): default_conf['exchange']['name'] = 'wrong_exchange_name'