Fix RPC methods to allow wildcards (and validate wildcards)
This commit is contained in:
		| @@ -20,6 +20,7 @@ from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs | |||||||
| from freqtrade.loggers import bufferHandler | from freqtrade.loggers import bufferHandler | ||||||
| from freqtrade.misc import shorten_date | from freqtrade.misc import shorten_date | ||||||
| from freqtrade.persistence import PairLocks, Trade | from freqtrade.persistence import PairLocks, Trade | ||||||
|  | from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist | ||||||
| from freqtrade.rpc.fiat_convert import CryptoToFiatConverter | from freqtrade.rpc.fiat_convert import CryptoToFiatConverter | ||||||
| from freqtrade.state import State | from freqtrade.state import State | ||||||
| from freqtrade.strategy.interface import SellType | from freqtrade.strategy.interface import SellType | ||||||
| @@ -673,23 +674,23 @@ class RPC: | |||||||
|         """ Returns the currently active blacklist""" |         """ Returns the currently active blacklist""" | ||||||
|         errors = {} |         errors = {} | ||||||
|         if add: |         if add: | ||||||
|             stake_currency = self._freqtrade.config.get('stake_currency') |  | ||||||
|             for pair in add: |             for pair in add: | ||||||
|                 if self._freqtrade.exchange.get_pair_quote_currency(pair) == stake_currency: |                 if pair not in self._freqtrade.pairlists.blacklist: | ||||||
|                     if pair not in self._freqtrade.pairlists.blacklist: |                     try: | ||||||
|  |                         expand_pairlist([pair], self._freqtrade.exchange.get_markets().keys()) | ||||||
|                         self._freqtrade.pairlists.blacklist.append(pair) |                         self._freqtrade.pairlists.blacklist.append(pair) | ||||||
|                     else: |  | ||||||
|                         errors[pair] = { |  | ||||||
|                             'error_msg': f'Pair {pair} already in pairlist.'} |  | ||||||
|  |  | ||||||
|  |                     except ValueError: | ||||||
|  |                         errors[pair] = { | ||||||
|  |                             'error_msg': f'Pair {pair} is not a valid wildcard.'} | ||||||
|                 else: |                 else: | ||||||
|                     errors[pair] = { |                     errors[pair] = { | ||||||
|                         'error_msg': f"Pair {pair} does not match stake currency." |                         'error_msg': f'Pair {pair} already in pairlist.'} | ||||||
|                     } |  | ||||||
|  |  | ||||||
|         res = {'method': self._freqtrade.pairlists.name_list, |         res = {'method': self._freqtrade.pairlists.name_list, | ||||||
|                'length': len(self._freqtrade.pairlists.blacklist), |                'length': len(self._freqtrade.pairlists.blacklist), | ||||||
|                'blacklist': self._freqtrade.pairlists.blacklist, |                'blacklist': self._freqtrade.pairlists.blacklist, | ||||||
|  |                'blacklist_expanded': self._freqtrade.pairlists.expanded_blacklist, | ||||||
|                'errors': errors, |                'errors': errors, | ||||||
|                } |                } | ||||||
|         return res |         return res | ||||||
|   | |||||||
| @@ -957,14 +957,24 @@ def test_rpc_blacklist(mocker, default_conf) -> None: | |||||||
|     assert isinstance(ret['errors'], dict) |     assert isinstance(ret['errors'], dict) | ||||||
|     assert ret['errors']['ETH/BTC']['error_msg'] == 'Pair ETH/BTC already in pairlist.' |     assert ret['errors']['ETH/BTC']['error_msg'] == 'Pair ETH/BTC already in pairlist.' | ||||||
|  |  | ||||||
|     ret = rpc._rpc_blacklist(["ETH/ETH"]) |     ret = rpc._rpc_blacklist(["*/BTC"]) | ||||||
|     assert 'StaticPairList' in ret['method'] |     assert 'StaticPairList' in ret['method'] | ||||||
|     assert len(ret['blacklist']) == 3 |     assert len(ret['blacklist']) == 3 | ||||||
|     assert ret['blacklist'] == default_conf['exchange']['pair_blacklist'] |     assert ret['blacklist'] == default_conf['exchange']['pair_blacklist'] | ||||||
|     assert ret['blacklist'] == ['DOGE/BTC', 'HOT/BTC', 'ETH/BTC'] |     assert ret['blacklist'] == ['DOGE/BTC', 'HOT/BTC', 'ETH/BTC'] | ||||||
|  |     assert ret['blacklist_expanded'] == ['ETH/BTC'] | ||||||
|  |     assert 'errors' in ret | ||||||
|  |     assert isinstance(ret['errors'], dict) | ||||||
|  |     assert ret['errors'] == {'*/BTC': {'error_msg': 'Pair */BTC is not a valid wildcard.'}} | ||||||
|  |  | ||||||
|  |     ret = rpc._rpc_blacklist(["XRP/.*"]) | ||||||
|  |     assert 'StaticPairList' in ret['method'] | ||||||
|  |     assert len(ret['blacklist']) == 4 | ||||||
|  |     assert ret['blacklist'] == default_conf['exchange']['pair_blacklist'] | ||||||
|  |     assert ret['blacklist'] == ['DOGE/BTC', 'HOT/BTC', 'ETH/BTC', 'XRP/.*'] | ||||||
|  |     assert ret['blacklist_expanded'] == ['ETH/BTC', 'XRP/BTC'] | ||||||
|     assert 'errors' in ret |     assert 'errors' in ret | ||||||
|     assert isinstance(ret['errors'], dict) |     assert isinstance(ret['errors'], dict) | ||||||
|     assert ret['errors']['ETH/ETH']['error_msg'] == 'Pair ETH/ETH does not match stake currency.' |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_rpc_edge_disabled(mocker, default_conf) -> None: | def test_rpc_edge_disabled(mocker, default_conf) -> None: | ||||||
|   | |||||||
| @@ -730,7 +730,9 @@ def test_api_blacklist(botclient, mocker): | |||||||
|  |  | ||||||
|     rc = client_get(client, f"{BASE_URI}/blacklist") |     rc = client_get(client, f"{BASE_URI}/blacklist") | ||||||
|     assert_response(rc) |     assert_response(rc) | ||||||
|  |     # DOGE and HOT are not in the markets mock! | ||||||
|     assert rc.json == {"blacklist": ["DOGE/BTC", "HOT/BTC"], |     assert rc.json == {"blacklist": ["DOGE/BTC", "HOT/BTC"], | ||||||
|  |                        "blacklist_expanded": [], | ||||||
|                        "length": 2, |                        "length": 2, | ||||||
|                        "method": ["StaticPairList"], |                        "method": ["StaticPairList"], | ||||||
|                        "errors": {}, |                        "errors": {}, | ||||||
| @@ -741,11 +743,22 @@ def test_api_blacklist(botclient, mocker): | |||||||
|                      data='{"blacklist": ["ETH/BTC"]}') |                      data='{"blacklist": ["ETH/BTC"]}') | ||||||
|     assert_response(rc) |     assert_response(rc) | ||||||
|     assert rc.json == {"blacklist": ["DOGE/BTC", "HOT/BTC", "ETH/BTC"], |     assert rc.json == {"blacklist": ["DOGE/BTC", "HOT/BTC", "ETH/BTC"], | ||||||
|  |                        "blacklist_expanded": ["ETH/BTC"], | ||||||
|                        "length": 3, |                        "length": 3, | ||||||
|                        "method": ["StaticPairList"], |                        "method": ["StaticPairList"], | ||||||
|                        "errors": {}, |                        "errors": {}, | ||||||
|                        } |                        } | ||||||
|  |  | ||||||
|  |     rc = client_post(client, f"{BASE_URI}/blacklist", | ||||||
|  |                      data='{"blacklist": ["XRP/.*"]}') | ||||||
|  |     assert_response(rc) | ||||||
|  |     assert rc.json == {"blacklist": ["DOGE/BTC", "HOT/BTC", "ETH/BTC", "XRP/.*"], | ||||||
|  |                        "blacklist_expanded": ["ETH/BTC", "XRP/BTC"], | ||||||
|  |                        "length": 4, | ||||||
|  |                        "method": ["StaticPairList"], | ||||||
|  |                        "errors": {}, | ||||||
|  |                        } | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_api_whitelist(botclient): | def test_api_whitelist(botclient): | ||||||
|     ftbot, client = botclient |     ftbot, client = botclient | ||||||
|   | |||||||
| @@ -1011,15 +1011,13 @@ def test_blacklist_static(default_conf, update, mocker) -> None: | |||||||
|  |  | ||||||
|     msg_mock.reset_mock() |     msg_mock.reset_mock() | ||||||
|     context = MagicMock() |     context = MagicMock() | ||||||
|     context.args = ["ETH/ETH"] |     context.args = ["XRP/.*"] | ||||||
|     telegram._blacklist(update=update, context=context) |     telegram._blacklist(update=update, context=context) | ||||||
|     assert msg_mock.call_count == 2 |     assert msg_mock.call_count == 1 | ||||||
|     assert ("Error adding `ETH/ETH` to blacklist: `Pair ETH/ETH does not match stake currency.`" |  | ||||||
|             in msg_mock.call_args_list[0][0][0]) |  | ||||||
|  |  | ||||||
|     assert ("Blacklist contains 3 pairs\n`DOGE/BTC, HOT/BTC, ETH/BTC`" |     assert ("Blacklist contains 4 pairs\n`DOGE/BTC, HOT/BTC, ETH/BTC, XRP/.*`" | ||||||
|             in msg_mock.call_args_list[1][0][0]) |             in msg_mock.call_args_list[0][0][0]) | ||||||
|     assert freqtradebot.pairlists.blacklist == ["DOGE/BTC", "HOT/BTC", "ETH/BTC"] |     assert freqtradebot.pairlists.blacklist == ["DOGE/BTC", "HOT/BTC", "ETH/BTC", "XRP/.*"] | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_telegram_logs(default_conf, update, mocker) -> None: | def test_telegram_logs(default_conf, update, mocker) -> None: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user