diff --git a/freqtrade/main.py b/freqtrade/main.py index ff5d4b5aa..7fc7654ed 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -27,23 +27,27 @@ _CONF = {} def refresh_whitelist(whitelist: List[str]) -> List[str]: """ Check wallet health and remove pair from whitelist if necessary - :param whitelist: the pair the user might want to trade + :param whitelist: the sorted list (based on BaseVolume) of pairs the user might want to trade :return: the list of pairs the user wants to trade without the one unavailable or black_listed """ - sanitized_whitelist = [] + sanitized_whitelist = whitelist health = exchange.get_wallet_health() + known_pairs = set() for status in health: pair = '{}_{}'.format(_CONF['stake_currency'], status['Currency']) + known_pairs.add(pair) if pair not in whitelist or pair in _CONF['exchange'].get('pair_blacklist', []): continue - if status['IsActive']: - sanitized_whitelist.append(pair) - else: + if not status['IsActive']: + sanitized_whitelist.remove(pair) logger.info( 'Ignoring %s from whitelist (reason: %s).', pair, status.get('Notice') or 'wallet is not active' ) - return sanitized_whitelist + + # We need to remove pairs that are unknown + final_list = [x for x in sanitized_whitelist if x in known_pairs] + return final_list def _process(nb_assets: Optional[int] = 0) -> bool: diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 984ca3e72..47be60802 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -41,27 +41,29 @@ def generate_text_table( Generates and returns a text table for the given backtest data and the results dataframe :return: pretty printed table with tabulate as str """ + floatfmt = ('s', 'd', '.2f', '.8f', '.1f') tabular_data = [] - headers = ['pair', 'buy count', 'avg profit', 'total profit', 'avg duration'] + headers = ['pair', 'buy count', 'avg profit %', + 'total profit ' + stake_currency, 'avg duration'] for pair in data: result = results[results.currency == pair] tabular_data.append([ pair, len(result.index), - '{:.2f}%'.format(result.profit_percent.mean() * 100.0), - '{:.08f} {}'.format(result.profit_BTC.sum(), stake_currency), - '{:.2f}'.format(result.duration.mean() * ticker_interval), + result.profit_percent.mean() * 100.0, + result.profit_BTC.sum(), + result.duration.mean() * ticker_interval, ]) # Append Total tabular_data.append([ 'TOTAL', len(results.index), - '{:.2f}%'.format(results.profit_percent.mean() * 100.0), - '{:.08f} {}'.format(results.profit_BTC.sum(), stake_currency), - '{:.2f}'.format(results.duration.mean() * ticker_interval), + results.profit_percent.mean() * 100.0, + results.profit_BTC.sum(), + results.duration.mean() * ticker_interval, ]) - return tabulate(tabular_data, headers=headers) + return tabulate(tabular_data, headers=headers, floatfmt=floatfmt) def backtest(stake_amount: float, processed: Dict[str, DataFrame], @@ -173,6 +175,6 @@ def start(args): config['stake_amount'], preprocess(data), max_open_trades, args.realistic_simulation ) logger.info( - '\n====================== BACKTESTING REPORT ======================================\n%s', + '\n====================== BACKTESTING REPORT ================================\n%s', generate_text_table(data, results, config['stake_currency'], args.ticker_interval) ) diff --git a/freqtrade/tests/optimize/test_backtesting.py b/freqtrade/tests/optimize/test_backtesting.py index 94c062cac..e3e34de1d 100644 --- a/freqtrade/tests/optimize/test_backtesting.py +++ b/freqtrade/tests/optimize/test_backtesting.py @@ -18,11 +18,12 @@ def test_generate_text_table(): 'duration': [10, 30] } ) + print(generate_text_table({'BTC_ETH': {}}, results, 'BTC', 5)) assert generate_text_table({'BTC_ETH': {}}, results, 'BTC', 5) == ( - 'pair buy count avg profit total profit avg duration\n' - '------- ----------- ------------ -------------- --------------\n' - 'BTC_ETH 2 15.00% 0.60000000 BTC 100\n' - 'TOTAL 2 15.00% 0.60000000 BTC 100') + 'pair buy count avg profit % total profit BTC avg duration\n' + '------- ----------- -------------- ------------------ --------------\n' + 'BTC_ETH 2 15.00 0.60000000 100.0\n' + 'TOTAL 2 15.00 0.60000000 100.0') def test_get_timeframe(): diff --git a/freqtrade/tests/test_acl_pair.py b/freqtrade/tests/test_acl_pair.py index 0067eb302..1368ac25c 100644 --- a/freqtrade/tests/test_acl_pair.py +++ b/freqtrade/tests/test_acl_pair.py @@ -16,24 +16,43 @@ def whitelist_conf(): "BTC_SWT", "BTC_BCC" ], + "pair_blacklist": [ + "BTC_BLK" + ], }, } def get_health(): return [{'Currency': 'ETH', - 'IsActive': True + 'IsActive': True, + 'BaseVolume': 42 }, {'Currency': 'TKN', - 'IsActive': True - }] + 'IsActive': True, + 'BaseVolume': 1664 + }, + {'Currency': 'BLK', + 'IsActive': True, + 'BaseVolume': 4096 + } + ] def get_health_empty(): return [] -# below three test could be merged into a single -# test that ran randomlly generated health lists + +def test_refresh_market_pair_not_in_whitelist(mocker): + conf = whitelist_conf() + mocker.patch.dict('freqtrade.main._CONF', conf) + mocker.patch.multiple('freqtrade.main.exchange', + get_wallet_health=get_health) + refreshedwhitelist = refresh_whitelist(conf['exchange']['pair_whitelist'] + ['BTC_XXX']) + # List ordered by BaseVolume + whitelist = ['BTC_ETH', 'BTC_TKN'] + # Ensure all except those in whitelist are removed + assert whitelist == refreshedwhitelist def test_refresh_whitelist(mocker): @@ -42,9 +61,10 @@ def test_refresh_whitelist(mocker): mocker.patch.multiple('freqtrade.main.exchange', get_wallet_health=get_health) refreshedwhitelist = refresh_whitelist(conf['exchange']['pair_whitelist']) + # List ordered by BaseVolume whitelist = ['BTC_ETH', 'BTC_TKN'] # Ensure all except those in whitelist are removed - assert set(whitelist) == set(refreshedwhitelist) + assert whitelist == refreshedwhitelist def test_refresh_whitelist_dynamic(mocker): @@ -53,9 +73,9 @@ def test_refresh_whitelist_dynamic(mocker): mocker.patch.multiple('freqtrade.main.exchange', get_wallet_health=get_health) # argument: use the whitelist dynamically by exchange-volume - whitelist = ['BTC_ETH', 'BTC_TKN'] + whitelist = ['BTC_TKN', 'BTC_ETH'] refreshedwhitelist = refresh_whitelist(whitelist) - assert set(whitelist) == set(refreshedwhitelist) + assert whitelist == refreshedwhitelist def test_refresh_whitelist_dynamic_empty(mocker):