From 13274964a94a38975e66b8963c1c5622a7cec022 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Jan 2020 11:53:44 +0100 Subject: [PATCH] Implement validation for valid stake currency --- freqtrade/constants.py | 2 +- freqtrade/exchange/exchange.py | 25 +++++++++++++++++++++++-- tests/conftest.py | 1 + 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 598a64337..53bc4af53 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -61,7 +61,7 @@ CONF_SCHEMA = { 'properties': { 'max_open_trades': {'type': ['integer', 'number'], 'minimum': -1}, 'ticker_interval': {'type': 'string'}, - 'stake_currency': {'type': 'string', 'enum': ['BTC', 'XBT', 'ETH', 'USDT', 'EUR', 'USD']}, + 'stake_currency': {'type': 'string'}, 'stake_amount': { 'type': ['number', 'string'], 'minimum': 0.0001, diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 1ee6c2f1c..e15f6885c 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -116,6 +116,7 @@ class Exchange: self._load_markets() # Check if all pairs are available + self.validate_stakecurrency(config['stake_currency']) 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', {})) @@ -210,6 +211,14 @@ class Exchange: markets = {k: v for k, v in markets.items() if market_is_active(v)} return markets + def get_quote_currencies(self) -> List[str]: + """ + Return a list of supported quote currencies + """ + markets = self.markets + currencies = set([x['quote'] for _, x in markets.items()]) + return list(currencies) + def klines(self, pair_interval: Tuple[str, str], copy=True) -> DataFrame: if pair_interval in self._klines: return self._klines[pair_interval].copy() if copy else self._klines[pair_interval] @@ -259,11 +268,23 @@ class Exchange: except ccxt.BaseError: logger.exception("Could not reload markets.") + def validate_stakecurrency(self, stake_currency) -> None: + """ + Checks stake-currency against available currencies on the exchange. + :param stake_currency: Stake-currency to validate + :raise: OperationalException if stake-currency is not available. + """ + quote_currencies = self.get_quote_currencies() + if stake_currency not in quote_currencies: + raise OperationalException( + f"{stake_currency} is not available as stake on {self.name}." + f"Available currencies are: {','.join(quote_currencies)}") + def validate_pairs(self, pairs: List[str]) -> None: """ Checks if all given pairs are tradable on the current exchange. - Raises OperationalException if one pair is not available. :param pairs: list of pairs + :raise: OperationalException if one pair is not available :return: None """ @@ -319,7 +340,7 @@ class Exchange: raise OperationalException( f"Invalid ticker interval '{timeframe}'. This exchange supports: {self.timeframes}") - if timeframe_to_minutes(timeframe) < 1: + if timeframe and timeframe_to_minutes(timeframe) < 1: raise OperationalException( f"Timeframes < 1m are currently not supported by Freqtrade.") diff --git a/tests/conftest.py b/tests/conftest.py index 7bb4cf4c9..ac1b10284 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -60,6 +60,7 @@ def patch_exchange(mocker, api_mock=None, id='bittrex', mock_markets=True) -> No mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_ordertypes', MagicMock()) + mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.id', PropertyMock(return_value=id)) mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value=id.title())) if mock_markets: