freqtrade_origin/tests/plugins/test_remotepairlist.py

344 lines
11 KiB
Python
Raw Permalink Normal View History

2022-12-15 16:38:21 +00:00
import json
from unittest.mock import MagicMock, PropertyMock
2022-12-13 19:21:06 +00:00
import pytest
2022-12-15 16:38:21 +00:00
import requests
2022-12-13 19:21:06 +00:00
from freqtrade.exceptions import OperationalException
from freqtrade.plugins.pairlist.RemotePairList import RemotePairList
from freqtrade.plugins.pairlistmanager import PairListManager
from tests.conftest import EXMS, get_patched_exchange, get_patched_freqtradebot, log_has
2022-12-13 19:21:06 +00:00
@pytest.fixture(scope="function")
def rpl_config(default_conf):
2024-05-12 13:57:44 +00:00
default_conf["stake_currency"] = "USDT"
2022-12-13 19:21:06 +00:00
2024-05-12 13:57:44 +00:00
default_conf["exchange"]["pair_whitelist"] = [
"ETH/USDT",
"XRP/USDT",
2022-12-13 19:21:06 +00:00
]
2024-05-12 13:57:44 +00:00
default_conf["exchange"]["pair_blacklist"] = ["BLK/USDT"]
2023-06-24 12:31:30 +00:00
2022-12-13 19:21:06 +00:00
return default_conf
2022-12-15 16:38:21 +00:00
def test_gen_pairlist_with_local_file(mocker, rpl_config):
mock_file = MagicMock()
mock_file.read.return_value = '{"pairs": ["TKN/USDT","ETH/USDT","NANO/USDT"]}'
2024-05-12 13:57:44 +00:00
mocker.patch("freqtrade.plugins.pairlist.RemotePairList.open", return_value=mock_file)
2022-12-15 16:38:21 +00:00
2024-05-12 13:57:44 +00:00
mock_file_path = mocker.patch("freqtrade.plugins.pairlist.RemotePairList.Path")
2022-12-15 16:38:21 +00:00
mock_file_path.exists.return_value = True
jsonparse = json.loads(mock_file.read.return_value)
2024-05-12 13:57:44 +00:00
mocker.patch("freqtrade.plugins.pairlist.RemotePairList.rapidjson.load", return_value=jsonparse)
2022-12-15 16:38:21 +00:00
2024-05-12 13:57:44 +00:00
rpl_config["pairlists"] = [
2022-12-15 16:38:21 +00:00
{
"method": "RemotePairList",
2024-05-12 13:57:44 +00:00
"number_assets": 2,
"refresh_period": 1800,
"keep_pairlist_on_failure": True,
"pairlist_url": "file:///pairlist.json",
"bearer_token": "",
"read_timeout": 60,
2022-12-15 16:38:21 +00:00
}
]
exchange = get_patched_exchange(mocker, rpl_config)
pairlistmanager = PairListManager(exchange, rpl_config)
2024-05-12 13:57:44 +00:00
remote_pairlist = RemotePairList(
exchange, pairlistmanager, rpl_config, rpl_config["pairlists"][0], 0
)
2022-12-15 16:38:21 +00:00
result = remote_pairlist.gen_pairlist([])
2024-05-12 13:57:44 +00:00
assert result == ["TKN/USDT", "ETH/USDT"]
2022-12-15 16:38:21 +00:00
2022-12-13 19:21:06 +00:00
def test_fetch_pairlist_mock_response_html(mocker, rpl_config):
mock_response = MagicMock()
2024-05-12 13:57:44 +00:00
mock_response.headers = {"content-type": "text/html"}
2022-12-13 19:21:06 +00:00
2024-05-12 13:57:44 +00:00
rpl_config["pairlists"] = [
2022-12-13 19:21:06 +00:00
{
"method": "RemotePairList",
"pairlist_url": "http://example.com/pairlist",
"number_assets": 10,
"read_timeout": 10,
"keep_pairlist_on_failure": True,
}
]
exchange = get_patched_exchange(mocker, rpl_config)
pairlistmanager = PairListManager(exchange, rpl_config)
2024-05-12 13:57:44 +00:00
mocker.patch(
"freqtrade.plugins.pairlist.RemotePairList.requests.get", return_value=mock_response
)
remote_pairlist = RemotePairList(
exchange, pairlistmanager, rpl_config, rpl_config["pairlists"][0], 0
)
2022-12-13 19:21:06 +00:00
2024-05-12 13:57:44 +00:00
with pytest.raises(OperationalException, match="RemotePairList is not of type JSON."):
2022-12-13 19:21:06 +00:00
remote_pairlist.fetch_pairlist()
2022-12-15 16:38:21 +00:00
def test_fetch_pairlist_timeout_keep_last_pairlist(mocker, rpl_config, caplog):
2024-05-12 13:57:44 +00:00
rpl_config["pairlists"] = [
2022-12-15 16:38:21 +00:00
{
"method": "RemotePairList",
"pairlist_url": "http://example.com/pairlist",
"number_assets": 10,
"read_timeout": 10,
"keep_pairlist_on_failure": True,
}
]
exchange = get_patched_exchange(mocker, rpl_config)
pairlistmanager = PairListManager(exchange, rpl_config)
2024-05-12 13:57:44 +00:00
mocker.patch(
"freqtrade.plugins.pairlist.RemotePairList.requests.get",
side_effect=requests.exceptions.RequestException,
)
2022-12-15 16:38:21 +00:00
2024-05-12 13:57:44 +00:00
remote_pairlist = RemotePairList(
exchange, pairlistmanager, rpl_config, rpl_config["pairlists"][0], 0
)
2022-12-15 16:38:21 +00:00
remote_pairlist._last_pairlist = ["BTC/USDT", "ETH/USDT", "LTC/USDT"]
2024-01-26 19:55:24 +00:00
remote_pairlist._init_done = True
2024-05-12 13:57:44 +00:00
pairlist_url = rpl_config["pairlists"][0]["pairlist_url"]
2024-01-24 19:31:38 +00:00
pairs, _time_elapsed = remote_pairlist.fetch_pairlist()
2024-01-26 19:55:24 +00:00
2024-05-12 15:58:28 +00:00
assert log_has(f"Error: Was not able to fetch pairlist from: {pairlist_url}", caplog)
2022-12-15 16:38:21 +00:00
assert log_has("Keeping last fetched pairlist", caplog)
assert pairs == ["BTC/USDT", "ETH/USDT", "LTC/USDT"]
2022-12-13 19:21:06 +00:00
def test_remote_pairlist_init_no_pairlist_url(mocker, rpl_config):
2024-05-12 13:57:44 +00:00
rpl_config["pairlists"] = [
2022-12-13 19:21:06 +00:00
{
"method": "RemotePairList",
"number_assets": 10,
"keep_pairlist_on_failure": True,
}
]
get_patched_exchange(mocker, rpl_config)
2024-05-12 13:57:44 +00:00
with pytest.raises(
OperationalException,
match=r"`pairlist_url` not specified."
r' Please check your configuration for "pairlist.config.pairlist_url"',
):
2022-12-13 19:21:06 +00:00
get_patched_freqtradebot(mocker, rpl_config)
def test_remote_pairlist_init_no_number_assets(mocker, rpl_config):
2024-05-12 13:57:44 +00:00
rpl_config["pairlists"] = [
2022-12-13 19:21:06 +00:00
{
"method": "RemotePairList",
"pairlist_url": "http://example.com/pairlist",
"keep_pairlist_on_failure": True,
}
]
get_patched_exchange(mocker, rpl_config)
2024-05-12 13:57:44 +00:00
with pytest.raises(
OperationalException,
match=r"`number_assets` not specified. "
'Please check your configuration for "pairlist.config.number_assets"',
):
2022-12-13 19:21:06 +00:00
get_patched_freqtradebot(mocker, rpl_config)
def test_fetch_pairlist_mock_response_valid(mocker, rpl_config):
2024-05-12 13:57:44 +00:00
rpl_config["pairlists"] = [
2022-12-13 19:21:06 +00:00
{
"method": "RemotePairList",
"pairlist_url": "http://example.com/pairlist",
"number_assets": 10,
"refresh_period": 10,
"read_timeout": 10,
"keep_pairlist_on_failure": True,
}
]
mock_response = MagicMock()
mock_response.json.return_value = {
2022-12-15 16:38:21 +00:00
"pairs": ["ETH/USDT", "XRP/USDT", "LTC/USDT", "EOS/USDT"],
2024-05-12 13:57:44 +00:00
"refresh_period": 60,
2022-12-13 19:21:06 +00:00
}
2024-05-12 13:57:44 +00:00
mock_response.headers = {"content-type": "application/json"}
2022-12-13 19:21:06 +00:00
mock_response.elapsed.total_seconds.return_value = 0.4
2024-05-12 13:57:44 +00:00
mocker.patch(
"freqtrade.plugins.pairlist.RemotePairList.requests.get", return_value=mock_response
)
2022-12-13 19:21:06 +00:00
exchange = get_patched_exchange(mocker, rpl_config)
pairlistmanager = PairListManager(exchange, rpl_config)
2024-05-12 13:57:44 +00:00
remote_pairlist = RemotePairList(
exchange, pairlistmanager, rpl_config, rpl_config["pairlists"][0], 0
)
pairs, time_elapsed = remote_pairlist.fetch_pairlist()
2022-12-13 19:21:06 +00:00
2022-12-15 16:38:21 +00:00
assert pairs == ["ETH/USDT", "XRP/USDT", "LTC/USDT", "EOS/USDT"]
2022-12-13 19:21:06 +00:00
assert time_elapsed == 0.4
assert remote_pairlist._refresh_period == 60
2023-06-24 12:31:30 +00:00
def test_remote_pairlist_init_wrong_mode(mocker, rpl_config):
2024-05-12 13:57:44 +00:00
rpl_config["pairlists"] = [
2023-06-24 12:31:30 +00:00
{
"method": "RemotePairList",
"mode": "blacklis",
"number_assets": 20,
"pairlist_url": "http://example.com/pairlist",
"keep_pairlist_on_failure": True,
}
]
with pytest.raises(
OperationalException,
2024-05-12 13:57:44 +00:00
match=r'`mode` not configured correctly. Supported Modes are "whitelist","blacklist"',
):
get_patched_freqtradebot(mocker, rpl_config)
2024-05-12 13:57:44 +00:00
rpl_config["pairlists"] = [
2023-07-09 09:37:06 +00:00
{
"method": "RemotePairList",
"mode": "blacklist",
"number_assets": 20,
"pairlist_url": "http://example.com/pairlist",
"keep_pairlist_on_failure": True,
}
]
with pytest.raises(
2024-05-12 13:57:44 +00:00
OperationalException, match=r"A `blacklist` mode RemotePairList can not be.*first.*"
2023-07-09 09:37:06 +00:00
):
get_patched_freqtradebot(mocker, rpl_config)
def test_remote_pairlist_init_wrong_proc_mode(mocker, rpl_config):
2024-05-12 13:57:44 +00:00
rpl_config["pairlists"] = [
{
"method": "RemotePairList",
"processing_mode": "filler",
"mode": "whitelist",
"number_assets": 20,
"pairlist_url": "http://example.com/pairlist",
"keep_pairlist_on_failure": True,
}
]
get_patched_exchange(mocker, rpl_config)
with pytest.raises(
OperationalException,
2024-05-12 13:57:44 +00:00
match=r'`processing_mode` not configured correctly. Supported Modes are "filter","append"',
):
2023-06-24 12:31:30 +00:00
get_patched_freqtradebot(mocker, rpl_config)
def test_remote_pairlist_blacklist(mocker, rpl_config, caplog, markets, tickers):
2023-06-24 12:31:30 +00:00
mock_response = MagicMock()
2024-05-12 13:57:44 +00:00
mock_response.json.return_value = {"pairs": ["XRP/USDT"], "refresh_period": 60}
2023-06-24 12:31:30 +00:00
2024-05-12 13:57:44 +00:00
mock_response.headers = {"content-type": "application/json"}
2023-06-24 12:31:30 +00:00
2024-05-12 13:57:44 +00:00
rpl_config["pairlists"] = [
{
"method": "StaticPairList",
},
2023-06-24 12:31:30 +00:00
{
"method": "RemotePairList",
"mode": "blacklist",
"pairlist_url": "http://example.com/pairlist",
2024-05-12 13:57:44 +00:00
"number_assets": 3,
},
2023-06-24 12:31:30 +00:00
]
2024-05-12 13:57:44 +00:00
mocker.patch.multiple(
EXMS,
markets=PropertyMock(return_value=markets),
exchange_has=MagicMock(return_value=True),
get_tickers=tickers,
)
2024-05-12 13:57:44 +00:00
mocker.patch(
"freqtrade.plugins.pairlist.RemotePairList.requests.get", return_value=mock_response
)
2023-06-24 12:31:30 +00:00
exchange = get_patched_exchange(mocker, rpl_config)
pairlistmanager = PairListManager(exchange, rpl_config)
2024-05-12 13:57:44 +00:00
remote_pairlist = RemotePairList(
exchange, pairlistmanager, rpl_config, rpl_config["pairlists"][1], 1
)
2024-01-24 19:31:38 +00:00
pairs, _time_elapsed = remote_pairlist.fetch_pairlist()
2023-06-24 12:31:30 +00:00
assert pairs == ["XRP/USDT"]
2024-05-12 13:57:44 +00:00
whitelist = remote_pairlist.filter_pairlist(rpl_config["exchange"]["pair_whitelist"], {})
2023-06-24 12:31:30 +00:00
assert whitelist == ["ETH/USDT"]
assert log_has(f"Blacklist - Filtered out pairs: {pairs}", caplog)
@pytest.mark.parametrize("processing_mode", ["filter", "append"])
def test_remote_pairlist_whitelist(mocker, rpl_config, processing_mode, markets, tickers):
mock_response = MagicMock()
2024-05-12 13:57:44 +00:00
mock_response.json.return_value = {"pairs": ["XRP/USDT"], "refresh_period": 60}
2024-05-12 13:57:44 +00:00
mock_response.headers = {"content-type": "application/json"}
2024-05-12 13:57:44 +00:00
rpl_config["pairlists"] = [
{
"method": "StaticPairList",
},
{
"method": "RemotePairList",
"mode": "whitelist",
"processing_mode": processing_mode,
"pairlist_url": "http://example.com/pairlist",
2024-05-12 13:57:44 +00:00
"number_assets": 3,
},
]
2024-05-12 13:57:44 +00:00
mocker.patch.multiple(
EXMS,
markets=PropertyMock(return_value=markets),
exchange_has=MagicMock(return_value=True),
get_tickers=tickers,
)
2024-05-12 13:57:44 +00:00
mocker.patch(
"freqtrade.plugins.pairlist.RemotePairList.requests.get", return_value=mock_response
)
exchange = get_patched_exchange(mocker, rpl_config)
pairlistmanager = PairListManager(exchange, rpl_config)
2024-05-12 13:57:44 +00:00
remote_pairlist = RemotePairList(
exchange, pairlistmanager, rpl_config, rpl_config["pairlists"][1], 1
)
2024-01-24 19:31:38 +00:00
pairs, _time_elapsed = remote_pairlist.fetch_pairlist()
assert pairs == ["XRP/USDT"]
2024-05-12 13:57:44 +00:00
whitelist = remote_pairlist.filter_pairlist(rpl_config["exchange"]["pair_whitelist"], {})
assert whitelist == (["XRP/USDT"] if processing_mode == "filter" else ["ETH/USDT", "XRP/USDT"])