From 6e27c47dee53d71149c875b43f37fd2c95cf1788 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Mon, 14 Oct 2019 13:32:39 +0300 Subject: [PATCH] Handle properly exchanges with no active flag set for markets --- freqtrade/exchange/__init__.py | 2 ++ freqtrade/exchange/exchange.py | 26 ++++++++++++++++++-- freqtrade/utils.py | 45 +++++++++++++++++++--------------- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 29971c897..470091181 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -10,5 +10,7 @@ from freqtrade.exchange.exchange import (timeframe_to_seconds, # noqa: F401 timeframe_to_msecs, timeframe_to_next_date, timeframe_to_prev_date) +from freqtrade.exchange.exchange import (market_is_active, # noqa: F401 + market_is_pair) from freqtrade.exchange.kraken import Kraken # noqa: F401 from freqtrade.exchange.binance import Binance # noqa: F401 diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index a312d6c62..185c9dc3d 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -289,14 +289,17 @@ class Exchange: TODO: consider moving it to the Dataprovider """ markets = self.markets + if not markets: + raise OperationalException("Markets were not loaded.") + if base_currency: markets = {k: v for k, v in markets.items() if v['base'] == base_currency} if quote_currency: markets = {k: v for k, v in markets.items() if v['quote'] == quote_currency} if pairs_only: - markets = {k: v for k, v in markets.items() if '/' in v['symbol']} + markets = {k: v for k, v in markets.items() if market_is_pair(v)} if active_only: - markets = {k: v for k, v in markets.items() if v['active']} + markets = {k: v for k, v in markets.items() if market_is_active(v)} return markets def klines(self, pair_interval: Tuple[str, str], copy=True) -> DataFrame: @@ -932,3 +935,22 @@ def timeframe_to_next_date(timeframe: str, date: datetime = None) -> datetime: new_timestamp = ccxt.Exchange.round_timeframe(timeframe, date.timestamp() * 1000, ROUND_UP) // 1000 return datetime.fromtimestamp(new_timestamp, tz=timezone.utc) + + +def market_is_pair(market): + """ + Return True if the market is a pair. + Currently pairs are defined as markets containing '/' character in its symbol. + """ + return '/' in market.get('symbol', '') + + +def market_is_active(market): + """ + Return True if the market is active. + """ + # "It's active, if the active flag isn't explicitly set to false. If it's missing or + # true then it's true. If it's undefined, then it's most likely true, but not 100% )" + # See https://github.com/ccxt/ccxt/issues/4874, + # https://github.com/ccxt/ccxt/issues/4075#issuecomment-434760520 + return market.get('active', True) is not False diff --git a/freqtrade/utils.py b/freqtrade/utils.py index 3f25778a4..67a981461 100644 --- a/freqtrade/utils.py +++ b/freqtrade/utils.py @@ -10,7 +10,7 @@ from freqtrade import OperationalException from freqtrade.configuration import Configuration, TimeRange from freqtrade.configuration.directory_operations import create_userdata_dir from freqtrade.data.history import refresh_backtest_ohlcv_data -from freqtrade.exchange import available_exchanges, ccxt_exchanges +from freqtrade.exchange import (available_exchanges, ccxt_exchanges, market_is_active) from freqtrade.misc import plural from freqtrade.resolvers import ExchangeResolver from freqtrade.state import RunMode @@ -137,25 +137,30 @@ def start_list_pairs(args: Dict[str, Any], pairs_only: bool = False) -> None: base_currency = args.get('base_currency', '') quote_currency = args.get('quote_currency', '') - pairs = exchange.get_markets(base_currency=base_currency, - quote_currency=quote_currency, - pairs_only=pairs_only, - active_only=active_only) + try: + pairs = exchange.get_markets(base_currency=base_currency, + quote_currency=quote_currency, + pairs_only=pairs_only, + active_only=active_only) + except Exception as e: + raise OperationalException(f"Cannot get markets. Reason: {e}") from e - if args.get('print_list', False): - # print data as a list - print(f"Exchange {exchange.name} has {len(pairs)} " + - (plural(len(pairs), "pair" if pairs_only else "market")) + - (f" with {base_currency} as base currency" if base_currency else "") + - (" and" if base_currency and quote_currency else "") + - (f" with {quote_currency} as quote currency" if quote_currency else "") + - (f": {sorted(pairs.keys())}" if len(pairs) else "") + ".") else: - # print data as a table - tabular_data = [] - for _, v in pairs.items(): - tabular_data.append([v['id'], v['symbol'], v['base'], v['quote'], - "Yes" if v['active'] else "No"]) + if args.get('print_list', False): + # print data as a list + print(f"Exchange {exchange.name} has {len(pairs)} " + + ("active " if active_only else "") + + (plural(len(pairs), "pair" if pairs_only else "market")) + + (f" with {base_currency} as base currency" if base_currency else "") + + (" and" if base_currency and quote_currency else "") + + (f" with {quote_currency} as quote currency" if quote_currency else "") + + (f": {sorted(pairs.keys())}" if len(pairs) else "") + ".") + else: + # print data as a table + tabular_data = [] + for _, v in pairs.items(): + tabular_data.append([v['id'], v['symbol'], v['base'], v['quote'], + "Yes" if market_is_active(v) else "No"]) - headers = ['Id', 'Symbol', 'Base', 'Quote', 'Active'] - print(tabulate(tabular_data, headers=headers, tablefmt='pipe')) + headers = ['Id', 'Symbol', 'Base', 'Quote', 'Active'] + print(tabulate(tabular_data, headers=headers, tablefmt='pipe'))