From 8c64be3cfd618ba3e69dc30c1cb4096d4a56b693 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 14 Nov 2019 07:01:23 +0100 Subject: [PATCH 01/18] get tickers only once to show balance --- freqtrade/rpc/rpc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 8898f3068..f2851e0e1 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -301,6 +301,7 @@ class RPC: """ Returns current account balance per crypto """ output = [] total = 0.0 + tickers = self._freqtrade.exchange.get_tickers() for coin, balance in self._freqtrade.exchange.get_balances().items(): if not balance['total']: continue @@ -310,10 +311,11 @@ class RPC: else: try: pair = self._freqtrade.exchange.get_valid_pair_combination(coin, "BTC") + if pair.startswith("BTC"): - rate = 1.0 / self._freqtrade.get_sell_rate(pair, False) + rate = 1.0 / tickers.get(pair, {}).get('bid', 1) else: - rate = self._freqtrade.get_sell_rate(pair, False) + rate = tickers.get(pair, {}).get('bid', 1) except (TemporaryError, DependencyException): logger.warning(f" Could not get rate for pair {coin}.") continue From 62d50f512d82c9988897425b5013f718ae039f34 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 14 Nov 2019 20:12:41 +0100 Subject: [PATCH 02/18] add tests for balance from get-tickers --- freqtrade/rpc/rpc.py | 6 +++- tests/conftest.py | 50 +++++++++++++++++++++++++++++++-- tests/pairlist/test_pairlist.py | 16 +++++------ tests/rpc/test_rpc.py | 38 +++++++++---------------- tests/rpc/test_rpc_telegram.py | 23 ++------------- 5 files changed, 75 insertions(+), 58 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index f2851e0e1..e338cd6dd 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -301,7 +301,11 @@ class RPC: """ Returns current account balance per crypto """ output = [] total = 0.0 - tickers = self._freqtrade.exchange.get_tickers() + try: + tickers = self._freqtrade.exchange.get_tickers() + except (TemporaryError, DependencyException): + raise RPCException('Error getting current tickers.') + for coin, balance in self._freqtrade.exchange.get_balances().items(): if not balance['total']: continue diff --git a/tests/conftest.py b/tests/conftest.py index fbd23a0dc..bc6599e4d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -980,6 +980,28 @@ def tickers(): 'quoteVolume': 62.68220262, 'info': {} }, + 'BTC/USDT': { + 'symbol': 'BTC/USDT', + 'timestamp': 1573758371399, + 'datetime': '2019-11-14T19:06:11.399Z', + 'high': 8800.0, + 'low': 8582.6, + 'bid': 8648.16, + 'bidVolume': 0.238771, + 'ask': 8648.72, + 'askVolume': 0.016253, + 'vwap': 8683.13647806, + 'open': 8759.7, + 'close': 8648.72, + 'last': 8648.72, + 'previousClose': 8759.67, + 'change': -110.98, + 'percentage': -1.267, + 'average': None, + 'baseVolume': 35025.943355, + 'quoteVolume': 304135046.4242901, + 'info': {} + }, 'ETH/USDT': { 'symbol': 'ETH/USDT', 'timestamp': 1522014804118, @@ -1067,7 +1089,29 @@ def tickers(): 'baseVolume': 59698.79897, 'quoteVolume': 29132399.743954, 'info': {} - } + }, + 'XRP/BTC': { + 'symbol': 'XRP/BTC', + 'timestamp': 1573758257534, + 'datetime': '2019-11-14T19:04:17.534Z', + 'high': 3.126e-05, + 'low': 3.061e-05, + 'bid': 3.093e-05, + 'bidVolume': 27901.0, + 'ask': 3.095e-05, + 'askVolume': 10551.0, + 'vwap': 3.091e-05, + 'open': 3.119e-05, + 'close': 3.094e-05, + 'last': 3.094e-05, + 'previousClose': 3.117e-05, + 'change': -2.5e-07, + 'percentage': -0.802, + 'average': None, + 'baseVolume': 37334921.0, + 'quoteVolume': 1154.19266394, + 'info': {} + }, }) @@ -1317,8 +1361,8 @@ def rpc_balance(): 'used': 0.0 }, 'XRP': { - 'total': 1.0, - 'free': 1.0, + 'total': 0.1, + 'free': 0.01, 'used': 0.0 }, 'EUR': { diff --git a/tests/pairlist/test_pairlist.py b/tests/pairlist/test_pairlist.py index 76537880c..460f2ddcf 100644 --- a/tests/pairlist/test_pairlist.py +++ b/tests/pairlist/test_pairlist.py @@ -100,7 +100,7 @@ def test_refresh_pairlist_dynamic(mocker, shitcoinmarkets, tickers, whitelist_co markets=PropertyMock(return_value=shitcoinmarkets), ) # argument: use the whitelist dynamically by exchange-volume - whitelist = ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'HOT/BTC', 'FUEL/BTC'] + whitelist = ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC', 'HOT/BTC'] bot.pairlists.refresh_pairlist() assert whitelist == bot.pairlists.whitelist @@ -135,10 +135,10 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf): @pytest.mark.parametrize("pairlists,base_currency,whitelist_result", [ ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}], - "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'HOT/BTC', 'FUEL/BTC']), + "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC', 'HOT/BTC']), # Different sorting depending on quote or bid volume ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "bidVolume"}], - "BTC", ['HOT/BTC', 'FUEL/BTC', 'LTC/BTC', 'TKN/BTC', 'ETH/BTC']), + "BTC", ['HOT/BTC', 'FUEL/BTC', 'XRP/BTC', 'LTC/BTC', 'TKN/BTC']), ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}], "USDT", ['ETH/USDT']), # No pair for ETH ... @@ -146,19 +146,19 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf): "ETH", []), # Precisionfilter and quote volume ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}, - {"method": "PrecisionFilter"}], "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'FUEL/BTC']), + {"method": "PrecisionFilter"}], "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC']), # Precisionfilter bid ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "bidVolume"}, - {"method": "PrecisionFilter"}], "BTC", ['FUEL/BTC', 'LTC/BTC', 'TKN/BTC', 'ETH/BTC']), + {"method": "PrecisionFilter"}], "BTC", ['FUEL/BTC', 'XRP/BTC', 'LTC/BTC', 'TKN/BTC']), # PriceFilter and VolumePairList ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}, {"method": "PriceFilter", "low_price_ratio": 0.03}], - "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'FUEL/BTC']), + "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC']), # Hot is removed by precision_filter, Fuel by low_price_filter. - ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}, + ([{"method": "VolumePairList", "number_assets": 6, "sort_key": "quoteVolume"}, {"method": "PrecisionFilter"}, {"method": "PriceFilter", "low_price_ratio": 0.02} - ], "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC']), + ], "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC']), # StaticPairlist Only ([{"method": "StaticPairList"}, ], "BTC", ['ETH/BTC', 'TKN/BTC']), diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index fb7a5276a..d745212ac 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -355,29 +355,18 @@ def test_rpc_balance_handle_error(default_conf, mocker): mocker.patch.multiple( 'freqtrade.exchange.Exchange', get_balances=MagicMock(return_value=mock_balance), - get_ticker=MagicMock(side_effect=TemporaryError('Could not load ticker due to xxx')) + get_tickers=MagicMock(side_effect=TemporaryError('Could not load ticker due to xxx')) ) freqtradebot = get_patched_freqtradebot(mocker, default_conf) patch_get_signal(freqtradebot, (True, False)) rpc = RPC(freqtradebot) rpc._fiat_converter = CryptoToFiatConverter() - - result = rpc._rpc_balance(default_conf['fiat_display_currency']) - assert prec_satoshi(result['total'], 12) - assert prec_satoshi(result['value'], 180000) - assert 'USD' == result['symbol'] - assert result['currencies'] == [{ - 'currency': 'BTC', - 'free': 10.0, - 'balance': 12.0, - 'used': 2.0, - 'est_btc': 12.0, - }] - assert result['total'] == 12.0 + with pytest.raises(RPCException, match="Error getting current tickers."): + rpc._rpc_balance(default_conf['fiat_display_currency']) -def test_rpc_balance_handle(default_conf, mocker): +def test_rpc_balance_handle(default_conf, mocker, tickers): mock_balance = { 'BTC': { 'free': 10.0, @@ -389,7 +378,7 @@ def test_rpc_balance_handle(default_conf, mocker): 'total': 5.0, 'used': 4.0, }, - 'PAX': { + 'USDT': { 'free': 5.0, 'total': 10.0, 'used': 5.0, @@ -405,10 +394,9 @@ def test_rpc_balance_handle(default_conf, mocker): mocker.patch.multiple( 'freqtrade.exchange.Exchange', get_balances=MagicMock(return_value=mock_balance), - get_ticker=MagicMock( - side_effect=lambda p, r: {'bid': 100} if p == "BTC/PAX" else {'bid': 0.01}), + get_tickers=tickers, get_valid_pair_combination=MagicMock( - side_effect=lambda a, b: f"{b}/{a}" if a == "PAX" else f"{a}/{b}") + side_effect=lambda a, b: f"{b}/{a}" if a == "USDT" else f"{a}/{b}") ) freqtradebot = get_patched_freqtradebot(mocker, default_conf) @@ -417,8 +405,8 @@ def test_rpc_balance_handle(default_conf, mocker): rpc._fiat_converter = CryptoToFiatConverter() result = rpc._rpc_balance(default_conf['fiat_display_currency']) - assert prec_satoshi(result['total'], 12.15) - assert prec_satoshi(result['value'], 182250) + assert prec_satoshi(result['total'], 12.309096315) + assert prec_satoshi(result['value'], 184636.44472997) assert 'USD' == result['symbol'] assert result['currencies'] == [ {'currency': 'BTC', @@ -430,16 +418,16 @@ def test_rpc_balance_handle(default_conf, mocker): {'free': 1.0, 'balance': 5.0, 'currency': 'ETH', - 'est_btc': 0.05, + 'est_btc': 0.30794, 'used': 4.0 }, {'free': 5.0, 'balance': 10.0, - 'currency': 'PAX', - 'est_btc': 0.1, + 'currency': 'USDT', + 'est_btc': 0.0011563153318162476, 'used': 5.0} ] - assert result['total'] == 12.15 + assert result['total'] == 12.309096315331816 def test_rpc_start(mocker, default_conf) -> None: diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index a33ab8675..89fd90b0b 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -461,29 +461,10 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee, assert '*Best Performing:* `ETH/BTC: 6.20%`' in msg_mock.call_args_list[-1][0][0] -def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance) -> None: - - def mock_ticker(symbol, refresh): - if symbol == 'BTC/USDT': - return { - 'bid': 10000.00, - 'ask': 10000.00, - 'last': 10000.00, - } - elif symbol == 'XRP/BTC': - return { - 'bid': 0.00001, - 'ask': 0.00001, - 'last': 0.00001, - } - return { - 'bid': 0.1, - 'ask': 0.1, - 'last': 0.1, - } +def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance, tickers) -> None: mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value=rpc_balance) - mocker.patch('freqtrade.exchange.Exchange.get_ticker', side_effect=mock_ticker) + mocker.patch('freqtrade.exchange.Exchange.get_tickers', tickers) mocker.patch('freqtrade.exchange.Exchange.get_valid_pair_combination', side_effect=lambda a, b: f"{a}/{b}") From 1bf8d8cff320da2b8e05fd64102faaf33e786e2f Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 15 Nov 2019 06:33:07 +0100 Subject: [PATCH 03/18] show /balance in stake currency --- freqtrade/rpc/api_server.py | 3 ++- freqtrade/rpc/rpc.py | 24 +++++++++++++----------- freqtrade/rpc/telegram.py | 7 ++++--- tests/rpc/test_rpc.py | 25 +++++++++++++++---------- tests/rpc/test_rpc_apiserver.py | 3 ++- tests/rpc/test_rpc_telegram.py | 3 ++- 6 files changed, 38 insertions(+), 27 deletions(-) diff --git a/freqtrade/rpc/api_server.py b/freqtrade/rpc/api_server.py index f87165253..4baca7f22 100644 --- a/freqtrade/rpc/api_server.py +++ b/freqtrade/rpc/api_server.py @@ -354,7 +354,8 @@ class ApiServer(RPC): Returns the current status of the trades in json format """ - results = self._rpc_balance(self._config.get('fiat_display_currency', '')) + results = self._rpc_balance(self._config['stake_currency'], + self._config.get('fiat_display_currency', '')) return self.rest_dump(results) @require_login diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index e338cd6dd..137e72ea6 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -297,7 +297,7 @@ class RPC: 'best_rate': round(bp_rate * 100, 2), } - def _rpc_balance(self, fiat_display_currency: str) -> Dict: + def _rpc_balance(self, stake_currency: str, fiat_display_currency: str) -> Dict: """ Returns current account balance per crypto """ output = [] total = 0.0 @@ -310,27 +310,29 @@ class RPC: if not balance['total']: continue - if coin == 'BTC': + est_stake: float = 0 + if coin == stake_currency: rate = 1.0 + est_stake = balance['total'] else: try: - pair = self._freqtrade.exchange.get_valid_pair_combination(coin, "BTC") - - if pair.startswith("BTC"): - rate = 1.0 / tickers.get(pair, {}).get('bid', 1) - else: - rate = tickers.get(pair, {}).get('bid', 1) + pair = self._freqtrade.exchange.get_valid_pair_combination(coin, stake_currency) + rate = tickers.get(pair, {}).get('bid', None) + if rate: + if pair.startswith(stake_currency): + rate = 1.0 / rate + est_stake = rate * balance['total'] except (TemporaryError, DependencyException): logger.warning(f" Could not get rate for pair {coin}.") continue - est_btc: float = rate * balance['total'] - total = total + est_btc + total = total + (est_stake or 0) output.append({ 'currency': coin, 'free': balance['free'] if balance['free'] is not None else 0, 'balance': balance['total'] if balance['total'] is not None else 0, 'used': balance['used'] if balance['used'] is not None else 0, - 'est_btc': est_btc, + 'est_stake': est_stake or 0, + 'stake': stake_currency, }) if total == 0.0: if self._freqtrade.config.get('dry_run', False): diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 0547af7b0..2ae22f472 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -325,15 +325,16 @@ class Telegram(RPC): def _balance(self, update: Update, context: CallbackContext) -> None: """ Handler for /balance """ try: - result = self._rpc_balance(self._config.get('fiat_display_currency', '')) + result = self._rpc_balance(self._config['stake_currency'], + self._config.get('fiat_display_currency', '')) output = '' for currency in result['currencies']: - if currency['est_btc'] > 0.0001: + if currency['est_stake'] > 0.0001: curr_output = "*{currency}:*\n" \ "\t`Available: {free: .8f}`\n" \ "\t`Balance: {balance: .8f}`\n" \ "\t`Pending: {used: .8f}`\n" \ - "\t`Est. BTC: {est_btc: .8f}`\n".format(**currency) + "\t`Est. {stake}: {est_stake: .8f}`\n".format(**currency) else: curr_output = "*{currency}:* not showing <1$ amount \n".format(**currency) diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index d745212ac..2c7228274 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -363,7 +363,7 @@ def test_rpc_balance_handle_error(default_conf, mocker): rpc = RPC(freqtradebot) rpc._fiat_converter = CryptoToFiatConverter() with pytest.raises(RPCException, match="Error getting current tickers."): - rpc._rpc_balance(default_conf['fiat_display_currency']) + rpc._rpc_balance(default_conf['stake_currency'], default_conf['fiat_display_currency']) def test_rpc_balance_handle(default_conf, mocker, tickers): @@ -404,28 +404,33 @@ def test_rpc_balance_handle(default_conf, mocker, tickers): rpc = RPC(freqtradebot) rpc._fiat_converter = CryptoToFiatConverter() - result = rpc._rpc_balance(default_conf['fiat_display_currency']) + result = rpc._rpc_balance(default_conf['stake_currency'], default_conf['fiat_display_currency']) assert prec_satoshi(result['total'], 12.309096315) assert prec_satoshi(result['value'], 184636.44472997) assert 'USD' == result['symbol'] assert result['currencies'] == [ {'currency': 'BTC', - 'free': 10.0, - 'balance': 12.0, - 'used': 2.0, - 'est_btc': 12.0, + 'free': 10.0, + 'balance': 12.0, + 'used': 2.0, + 'est_stake': 12.0, + 'stake': 'BTC', }, {'free': 1.0, 'balance': 5.0, 'currency': 'ETH', - 'est_btc': 0.30794, - 'used': 4.0 + 'est_stake': 0.30794, + 'used': 4.0, + 'stake': 'BTC', + }, {'free': 5.0, 'balance': 10.0, 'currency': 'USDT', - 'est_btc': 0.0011563153318162476, - 'used': 5.0} + 'est_stake': 0.0011563153318162476, + 'used': 5.0, + 'stake': 'BTC', + } ] assert result['total'] == 12.309096315331816 diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 8eff37023..4dc3fd265 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -256,7 +256,8 @@ def test_api_balance(botclient, mocker, rpc_balance): 'free': 12.0, 'balance': 12.0, 'used': 0.0, - 'est_btc': 12.0, + 'est_stake': 12.0, + 'stake': 'BTC', } diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 89fd90b0b..c848a3efd 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -545,7 +545,8 @@ def test_balance_handle_too_large_response(default_conf, update, mocker) -> None 'free': 1.0, 'used': 0.5, 'balance': i, - 'est_btc': 1 + 'est_stake': 1, + 'stake': 'BTC', }) mocker.patch('freqtrade.rpc.rpc.RPC._rpc_balance', return_value={ 'currencies': balances, From 50350a09cd494c802a1586cfaec9bf78ef876c4f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Nov 2019 19:41:51 +0100 Subject: [PATCH 04/18] use wallets instead of doing a direct call to /balance --- freqtrade/rpc/rpc.py | 14 +++++++------- freqtrade/wallets.py | 5 ++++- tests/rpc/test_rpc_apiserver.py | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 137e72ea6..4cebe646e 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -306,14 +306,14 @@ class RPC: except (TemporaryError, DependencyException): raise RPCException('Error getting current tickers.') - for coin, balance in self._freqtrade.exchange.get_balances().items(): - if not balance['total']: + for coin, balance in self._freqtrade.wallets.get_all_balances().items(): + if not balance.total: continue est_stake: float = 0 if coin == stake_currency: rate = 1.0 - est_stake = balance['total'] + est_stake = balance.total else: try: pair = self._freqtrade.exchange.get_valid_pair_combination(coin, stake_currency) @@ -321,16 +321,16 @@ class RPC: if rate: if pair.startswith(stake_currency): rate = 1.0 / rate - est_stake = rate * balance['total'] + est_stake = rate * balance.total except (TemporaryError, DependencyException): logger.warning(f" Could not get rate for pair {coin}.") continue total = total + (est_stake or 0) output.append({ 'currency': coin, - 'free': balance['free'] if balance['free'] is not None else 0, - 'balance': balance['total'] if balance['total'] is not None else 0, - 'used': balance['used'] if balance['used'] is not None else 0, + 'free': balance.free if balance.free is not None else 0, + 'balance': balance.total if balance.total is not None else 0, + 'used': balance.used if balance.used is not None else 0, 'est_stake': est_stake or 0, 'stake': stake_currency, }) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 90b68c49d..c674b5286 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -2,7 +2,7 @@ """ Wallet """ import logging -from typing import Dict, NamedTuple +from typing import Dict, NamedTuple, Any from freqtrade.exchange import Exchange from freqtrade import constants @@ -72,3 +72,6 @@ class Wallets: ) logger.info('Wallets synced.') + + def get_all_balances(self) -> Dict[str, Any]: + return self._wallets diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 4dc3fd265..7b3e787f4 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -243,9 +243,9 @@ def test_api_balance(botclient, mocker, rpc_balance): 'last': 0.1, } mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value=rpc_balance) - mocker.patch('freqtrade.exchange.Exchange.get_ticker', side_effect=mock_ticker) mocker.patch('freqtrade.exchange.Exchange.get_valid_pair_combination', side_effect=lambda a, b: f"{a}/{b}") + ftbot.wallets.update() rc = client_get(client, f"{BASE_URI}/balance") assert_response(rc) From 1b337fe5e1c1cc67752aa8af6b0bf7f612038d96 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Nov 2019 19:47:20 +0100 Subject: [PATCH 05/18] Remove unnecessary code piece --- tests/rpc/test_rpc_apiserver.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 7b3e787f4..8d5b4a6b8 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -224,24 +224,6 @@ def test_api_stopbuy(botclient): def test_api_balance(botclient, mocker, rpc_balance): ftbot, client = botclient - def mock_ticker(symbol, refresh): - if symbol == 'BTC/USDT': - return { - 'bid': 10000.00, - 'ask': 10000.00, - 'last': 10000.00, - } - elif symbol == 'XRP/BTC': - return { - 'bid': 0.00001, - 'ask': 0.00001, - 'last': 0.00001, - } - return { - 'bid': 0.1, - 'ask': 0.1, - 'last': 0.1, - } mocker.patch('freqtrade.exchange.Exchange.get_balances', return_value=rpc_balance) mocker.patch('freqtrade.exchange.Exchange.get_valid_pair_combination', side_effect=lambda a, b: f"{a}/{b}") From 6ab7f93ce766ac708ea8b29919633dc5a156631d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2019 07:20:40 +0000 Subject: [PATCH 06/18] Bump scipy from 1.3.2 to 1.3.3 Bumps [scipy](https://github.com/scipy/scipy) from 1.3.2 to 1.3.3. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.3.2...v1.3.3) Signed-off-by: dependabot-preview[bot] --- requirements-hyperopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index ff8de9cb2..96a22b42e 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -2,7 +2,7 @@ -r requirements.txt # Required for hyperopt -scipy==1.3.2 +scipy==1.3.3 scikit-learn==0.21.3 scikit-optimize==0.5.2 filelock==3.0.12 From 28f73ecb3d02802f586cc27f15cbaed30769c886 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2019 07:21:16 +0000 Subject: [PATCH 07/18] Bump ccxt from 1.19.54 to 1.19.86 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.19.54 to 1.19.86. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/CHANGELOG.md) - [Commits](https://github.com/ccxt/ccxt/compare/1.19.54...1.19.86) Signed-off-by: dependabot-preview[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index 2c176e9c3..ec6224c50 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -1,6 +1,6 @@ # requirements without requirements installable via conda # mainly used for Raspberry pi installs -ccxt==1.19.54 +ccxt==1.19.86 SQLAlchemy==1.3.11 python-telegram-bot==12.2.0 arrow==0.15.4 From 0a7a1290e3ba062deeacba3205141fc763a04cf1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2019 07:21:32 +0000 Subject: [PATCH 08/18] Bump pytest-mock from 1.11.2 to 1.12.1 Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 1.11.2 to 1.12.1. - [Release notes](https://github.com/pytest-dev/pytest-mock/releases) - [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-mock/compare/v1.11.2...v1.12.1) Signed-off-by: dependabot-preview[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 297b95623..34b52c963 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -11,7 +11,7 @@ mypy==0.740 pytest==5.2.4 pytest-asyncio==0.10.0 pytest-cov==2.8.1 -pytest-mock==1.11.2 +pytest-mock==1.12.1 pytest-random-order==1.0.4 # Convert jupyter notebooks to markdown documents From 03f02294d1b351b415431cac82deed633b0cda60 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2019 07:21:52 +0000 Subject: [PATCH 09/18] Bump pytest from 5.2.4 to 5.3.0 Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.2.4 to 5.3.0. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/5.2.4...5.3.0) Signed-off-by: dependabot-preview[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 297b95623..2dc8c88d9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -8,7 +8,7 @@ flake8==3.7.9 flake8-type-annotations==0.1.0 flake8-tidy-imports==3.1.0 mypy==0.740 -pytest==5.2.4 +pytest==5.3.0 pytest-asyncio==0.10.0 pytest-cov==2.8.1 pytest-mock==1.11.2 From 418ca0030521d5d1d827c12c348820aefd545e83 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2019 07:22:09 +0000 Subject: [PATCH 10/18] Bump jsonschema from 3.1.1 to 3.2.0 Bumps [jsonschema](https://github.com/Julian/jsonschema) from 3.1.1 to 3.2.0. - [Release notes](https://github.com/Julian/jsonschema/releases) - [Changelog](https://github.com/Julian/jsonschema/blob/master/CHANGELOG.rst) - [Commits](https://github.com/Julian/jsonschema/compare/v3.1.1...v3.2.0) Signed-off-by: dependabot-preview[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index 2c176e9c3..8f6c7e3d6 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -8,7 +8,7 @@ cachetools==3.1.1 requests==2.22.0 urllib3==1.25.7 wrapt==1.11.2 -jsonschema==3.1.1 +jsonschema==3.2.0 TA-Lib==0.4.17 tabulate==0.8.6 coinmarketcap==5.0.3 From 8204107315fdda493c254b592c86adb448c2b157 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Tue, 26 Nov 2019 11:57:02 +0300 Subject: [PATCH 11/18] Add test for get_min_pair_stake_amount() with real data --- tests/test_freqtradebot.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index b01c8e247..937723073 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -334,6 +334,7 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: freqtrade = FreqtradeBot(default_conf) freqtrade.strategy.stoploss = -0.05 markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}} + # no pair found mocker.patch( 'freqtrade.exchange.Exchange.markets', @@ -440,6 +441,25 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: assert result == min(8, 2 * 2) / 0.9 +def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None: + patch_RPCManager(mocker) + patch_exchange(mocker) + freqtrade = FreqtradeBot(default_conf) + freqtrade.strategy.stoploss = -0.05 + markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}} + + # Real Binance data + markets["ETH/BTC"]["limits"] = { + 'cost': {'min': 0.0001}, + 'amount': {'min': 0.001} + } + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=markets) + ) + result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 0.020405) + assert round(result, 8) == round(max(0.0001, 0.001 * 0.020405) / 0.9, 8) + def test_create_trades(default_conf, ticker, limit_buy_order, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) From 17269c88bef96618cf91bbe6ceabbefa3ae37c39 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Tue, 26 Nov 2019 11:57:58 +0300 Subject: [PATCH 12/18] Fix _get_min_pair_stake_amount() --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 358c63f90..b5d157635 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -266,7 +266,7 @@ class FreqtradeBot: amount_reserve_percent += self.strategy.stoploss # it should not be more than 50% amount_reserve_percent = max(amount_reserve_percent, 0.5) - return min(min_stake_amounts) / amount_reserve_percent + return max(min_stake_amounts) / amount_reserve_percent def create_trades(self) -> bool: """ From 0ac592ad40a473a8a7adfc4ab7319d14c2a00632 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Tue, 26 Nov 2019 12:00:20 +0300 Subject: [PATCH 13/18] Fix markets in conftest --- tests/conftest.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index fbd23a0dc..bf245a840 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -325,7 +325,7 @@ def get_markets(): }, 'price': 500000, 'cost': { - 'min': 1, + 'min': 0.0001, 'max': 500000, }, }, @@ -351,7 +351,7 @@ def get_markets(): }, 'price': 500000, 'cost': { - 'min': 1, + 'min': 0.0001, 'max': 500000, }, }, @@ -376,7 +376,7 @@ def get_markets(): }, 'price': 500000, 'cost': { - 'min': 1, + 'min': 0.0001, 'max': 500000, }, }, @@ -401,7 +401,7 @@ def get_markets(): }, 'price': 500000, 'cost': { - 'min': 1, + 'min': 0.0001, 'max': 500000, }, }, @@ -426,7 +426,7 @@ def get_markets(): }, 'price': 500000, 'cost': { - 'min': 1, + 'min': 0.0001, 'max': 500000, }, }, @@ -451,7 +451,7 @@ def get_markets(): }, 'price': 500000, 'cost': { - 'min': 1, + 'min': 0.0001, 'max': 500000, }, }, @@ -479,7 +479,7 @@ def get_markets(): 'max': None }, 'cost': { - 'min': 0.001, + 'min': 0.0001, 'max': None } }, From 8e1e20bf0d536e8b4b46c8ea26757a180419e080 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Tue, 26 Nov 2019 12:07:43 +0300 Subject: [PATCH 14/18] Fix some tests --- tests/test_freqtradebot.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 937723073..746a05cc6 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -299,7 +299,7 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker, limit_buy_order, fee) -> None: patch_RPCManager(mocker) patch_exchange(mocker) - default_conf['stake_amount'] = 0.0000098751 + default_conf['stake_amount'] = 0.00098751 default_conf['max_open_trades'] = 2 mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -313,7 +313,7 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker, trade = Trade.query.first() assert trade is not None - assert trade.stake_amount == 0.0000098751 + assert trade.stake_amount == 0.00098751 assert trade.is_open assert trade.open_date is not None @@ -321,11 +321,11 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker, trade = Trade.query.order_by(Trade.id.desc()).first() assert trade is not None - assert trade.stake_amount == 0.0000098751 + assert trade.stake_amount == 0.00098751 assert trade.is_open assert trade.open_date is not None - assert Trade.total_open_trades_stakes() == 1.97502e-05 + assert Trade.total_open_trades_stakes() == 1.97502e-03 def test_get_min_pair_stake_amount(mocker, default_conf) -> None: From 066f32406058b22b0d3c227745cd205ec6ab3418 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Tue, 26 Nov 2019 12:28:04 +0300 Subject: [PATCH 15/18] Make flake happy --- tests/test_freqtradebot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 746a05cc6..31e9f8750 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -460,6 +460,7 @@ def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None: result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 0.020405) assert round(result, 8) == round(max(0.0001, 0.001 * 0.020405) / 0.9, 8) + def test_create_trades(default_conf, ticker, limit_buy_order, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) From cceb00c4065c1a66ff7995f7a59304365e75b046 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 26 Nov 2019 12:12:41 +0100 Subject: [PATCH 16/18] Try coveralls --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 047a34dd6..f6a111944 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,7 +74,7 @@ jobs: # Fake travis environment to get coveralls working correctly export TRAVIS_PULL_REQUEST="https://github.com/${GITHUB_REPOSITORY}/pull/$(cat $GITHUB_EVENT_PATH | jq -r .number)" export TRAVIS_BRANCH=${GITHUB_REF#"ref/heads"} - export TRAVIS_BRANCH=${HEAD_REF} + export CI_BRANCH=${GITHUB_REF#"ref/heads"} echo "${TRAVIS_BRANCH}" coveralls || true From f2cd4fdafe989bd6d8713d19126d1dfdf8a646ba Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 27 Nov 2019 05:12:54 +0300 Subject: [PATCH 17/18] Fix the rest of tests --- tests/test_freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 31e9f8750..841bf8a6a 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -426,7 +426,7 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: PropertyMock(return_value=markets) ) result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2) - assert result == min(2, 2 * 2) / 0.9 + assert result == max(2, 2 * 2) / 0.9 # min amount and cost are set (amount is minial) markets["ETH/BTC"]["limits"] = { @@ -438,7 +438,7 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: PropertyMock(return_value=markets) ) result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2) - assert result == min(8, 2 * 2) / 0.9 + assert result == max(8, 2 * 2) / 0.9 def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None: From a373e48939f74c73091d7d010988861c64cf2ee4 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 27 Nov 2019 14:53:01 +0300 Subject: [PATCH 18/18] Comment added --- freqtrade/freqtradebot.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index b5d157635..ec341ff0a 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -266,6 +266,10 @@ class FreqtradeBot: amount_reserve_percent += self.strategy.stoploss # it should not be more than 50% amount_reserve_percent = max(amount_reserve_percent, 0.5) + + # The value returned should satisfy both limits: for amount (base currency) and + # for cost (quote, stake currency), so max() is used here. + # See also #2575 at github. return max(min_stake_amounts) / amount_reserve_percent def create_trades(self) -> bool: