diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 25d3e62c0..0ca939ec5 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -715,7 +715,9 @@ class Exchange(object): @retrier def get_markets(self) -> List[dict]: try: - return self._api.fetch_markets() + markets = self._api.fetch_markets() + self.markets.update({m["symbol"]: m for m in markets}) + return markets except (ccxt.NetworkError, ccxt.ExchangeError) as e: raise TemporaryError( f'Could not load markets due to {e.__class__.__name__}. Message: {e}') diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 86f739f2f..28a7c9146 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -206,7 +206,7 @@ class FreqtradeBot(object): self.state = State.STOPPED return state_changed - def get_target_bid(self, pair: str, ticker: Dict = None) -> float: + def get_target_bid(self, pair: str, tick: Dict = None) -> float: """ Calculates bid target between current ask price and last price :return: float: Price @@ -223,9 +223,11 @@ class FreqtradeBot(object): logger.info('...top %s order book buy rate %0.8f', order_book_top, order_book_rate) used_rate = order_book_rate else: - if not ticker: + if not tick: logger.info('Using Last Ask / Last Price') ticker = self.exchange.get_ticker(pair) + else: + ticker = tick if ticker['ask'] < ticker['last']: ticker_rate = ticker['ask'] else: @@ -270,10 +272,12 @@ class FreqtradeBot(object): return stake_amount def _get_min_pair_stake_amount(self, pair: str, price: float) -> Optional[float]: - try: - market = self.exchange.markets[pair] - except KeyError: - raise ValueError(f"Can't get market information for symbol {pair}") + markets = self.exchange.get_markets() + markets = [m for m in markets if m['symbol'] == pair] + if not markets: + raise ValueError(f'Can\'t get market information for symbol {pair}') + + market = markets[0] if 'limits' not in market: return None diff --git a/freqtrade/pairlist/IPairList.py b/freqtrade/pairlist/IPairList.py index 4e9e28b3d..7675c1eee 100644 --- a/freqtrade/pairlist/IPairList.py +++ b/freqtrade/pairlist/IPairList.py @@ -18,7 +18,7 @@ class IPairList(ABC): self._config = config self._whitelist = self._config['exchange']['pair_whitelist'] self._blacklist = self._config['exchange'].get('pair_blacklist', []) - self._markets = self._freqtrade.exchange.markets + self._markets = self._freqtrade.exchange.get_markets() @property def name(self) -> str: @@ -67,7 +67,7 @@ class IPairList(ABC): black_listed """ sanitized_whitelist = whitelist - markets = list(self._markets.values()) + markets = self._freqtrade.exchange.get_markets() # Filter to markets in stake currency markets = [m for m in markets if m['quote'] == self._config['stake_currency']] @@ -75,7 +75,7 @@ class IPairList(ABC): for market in markets: pair = market['symbol'] - # pair is not int the generated dynamic market, or in the blacklist ... ignore it + # pair is not in the generated dynamic market, or in the blacklist ... ignore it if pair not in whitelist or pair in self.blacklist: continue # else the pair is valid diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index d6628d925..98171844a 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -375,6 +375,78 @@ def markets(): }, }, 'info': '', + }, + { + 'id': 'BTTBTC', + 'symbol': 'BTT/BTC', + 'base': 'BTT', + 'quote': 'BTC', + 'active': True, + 'precision': { + 'base': 8, + 'quote': 8, + 'amount': 0, + 'price': 8 + }, + 'limits': { + 'amount': { + 'min': 1.0, + 'max': 90000000.0 + }, + 'price': { + 'min': None, + 'max': None + }, + 'cost': { + 'min': 0.001, + 'max': None + } + }, + 'info': "", + }, + { + 'id': 'USDT-ETH', + 'symbol': 'ETH/USDT', + 'base': 'ETH', + 'quote': 'USDT', + 'precision': { + 'amount': 8, + 'price': 8 + }, + 'limits': { + 'amount': { + 'min': 0.02214286, + 'max': None + }, + 'price': { + 'min': 1e-08, + 'max': None + } + }, + 'active': True, + 'info': "" + }, + { + 'id': 'USDT-LTC', + 'symbol': 'LTC/USDT', + 'base': 'LTC', + 'quote': 'USDT', + 'active': True, + 'precision': { + 'amount': 8, + 'price': 8 + }, + 'limits': { + 'amount': { + 'min': 0.06646786, + 'max': None + }, + 'price': { + 'min': 1e-08, + 'max': None + } + }, + 'info': "" } ]) @@ -642,6 +714,28 @@ def tickers(): 'quoteVolume': 1401.65697943, 'info': {} }, + 'BTT/BTC': { + 'symbol': 'BTT/BTC', + 'timestamp': 1550936557206, + 'datetime': '2019-02-23T15:42:37.206Z', + 'high': 0.00000026, + 'low': 0.00000024, + 'bid': 0.00000024, + 'bidVolume': 2446894197.0, + 'ask': 0.00000025, + 'askVolume': 2447913837.0, + 'vwap': 0.00000025, + 'open': 0.00000026, + 'close': 0.00000024, + 'last': 0.00000024, + 'previousClose': 0.00000026, + 'change': -0.00000002, + 'percentage': -7.692, + 'average': None, + 'baseVolume': 4886464537.0, + 'quoteVolume': 1215.14489611, + 'info': {} + }, 'ETH/USDT': { 'symbol': 'ETH/USDT', 'timestamp': 1522014804118, diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index 15da5e924..4fadfd4b7 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -1264,7 +1264,7 @@ def test_get_markets(default_conf, mocker, markets): exchange = get_patched_exchange(mocker, default_conf, api_mock) ret = exchange.get_markets() assert isinstance(ret, list) - assert len(ret) == 6 + assert len(ret) == 9 assert ret[0]["id"] == "ethbtc" assert ret[0]["symbol"] == "ETH/BTC" diff --git a/freqtrade/tests/pairlist/test_pairlist.py b/freqtrade/tests/pairlist/test_pairlist.py index 9f90aac6e..e78404587 100644 --- a/freqtrade/tests/pairlist/test_pairlist.py +++ b/freqtrade/tests/pairlist/test_pairlist.py @@ -80,7 +80,7 @@ def test_refresh_pairlist_dynamic(mocker, markets, tickers, whitelist_conf): freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf) # argument: use the whitelist dynamically by exchange-volume - whitelist = ['ETH/BTC', 'TKN/BTC'] + whitelist = ['ETH/BTC', 'TKN/BTC', 'BTT/BTC'] freqtradebot.pairlists.refresh_pairlist() assert whitelist == freqtradebot.pairlists.whitelist @@ -116,17 +116,19 @@ def test_VolumePairList_whitelist_gen(mocker, whitelist_conf, markets, tickers) # Test to retrieved BTC sorted on quoteVolume (default) whitelist = freqtrade.pairlists._gen_pair_whitelist(base_currency='BTC', key='quoteVolume') - assert whitelist == ['ETH/BTC', 'TKN/BTC', 'BLK/BTC', 'LTC/BTC'] + assert whitelist == ['ETH/BTC', 'TKN/BTC', 'BTT/BTC'] # Test to retrieve BTC sorted on bidVolume whitelist = freqtrade.pairlists._gen_pair_whitelist(base_currency='BTC', key='bidVolume') - assert whitelist == ['LTC/BTC', 'TKN/BTC', 'ETH/BTC', 'BLK/BTC'] + assert whitelist == ['BTT/BTC', 'TKN/BTC', 'ETH/BTC'] # Test with USDT sorted on quoteVolume (default) + freqtrade.config['stake_currency'] = 'USDT' # this has to be set, otherwise markets are removed whitelist = freqtrade.pairlists._gen_pair_whitelist(base_currency='USDT', key='quoteVolume') - assert whitelist == ['TKN/USDT', 'ETH/USDT', 'LTC/USDT', 'BLK/USDT'] + assert whitelist == ['ETH/USDT', 'LTC/USDT'] # Test with ETH (our fixture does not have ETH, so result should be empty) + freqtrade.config['stake_currency'] = 'ETH' whitelist = freqtrade.pairlists._gen_pair_whitelist(base_currency='ETH', key='quoteVolume') assert whitelist == []