add tests to satisfy codecov
This commit is contained in:
@@ -14,15 +14,15 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class CrossMarketPairList(IPairList):
|
class CrossMarketPairList(IPairList):
|
||||||
|
is_pairlist_generator = True
|
||||||
supports_backtesting = SupportsBacktesting.BIASED
|
supports_backtesting = SupportsBacktesting.BIASED
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self._mode: str = self._pairlistconfig.get("mode", "whitelist")
|
self._mode: str = self._pairlistconfig.get("mode", "whitelist")
|
||||||
self._trading_mode: str = self._config["trading_mode"]
|
|
||||||
self._stake_currency: str = self._config["stake_currency"]
|
self._stake_currency: str = self._config["stake_currency"]
|
||||||
self._target_mode = "futures" if self._trading_mode == "spot" else "spot"
|
self._target_mode = "spot" if self._config["trading_mode"] == "futures" else "futures"
|
||||||
self._refresh_period = self._pairlistconfig.get("refresh_period", 1800)
|
self._refresh_period = self._pairlistconfig.get("refresh_period", 1800)
|
||||||
self._pair_cache: FtTTLCache = FtTTLCache(maxsize=1, ttl=self._refresh_period)
|
self._pair_cache: FtTTLCache = FtTTLCache(maxsize=1, ttl=self._refresh_period)
|
||||||
|
|
||||||
@@ -115,6 +115,9 @@ class CrossMarketPairList(IPairList):
|
|||||||
for pair in pairlist:
|
for pair in pairlist:
|
||||||
base = self._exchange.get_pair_base_currency(pair)
|
base = self._exchange.get_pair_base_currency(pair)
|
||||||
if not base:
|
if not base:
|
||||||
|
self.log_once(
|
||||||
|
f"Unable to get base currency for pair {pair}, skipping it.", logger.warning
|
||||||
|
)
|
||||||
filtered_pairlist.remove(pair)
|
filtered_pairlist.remove(pair)
|
||||||
continue
|
continue
|
||||||
found_in_bases = base in bases
|
found_in_bases = base in bases
|
||||||
|
|||||||
@@ -2685,6 +2685,102 @@ def test_CrossMarketPairlist_filter(
|
|||||||
assert pm.whitelist == result
|
assert pm.whitelist == result
|
||||||
|
|
||||||
|
|
||||||
|
def test_CrossMarketPairlist_gen_pairlist_uses_cache(mocker, default_conf_usdt, markets):
|
||||||
|
default_conf_usdt["trading_mode"] = "spot"
|
||||||
|
default_conf_usdt["pairlists"] = [{"method": "CrossMarketPairList", "mode": "whitelist"}]
|
||||||
|
|
||||||
|
mocker.patch.multiple(
|
||||||
|
EXMS,
|
||||||
|
markets=PropertyMock(return_value=markets),
|
||||||
|
exchange_has=MagicMock(return_value=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
exchange = get_patched_exchange(mocker, default_conf_usdt)
|
||||||
|
pm = PairListManager(exchange, default_conf_usdt)
|
||||||
|
pl = pm._pairlist_handlers[0]
|
||||||
|
|
||||||
|
pl._pair_cache["pairlist"] = ["ETH/USDT", "ADA/USDT"]
|
||||||
|
pl._exchange.get_markets = MagicMock(
|
||||||
|
side_effect=AssertionError("get_markets should not be called")
|
||||||
|
)
|
||||||
|
|
||||||
|
result = pl.gen_pairlist({})
|
||||||
|
|
||||||
|
assert result == ["ETH/USDT", "ADA/USDT"]
|
||||||
|
# Make sure the returned list is a copy, not the cached one
|
||||||
|
assert result is not pl._pair_cache["pairlist"]
|
||||||
|
result.append("BTC/USDT")
|
||||||
|
# Make sure the cache is not modified
|
||||||
|
assert pl._pair_cache["pairlist"] == ["ETH/USDT", "ADA/USDT"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_CrossMarketPairList_breaks_prefix_loop_on_match(mocker, default_conf_usdt, markets):
|
||||||
|
default_conf_usdt["trading_mode"] = "spot"
|
||||||
|
default_conf_usdt["pairlists"] = [{"method": "CrossMarketPairList", "mode": "whitelist"}]
|
||||||
|
|
||||||
|
mocker.patch.multiple(
|
||||||
|
EXMS,
|
||||||
|
markets=PropertyMock(return_value=markets),
|
||||||
|
exchange_has=MagicMock(return_value=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
exchange = get_patched_exchange(mocker, default_conf_usdt)
|
||||||
|
pm = PairListManager(exchange, default_conf_usdt)
|
||||||
|
pl = pm._pairlist_handlers[0]
|
||||||
|
|
||||||
|
# Force base lookup path
|
||||||
|
mocker.patch.object(pl, "get_base_list", return_value=["1000PEPE"])
|
||||||
|
mocker.patch.object(pl._exchange, "get_pair_base_currency", return_value="PEPE")
|
||||||
|
|
||||||
|
class PrefixesWithGuard:
|
||||||
|
def __iter__(self):
|
||||||
|
yield "1000" # first prefix => match via "1000PEPE"
|
||||||
|
raise AssertionError("Prefix loop did not break after match")
|
||||||
|
|
||||||
|
mocker.patch(
|
||||||
|
"freqtrade.plugins.pairlist.CrossMarketPairList.PairPrefixes",
|
||||||
|
new=PrefixesWithGuard(),
|
||||||
|
)
|
||||||
|
|
||||||
|
result = pl.filter_pairlist(["PEPE/USDT"], {})
|
||||||
|
assert result == ["PEPE/USDT"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_CrossMarketPairList_breaks_prefix_loop_on_delayed_match(
|
||||||
|
mocker, default_conf_usdt, markets
|
||||||
|
):
|
||||||
|
default_conf_usdt["trading_mode"] = "spot"
|
||||||
|
default_conf_usdt["pairlists"] = [{"method": "CrossMarketPairList", "mode": "whitelist"}]
|
||||||
|
|
||||||
|
mocker.patch.multiple(
|
||||||
|
EXMS,
|
||||||
|
markets=PropertyMock(return_value=markets),
|
||||||
|
exchange_has=MagicMock(return_value=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
exchange = get_patched_exchange(mocker, default_conf_usdt)
|
||||||
|
pm = PairListManager(exchange, default_conf_usdt)
|
||||||
|
pl = pm._pairlist_handlers[0]
|
||||||
|
|
||||||
|
# Force second matching path: base startswith prefix and removeprefix() matches bases.
|
||||||
|
mocker.patch.object(pl, "get_base_list", return_value=["PEPE"])
|
||||||
|
mocker.patch.object(pl._exchange, "get_pair_base_currency", return_value="1000PEPE")
|
||||||
|
|
||||||
|
class PrefixesWithGuard:
|
||||||
|
def __iter__(self):
|
||||||
|
yield "X" # no match, loop should continue
|
||||||
|
yield "1000" # second path should match via removeprefix -> PEPE and break
|
||||||
|
raise AssertionError("Prefix loop did not break after delayed match")
|
||||||
|
|
||||||
|
mocker.patch(
|
||||||
|
"freqtrade.plugins.pairlist.CrossMarketPairList.PairPrefixes",
|
||||||
|
new=PrefixesWithGuard(),
|
||||||
|
)
|
||||||
|
|
||||||
|
result = pl.filter_pairlist(["1000PEPE/USDT"], {})
|
||||||
|
assert result == ["1000PEPE/USDT"]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"pairlists,expected_error,expected_warning",
|
"pairlists,expected_error,expected_warning",
|
||||||
[
|
[
|
||||||
|
|||||||
Reference in New Issue
Block a user