Repository: freqtrade/freqtrade

Issue:
Bitstamp has no attribute 'timeframes'

    Python Version: Python 3.7.3
    CCXT version: ccxt==1.18.805
    Branch: Develop
    Last Commit ID: ca7080c
  
## Step 3: Describe the problem:

```
Traceback (most recent call last):
  File "/opt/Projects/freqtrade/freqtrade/main.py", line 51, in main
    worker = Worker(args)
  File "/opt/Projects/freqtrade/freqtrade/worker.py", line 35, in __init__
    self._init(False)
  File "/opt/Projects/freqtrade/freqtrade/worker.py", line 51, in _init
    self.freqtrade = FreqtradeBot(self._config)
  File "/opt/Projects/freqtrade/freqtrade/freqtradebot.py", line 56, in __init__
    self.exchange = ExchangeResolver(self.config['exchange']['name'], self.config).exchange
  File "/opt/Projects/freqtrade/freqtrade/resolvers/exchange_resolver.py", line 31, in __init__
    self.exchange = Exchange(config)
  File "/opt/Projects/freqtrade/freqtrade/exchange/exchange.py", line 140, in __init__
    self.validate_timeframes(config['ticker_interval'])
  File "/opt/Projects/freqtrade/freqtrade/exchange/exchange.py", line 272, in validate_timeframes
    timeframes = self._api.timeframes
AttributeError: 'bitstamp' object has no attribute 'timeframes'
```

### Steps to reproduce:

  1. Attempt to use bitstamp
  
### Observed Results:

  * Exchange initialization failed
  * Exchange initialization succeed

### What to do ?
Is there a way to fix this ?
If not, how about a way to have it fail in a little bit nicer fashion ?


Discussion:
> timeframes: An associative array of timeframes, supported by the fetchOHLCV method of the exchange. This is only populated when has['fetchOHLCV'] property is true.

(source: [ccxt docs](https://ccxt.readthedocs.io/en/latest/manual.html?highlight=timeframe))

fetchOHLCV is "emulated" for bitstamp, which means that ccxt uses "some other" means to get some OHLCV data (bitstamp api apparently does not offer a fetchOHLCV method).

Trying that interactively yields 9 5m candles. With that low amount of history,  don't think bitstamp will work with the bot, since almost all indicators require 20-100 candles of history to be populated correctly.


``` python
import ccxt
bst = ccxt.bitstamp()
len(bst.fetch_ohlcv('ETH/BTC', timeframe="5m", limit=500))
```

Yes, we should fail "nicer" ... but running the bot with this exchange will probably not work, sorry
Hmmm, then : 
- we have a "white list" of known working & well supported exchanges
- shouldn't we also have a "black list" (documented somewhere) of exchanges that are known not to work, for reasons outside of freqtrade control ? I mean I had hoped that bitstamp was "implementable", even if it was not working out of the box...
well we do:
https://github.com/freqtrade/freqtrade/blob/152e138c17c1f19882c497eb36cee727fb15da57/freqtrade/exchange/exchange.py#L725-L726

we'll add exchanges as we discover problems with them - but we're not actively testing all 100+ exchanges for problems. 
I guess Bitstamp needs to be added to that list 
Oh ok, I didn't noticed that one, I meant on the README ;-)
Anyway, here you go : #1984 

Resolving patch:
diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py
--- a/freqtrade/exchange/exchange.py
+++ b/freqtrade/exchange/exchange.py
@@ -269,6 +269,12 @@ def validate_timeframes(self, timeframe: List[str]) -> None:
         """
         Checks if ticker interval from config is a supported timeframe on the exchange
         """
+        if not hasattr(self._api, "timeframes"):
+            # If timeframes is missing, the exchange probably has no fetchOHLCV method.
+            # Therefore we also show that.
+            raise OperationalException(
+                f"This exchange ({self.name}) does not have a `timeframes` attribute and "
+                f"is therefore not supported. fetchOHLCV: {self.exchange_has('fetchOHLCV')}")
         timeframes = self._api.timeframes
         if timeframe not in timeframes:
             raise OperationalException(
diff --git a/freqtrade/resolvers/exchange_resolver.py b/freqtrade/resolvers/exchange_resolver.py
--- a/freqtrade/resolvers/exchange_resolver.py
+++ b/freqtrade/resolvers/exchange_resolver.py
@@ -28,6 +28,7 @@ def __init__(self, exchange_name: str, config: dict) -> None:
         except ImportError:
             logger.info(
                 f"No {exchange_name} specific subclass found. Using the generic class instead.")
+        if not hasattr(self, "exchange"):
             self.exchange = Exchange(config)
 
     def _load_exchange(


Test patch:
diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py
--- a/freqtrade/tests/exchange/test_exchange.py
+++ b/freqtrade/tests/exchange/test_exchange.py
@@ -396,6 +396,23 @@ def test_validate_timeframes_failed(default_conf, mocker):
         Exchange(default_conf)
 
 
+def test_validate_timeframes_emulated_ohlcv(default_conf, mocker):
+    default_conf["ticker_interval"] = "3m"
+    api_mock = MagicMock()
+    id_mock = PropertyMock(return_value='test_exchange')
+    type(api_mock).id = id_mock
+
+    # delete timeframes so magicmock does not autocreate it
+    del api_mock.timeframes
+
+    mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
+    mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
+    mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
+    with pytest.raises(OperationalException,
+                       match=r'This exchange (.*) does not have a `timeframes` attribute and*'):
+        Exchange(default_conf)
+
+
 def test_validate_timeframes_not_in_config(default_conf, mocker):
     del default_conf["ticker_interval"]
     api_mock = MagicMock()