# Buggy code
def __init__(self, config: dict) -> None:
    """
    Initializes this module with the given config,
    it does basic validation whether the specified exchange and pairs are valid.
    :return: None
    """
    self._config.update(config)

    self._cached_ticker: Dict[str, Any] = {}

    # Holds last candle refreshed time of each pair
    self._pairs_last_refresh_time: Dict[Tuple[str, str], int] = {}
    # Timestamp of last markets refresh
    self._last_markets_refresh: int = 0

    # Holds candles
    self._klines: Dict[Tuple[str, str], DataFrame] = {}

    # Holds all open sell orders for dry_run
    self._dry_run_open_orders: Dict[str, Any] = {}

    if config["dry_run"]:
        logger.info("Instance is running with dry_run enabled")

    exchange_config = config["exchange"]

    # Deep merge ft_has with default ft_has options
    self._ft_has = deep_merge_dicts(self._ft_has, deepcopy(self._ft_has_default))
    if exchange_config.get("_ft_has_params"):
        self._ft_has = deep_merge_dicts(
            exchange_config.get("_ft_has_params"), self._ft_has
        )
        logger.info(
            "Overriding exchange._ft_has with config params, result: %s", self._ft_has
        )

    # Assign this directly for easy access
    self._ohlcv_candle_limit = self._ft_has["ohlcv_candle_limit"]
    self._ohlcv_partial_candle = self._ft_has["ohlcv_partial_candle"]

    # Initialize ccxt objects
    self._api: ccxt.Exchange = self._init_ccxt(
        exchange_config, ccxt_kwargs=exchange_config.get("ccxt_config")
    )
    self._api_async: ccxt_async.Exchange = self._init_ccxt(
        exchange_config,
        ccxt_async,
        ccxt_kwargs=exchange_config.get("ccxt_async_config"),
    )

    logger.info('Using Exchange "%s"', self.name)

    # Converts the interval provided in minutes in config to seconds
    self.markets_refresh_interval: int = (
        exchange_config.get("markets_refresh_interval", 60) * 60
    )
    # Initial markets load
    self._load_markets()

    # Check if all pairs are available
    self.validate_pairs(config["exchange"]["pair_whitelist"])
    self.validate_ordertypes(config.get("order_types", {}))
    self.validate_order_time_in_force(config.get("order_time_in_force", {}))

    if config.get("ticker_interval"):
        # Check if timeframe is available
        self.validate_timeframes(config["ticker_interval"])


# Traceback (AttributeError)
$ ./freqtrade/main.py -c config_theocean.json
2019-07-03 04:15:14,787 - freqtrade.configuration - INFO - Verbosity set to 0
2019-07-03 04:15:14,787 - freqtrade.configuration - INFO - Dry run is enabled
2019-07-03 04:15:14,787 - freqtrade.configuration - INFO - Using DB: "sqlite://"
2019-07-03 04:15:14,787 - freqtrade.configuration - INFO - Checking exchange...
2019-07-03 04:15:14,787 - freqtrade.configuration - WARNING - Exchange "theocean" is supported by ccxt and therefore available for the bot but not officially supported by the Freqtrade development team. It may work flawlessly (please report back) or have serious issues. Use it at your own discretion.
2019-07-03 04:15:14,787 - freqtrade.configuration - INFO - Using max_open_trades: 3 ...
2019-07-03 04:15:14,787 - freqtrade.configuration - INFO - Using data folder: user_data/data/theocean ...
2019-07-03 04:15:14,788 - freqtrade.freqtradebot - INFO - Starting freqtrade 2019.6-dev
2019-07-03 04:15:14,792 - freqtrade.resolvers.strategy_resolver - INFO - Using resolved strategy DefaultStrategy from '/home/user/freqtrade-wrk/github-hroff-1902/freqtrade/freqtrade/strategy'
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'ticker_interval' with value in config file: 5m.
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'trailing_stop' with value in config file: False.
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'stake_currency' with value in config file: BTC.
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'stake_amount' with value in config file: 0.05.
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'use_sell_signal' with value in config file: False.
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'sell_profit_only' with value in config file: False.
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'ignore_roi_if_buy_signal' with value in config file: False.
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using minimal_roi: {'40': 0.0, '30': 0.01, '20': 0.02, '0': 0.04}
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using ticker_interval: 5m
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using stoploss: -0.1
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using trailing_stop: False
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using trailing_stop_positive_offset: 0.0
2019-07-03 04:15:14,793 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using trailing_only_offset_is_reached: False
2019-07-03 04:15:14,794 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using process_only_new_candles: False
2019-07-03 04:15:14,794 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using order_types: {'buy': 'limit', 'sell': 'limit', 'stoploss': 'limit', 'stoploss_on_exchange': False}
2019-07-03 04:15:14,794 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using order_time_in_force: {'buy': 'gtc', 'sell': 'gtc'}
2019-07-03 04:15:14,794 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using stake_currency: BTC
2019-07-03 04:15:14,794 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using stake_amount: 0.05
2019-07-03 04:15:14,794 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using use_sell_signal: False
2019-07-03 04:15:14,794 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using sell_profit_only: False
2019-07-03 04:15:14,794 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using ignore_roi_if_buy_signal: False
2019-07-03 04:15:14,794 - freqtrade.resolvers.exchange_resolver - INFO - No Theocean specific subclass found. Using the generic class instead.
2019-07-03 04:15:14,794 - freqtrade.exchange.exchange - INFO - Instance is running with dry_run enabled
2019-07-03 04:15:14,794 - freqtrade.exchange.exchange - INFO - Applying additional ccxt config: {'enableRateLimit': True}
2019-07-03 04:15:14,794 - freqtrade - ERROR - Fatal exception!
Traceback (most recent call last):
File "./freqtrade/main.py", line 51, in main
worker = Worker(args)
File "/home/user/freqtrade-wrk/github-hroff-1902/freqtrade/freqtrade/worker.py", line 35, in __init__
self._init(False)
File "/home/user/freqtrade-wrk/github-hroff-1902/freqtrade/freqtrade/worker.py", line 51, in _init
self.freqtrade = FreqtradeBot(self._config)
File "/home/user/freqtrade-wrk/github-hroff-1902/freqtrade/freqtrade/freqtradebot.py", line 56, in __init__
self.exchange = ExchangeResolver(self.config['exchange']['name'], self.config).exchange
File "/home/user/freqtrade-wrk/github-hroff-1902/freqtrade/freqtrade/resolvers/exchange_resolver.py", line 32, in __init__
self.exchange = Exchange(config)
File "/home/user/freqtrade-wrk/github-hroff-1902/freqtrade/freqtrade/exchange/exchange.py", line 121, in __init__
exchange_config, ccxt_kwargs=exchange_config.get('ccxt_config'))
File "/home/user/freqtrade-wrk/github-hroff-1902/freqtrade/freqtrade/exchange/exchange.py", line 173, in _init_ccxt
api = getattr(ccxt_module, name.lower())(ex_config)
File "/home/user/freqtrade-wrk/github-hroff-1902/freqtrade/.env/lib/python3.6/site-packages/ccxt/base/exchange.py", line 330, in __init__
settings = self.deep_extend(self.describe(), config)
File "/home/user/freqtrade-wrk/github-hroff-1902/freqtrade/.env/lib/python3.6/site-packages/ccxt/theocean.py", line 25, in describe
self.check_required_dependencies()
File "/home/user/freqtrade-wrk/github-hroff-1902/freqtrade/.env/lib/python3.6/site-packages/ccxt/base/exchange.py", line 1638, in check_required_dependencies
raise NotSupported("Web3 functionality requires Python3 and web3 package installed: https://github.com/ethereum/web3.py")
ccxt.base.errors.NotSupported: Web3 functionality requires Python3 and web3 package installed: https://github.com/ethereum/web3.py
Exception ignored in: <bound method Exchange.__del__ of <freqtrade.exchange.exchange.Exchange object at 0x7f0021ea0080>>
Traceback (most recent call last):
File "/home/user/freqtrade-wrk/github-hroff-1902/freqtrade/freqtrade/exchange/exchange.py", line 147, in __del__
if self._api_async and inspect.iscoroutinefunction(self._api_async.close):
AttributeError: 'Exchange' object has no attribute '_api_async'

# Fixed code
def __init__(self, config: dict) -> None:
    """
    Initializes this module with the given config,
    it does basic validation whether the specified exchange and pairs are valid.
    :return: None
    """
    self._api: ccxt.Exchange = None
    self._api_async: ccxt_async.Exchange = None

    self._config.update(config)

    self._cached_ticker: Dict[str, Any] = {}

    # Holds last candle refreshed time of each pair
    self._pairs_last_refresh_time: Dict[Tuple[str, str], int] = {}
    # Timestamp of last markets refresh
    self._last_markets_refresh: int = 0

    # Holds candles
    self._klines: Dict[Tuple[str, str], DataFrame] = {}

    # Holds all open sell orders for dry_run
    self._dry_run_open_orders: Dict[str, Any] = {}

    if config["dry_run"]:
        logger.info("Instance is running with dry_run enabled")

    exchange_config = config["exchange"]

    # Deep merge ft_has with default ft_has options
    self._ft_has = deep_merge_dicts(self._ft_has, deepcopy(self._ft_has_default))
    if exchange_config.get("_ft_has_params"):
        self._ft_has = deep_merge_dicts(
            exchange_config.get("_ft_has_params"), self._ft_has
        )
        logger.info(
            "Overriding exchange._ft_has with config params, result: %s", self._ft_has
        )

    # Assign this directly for easy access
    self._ohlcv_candle_limit = self._ft_has["ohlcv_candle_limit"]
    self._ohlcv_partial_candle = self._ft_has["ohlcv_partial_candle"]

    # Initialize ccxt objects
    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)

    # Converts the interval provided in minutes in config to seconds
    self.markets_refresh_interval: int = (
        exchange_config.get("markets_refresh_interval", 60) * 60
    )
    # Initial markets load
    self._load_markets()

    # Check if all pairs are available
    self.validate_pairs(config["exchange"]["pair_whitelist"])
    self.validate_ordertypes(config.get("order_types", {}))
    self.validate_order_time_in_force(config.get("order_time_in_force", {}))

    if config.get("ticker_interval"):
        # Check if timeframe is available
        self.validate_timeframes(config["ticker_interval"])