From 966668f48a5f02cf6abd71358cadebca8fed09f5 Mon Sep 17 00:00:00 2001 From: creslinux Date: Thu, 5 Jul 2018 11:57:59 +0000 Subject: [PATCH 1/6] Handle if ticker_interval in config.json is not supported on exchange. Returns. Tested positive and negative data. The ticker list in constants.py may be obsolete now, im not sure. raise OperationalException(f'Invalid ticker {timeframe}, this Exchange supports {timeframes}') freqtrade.OperationalException: Invalid ticker 14m, this Exchange supports {'1m': '1m', '3m': '3m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '2h': '2h', '4h': '4h', '6h': '6h', '8h': '8h', '12h': '12h', '1d': '1d', '3d': '3d', '1w': '1w', '1M': '1M'} --- freqtrade/exchange/__init__.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index acfefdad4..23305b59f 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -70,6 +70,9 @@ class Exchange(object): # Check if all pairs are available self.validate_pairs(config['exchange']['pair_whitelist']) + # Check if timeframe is available + self.validate_timeframes(config['ticker_interval']) + def _init_ccxt(self, exchange_config: dict) -> ccxt.Exchange: """ Initialize ccxt with given config and return valid @@ -128,6 +131,14 @@ class Exchange(object): raise OperationalException( f'Pair {pair} is not available at {self.name}') + def validate_timeframes(self, timeframe: List[str]) -> None: + """ + Checks if ticker interval from config is a supported timeframe on the exchange + """ + timeframes=self._api.timeframes + if timeframe not in timeframes: + raise OperationalException(f'Invalid ticker {timeframe}, this Exchange supports {timeframes}') + def exchange_has(self, endpoint: str) -> bool: """ Checks if exchange implements a specific API endpoint. From 5ab644dea6fe64e2e11478cf560adb8b295e6444 Mon Sep 17 00:00:00 2001 From: creslinux Date: Thu, 5 Jul 2018 12:05:31 +0000 Subject: [PATCH 2/6] flake 8 fix --- freqtrade/exchange/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 23305b59f..d87d3fc85 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -135,9 +135,10 @@ class Exchange(object): """ Checks if ticker interval from config is a supported timeframe on the exchange """ - timeframes=self._api.timeframes + timeframes = self._api.timeframes if timeframe not in timeframes: - raise OperationalException(f'Invalid ticker {timeframe}, this Exchange supports {timeframes}') + raise OperationalException( + f'Invalid ticker {timeframe}, this Exchange supports {timeframes}') def exchange_has(self, endpoint: str) -> bool: """ From af17cef0027018de47fbee25aec9114cebc52ef7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 Jul 2018 14:41:36 +0200 Subject: [PATCH 3/6] fix existing tests to work with validate_timeframes --- freqtrade/tests/conftest.py | 1 + freqtrade/tests/exchange/test_exchange.py | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index 9c86d1ece..ec435ab09 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -29,6 +29,7 @@ def log_has(line, logs): def patch_exchange(mocker, api_mock=None) -> None: mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock()) + mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) if api_mock: mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) else: diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index 3ddec0ded..246c9c54f 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -61,6 +61,7 @@ def test_validate_pairs(default_conf, mocker): type(api_mock).id = id_mock mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) + mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) Exchange(default_conf) @@ -68,6 +69,7 @@ def test_validate_pairs_not_available(default_conf, mocker): api_mock = MagicMock() api_mock.load_markets = MagicMock(return_value={}) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) + mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) with pytest.raises(OperationalException, match=r'not available'): Exchange(default_conf) @@ -81,7 +83,7 @@ def test_validate_pairs_not_compatible(default_conf, mocker): conf = deepcopy(default_conf) conf['stake_currency'] = 'ETH' mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) - + mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) with pytest.raises(OperationalException, match=r'not compatible'): Exchange(conf) @@ -93,6 +95,7 @@ def test_validate_pairs_exception(default_conf, mocker, caplog): api_mock.load_markets = MagicMock(return_value={}) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', api_mock) + mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) with pytest.raises(OperationalException, match=r'Pair ETH/BTC is not available at Binance'): Exchange(default_conf) @@ -112,6 +115,7 @@ def test_validate_pairs_stake_exception(default_conf, mocker, caplog): api_mock = MagicMock() api_mock.name = MagicMock(return_value='binance') mocker.patch('freqtrade.exchange.Exchange._init_ccxt', api_mock) + mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) with pytest.raises( OperationalException, From 3f6e9cd28f3e6209f398429f1565148390c9eb15 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 Jul 2018 14:42:53 +0200 Subject: [PATCH 4/6] Add tests for validate_timeframes --- freqtrade/tests/exchange/test_exchange.py | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index 246c9c54f..89d3beb42 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -124,6 +124,39 @@ def test_validate_pairs_stake_exception(default_conf, mocker, caplog): Exchange(conf) +def test_validate_timeframes(default_conf, mocker): + default_conf["ticker_interval"] = "5m" + api_mock = MagicMock() + id_mock = PropertyMock(return_value='test_exchange') + type(api_mock).id = id_mock + timeframes = PropertyMock(return_value={'1m': '1m', + '5m': '5m', + '15m': '15m', + '1h': '1h'}) + type(api_mock).timeframes = timeframes + + mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) + mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock()) + Exchange(default_conf) + + +def test_validate_timeframes_failed(default_conf, mocker): + default_conf["ticker_interval"] = "3m" + api_mock = MagicMock() + id_mock = PropertyMock(return_value='test_exchange') + type(api_mock).id = id_mock + timeframes = PropertyMock(return_value={'1m': '1m', + '5m': '5m', + '15m': '15m', + '1h': '1h'}) + type(api_mock).timeframes = timeframes + + mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) + mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock()) + with pytest.raises(OperationalException, match=r'Invalid ticker 3m, this Exchange supports.*'): + Exchange(default_conf) + + def test_exchangehas(default_conf, mocker): exchange = get_patched_exchange(mocker, default_conf) assert not exchange.exchange_has('ASDFASDF') From 570d27a0c48f7b4e52ec5c9fcbc09171f113d63b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 Jul 2018 15:30:29 +0200 Subject: [PATCH 5/6] Add testcase where ticker_interval is not in the configuration --- freqtrade/tests/exchange/test_exchange.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index 89d3beb42..282d8ef01 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -157,6 +157,22 @@ def test_validate_timeframes_failed(default_conf, mocker): Exchange(default_conf) +def test_validate_timeframes_not_in_config(default_conf, mocker): + del default_conf["ticker_interval"] + api_mock = MagicMock() + id_mock = PropertyMock(return_value='test_exchange') + type(api_mock).id = id_mock + timeframes = PropertyMock(return_value={'1m': '1m', + '5m': '5m', + '15m': '15m', + '1h': '1h'}) + type(api_mock).timeframes = timeframes + + mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) + mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock()) + Exchange(default_conf) + + def test_exchangehas(default_conf, mocker): exchange = get_patched_exchange(mocker, default_conf) assert not exchange.exchange_has('ASDFASDF') From 85c60519b0d9c3642fd6f20e8d948b74783a6b71 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 9 Jul 2018 22:11:12 +0200 Subject: [PATCH 6/6] Fix test crash --- freqtrade/exchange/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index d87d3fc85..972ff49ca 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -70,8 +70,9 @@ class Exchange(object): # Check if all pairs are available self.validate_pairs(config['exchange']['pair_whitelist']) - # Check if timeframe is available - self.validate_timeframes(config['ticker_interval']) + if config.get('ticker_interval'): + # Check if timeframe is available + self.validate_timeframes(config['ticker_interval']) def _init_ccxt(self, exchange_config: dict) -> ccxt.Exchange: """