diff --git a/freqtrade/constants.py b/freqtrade/constants.py index f1cb03d26..a22a06ebe 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -37,7 +37,7 @@ CONF_SCHEMA = { 'properties': { 'max_open_trades': {'type': 'integer', 'minimum': 0}, 'ticker_interval': {'type': 'string', 'enum': list(TICKER_INTERVAL_MINUTES.keys())}, - 'stake_currency': {'type': 'string', 'enum': ['BTC', 'ETH', 'USDT']}, + 'stake_currency': {'type': 'string', 'enum': ['BTC', 'ETH', 'USDT', 'EUR', 'USD']}, 'stake_amount': {'type': 'number', 'minimum': 0.0005}, 'fiat_display_currency': {'type': 'string', 'enum': SUPPORTED_FIAT}, 'dry_run': {'type': 'boolean'}, diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index b186f3611..3c67db71f 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -294,6 +294,11 @@ def get_ticker_history(pair: str, tick_interval: str, since_ms: Optional[int] = while not since_ms or since_ms < till_time_ms: data_part = _API.fetch_ohlcv(pair, timeframe=tick_interval, since=since_ms) + # Because some exchange sort Tickers ASC and other DESC. + # Ex: Bittrex returns a list of tickers ASC (oldest first, newest last) + # when GDAX returns a list of tickers DESC (newest first, oldest last) + data_part = sorted(data_part, key=lambda x: x[0]) + if not data_part: break diff --git a/freqtrade/fiat_convert.py b/freqtrade/fiat_convert.py index a653ad76e..3fc8acb3c 100644 --- a/freqtrade/fiat_convert.py +++ b/freqtrade/fiat_convert.py @@ -88,8 +88,11 @@ class CryptoToFiatConverter(object): coinlistings = self._coinmarketcap.listings() self._cryptomap = dict(map(lambda coin: (coin["symbol"], str(coin["id"])), coinlistings["data"])) - except (ValueError, RequestException) as e: - logger.error("Could not load FIAT Cryptocurrency map for the following problem: %s", e) + except (ValueError, RequestException) as exception: + logger.error( + "Could not load FIAT Cryptocurrency map for the following problem: %s", + exception + ) def convert_amount(self, crypto_amount: float, crypto_symbol: str, fiat_symbol: str) -> float: """ @@ -181,6 +184,10 @@ class CryptoToFiatConverter(object): if not self._is_supported_fiat(fiat=fiat_symbol): raise ValueError('The fiat {} is not supported.'.format(fiat_symbol)) + # No need to convert if both crypto and fiat are the same + if crypto_symbol == fiat_symbol: + return 1.0 + if crypto_symbol not in self._cryptomap: # return 0 for unsupported stake currencies (fiat-convert should not break the bot) logger.warning("unsupported crypto-symbol %s - returning 0.0", crypto_symbol) @@ -192,6 +199,6 @@ class CryptoToFiatConverter(object): convert=fiat_symbol )['data']['quotes'][fiat_symbol.upper()]['price'] ) - except BaseException as ex: - logger.error("Error in _find_price: %s", ex) + except BaseException as exception: + logger.error("Error in _find_price: %s", exception) return 0.0 diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index a506a8416..56812c75e 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -393,6 +393,78 @@ def test_get_ticker_history(default_conf, mocker): get_ticker_history('EFGH/BTC', default_conf['ticker_interval']) +def test_get_ticker_history_sort(default_conf, mocker): + api_mock = MagicMock() + + # GDAX use-case (real data from GDAX) + # This ticker history is ordered DESC (newest first, oldest last) + tick = [ + [1527833100000, 0.07666, 0.07671, 0.07666, 0.07668, 16.65244264], + [1527832800000, 0.07662, 0.07666, 0.07662, 0.07666, 1.30051526], + [1527832500000, 0.07656, 0.07661, 0.07656, 0.07661, 12.034778840000001], + [1527832200000, 0.07658, 0.07658, 0.07655, 0.07656, 0.59780186], + [1527831900000, 0.07658, 0.07658, 0.07658, 0.07658, 1.76278136], + [1527831600000, 0.07658, 0.07658, 0.07658, 0.07658, 2.22646521], + [1527831300000, 0.07655, 0.07657, 0.07655, 0.07657, 1.1753], + [1527831000000, 0.07654, 0.07654, 0.07651, 0.07651, 0.8073060299999999], + [1527830700000, 0.07652, 0.07652, 0.07651, 0.07652, 10.04822687], + [1527830400000, 0.07649, 0.07651, 0.07649, 0.07651, 2.5734867] + ] + type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True}) + api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(tick)) + mocker.patch('freqtrade.exchange._API', api_mock) + + # Test the ticker history sort + ticks = get_ticker_history('ETH/BTC', default_conf['ticker_interval']) + assert ticks[0][0] == 1527830400000 + assert ticks[0][1] == 0.07649 + assert ticks[0][2] == 0.07651 + assert ticks[0][3] == 0.07649 + assert ticks[0][4] == 0.07651 + assert ticks[0][5] == 2.5734867 + + assert ticks[9][0] == 1527833100000 + assert ticks[9][1] == 0.07666 + assert ticks[9][2] == 0.07671 + assert ticks[9][3] == 0.07666 + assert ticks[9][4] == 0.07668 + assert ticks[9][5] == 16.65244264 + + # Bittrex use-case (real data from Bittrex) + # This ticker history is ordered ASC (oldest first, newest last) + tick = [ + [1527827700000, 0.07659999, 0.0766, 0.07627, 0.07657998, 1.85216924], + [1527828000000, 0.07657995, 0.07657995, 0.0763, 0.0763, 26.04051037], + [1527828300000, 0.0763, 0.07659998, 0.0763, 0.0764, 10.36434124], + [1527828600000, 0.0764, 0.0766, 0.0764, 0.0766, 5.71044773], + [1527828900000, 0.0764, 0.07666998, 0.0764, 0.07666998, 47.48888565], + [1527829200000, 0.0765, 0.07672999, 0.0765, 0.07672999, 3.37640326], + [1527829500000, 0.0766, 0.07675, 0.0765, 0.07675, 8.36203831], + [1527829800000, 0.07675, 0.07677999, 0.07620002, 0.076695, 119.22963884], + [1527830100000, 0.076695, 0.07671, 0.07624171, 0.07671, 1.80689244], + [1527830400000, 0.07671, 0.07674399, 0.07629216, 0.07655213, 2.31452783] + ] + type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True}) + api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(tick)) + mocker.patch('freqtrade.exchange._API', api_mock) + + # Test the ticker history sort + ticks = get_ticker_history('ETH/BTC', default_conf['ticker_interval']) + assert ticks[0][0] == 1527827700000 + assert ticks[0][1] == 0.07659999 + assert ticks[0][2] == 0.0766 + assert ticks[0][3] == 0.07627 + assert ticks[0][4] == 0.07657998 + assert ticks[0][5] == 1.85216924 + + assert ticks[9][0] == 1527830400000 + assert ticks[9][1] == 0.07671 + assert ticks[9][2] == 0.07674399 + assert ticks[9][3] == 0.07629216 + assert ticks[9][4] == 0.07655213 + assert ticks[9][5] == 2.31452783 + + def test_cancel_order_dry_run(default_conf, mocker): default_conf['dry_run'] = True mocker.patch.dict('freqtrade.exchange._CONF', default_conf) diff --git a/freqtrade/tests/test_fiat_convert.py b/freqtrade/tests/test_fiat_convert.py index b37ca0f5c..faf7462c0 100644 --- a/freqtrade/tests/test_fiat_convert.py +++ b/freqtrade/tests/test_fiat_convert.py @@ -126,6 +126,20 @@ def test_fiat_convert_get_price(mocker): assert fiat_convert._pairs[0]._expiration is not expiration +def test_fiat_convert_same_currencies(mocker): + patch_coinmarketcap(mocker) + fiat_convert = CryptoToFiatConverter() + + assert fiat_convert.get_price(crypto_symbol='USD', fiat_symbol='USD') == 1.0 + + +def test_fiat_convert_two_FIAT(mocker): + patch_coinmarketcap(mocker) + fiat_convert = CryptoToFiatConverter() + + assert fiat_convert.get_price(crypto_symbol='USD', fiat_symbol='EUR') == 0.0 + + def test_loadcryptomap(mocker): patch_coinmarketcap(mocker)