mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-12-17 05:11:15 +00:00
Merge pull request #12448 from stash86/main-stash
Add blacklist mode to MarketcapPairlist
This commit is contained in:
@@ -367,7 +367,7 @@ The optional `bearer_token` will be included in the requests Authorization Heade
|
|||||||
|
|
||||||
#### MarketCapPairList
|
#### MarketCapPairList
|
||||||
|
|
||||||
`MarketCapPairList` employs sorting/filtering of pairs by their marketcap rank based of CoinGecko. The returned pairlist will be sorted based of their marketcap ranks.
|
`MarketCapPairList` employs sorting/filtering of pairs by their marketcap rank based of CoinGecko. The returned pairlist will be sorted based of their marketcap ranks if used in whitelist `mode`.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"pairlists": [
|
"pairlists": [
|
||||||
@@ -376,16 +376,21 @@ The optional `bearer_token` will be included in the requests Authorization Heade
|
|||||||
"number_assets": 20,
|
"number_assets": 20,
|
||||||
"max_rank": 50,
|
"max_rank": 50,
|
||||||
"refresh_period": 86400,
|
"refresh_period": 86400,
|
||||||
|
"mode": "whitelist",
|
||||||
"categories": ["layer-1"]
|
"categories": ["layer-1"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
`number_assets` defines the maximum number of pairs returned by the pairlist. `max_rank` will determine the maximum rank used in creating/filtering the pairlist. It's expected that some coins within the top `max_rank` marketcap will not be included in the resulting pairlist since not all pairs will have active trading pairs in your preferred market/stake/exchange combination.
|
`number_assets` defines the maximum number of pairs returned by the pairlist if used in whitelist `mode`. In blacklist `mode`, this setting will be ignored.
|
||||||
|
|
||||||
|
`max_rank` will determine the maximum rank used in creating/filtering the pairlist. It's expected that some coins within the top `max_rank` marketcap will not be included in the resulting pairlist since not all pairs will have active trading pairs in your preferred market/stake/exchange combination.
|
||||||
While using a `max_rank` bigger than 250 is supported, it's not recommended, as it'll cause multiple API calls to CoinGecko, which can lead to rate limit issues.
|
While using a `max_rank` bigger than 250 is supported, it's not recommended, as it'll cause multiple API calls to CoinGecko, which can lead to rate limit issues.
|
||||||
|
|
||||||
The `refresh_period` setting defines the interval (in seconds) at which the marketcap rank data will be refreshed. The default is 86,400 seconds (1 day). The pairlist cache (`refresh_period`) applies to both generating pairlists (when in the first position in the list) and filtering instances (when not in the first position in the list).
|
The `refresh_period` setting defines the interval (in seconds) at which the marketcap rank data will be refreshed. The default is 86,400 seconds (1 day). The pairlist cache (`refresh_period`) applies to both generating pairlists (when in the first position in the list) and filtering instances (when not in the first position in the list).
|
||||||
|
|
||||||
|
The `mode` setting defines whether the plugin will filters in (whitelist `mode`) or filters out (blacklist `mode`) top marketcap ranked coins. By default, the plugin will be in whitelist mode.
|
||||||
|
|
||||||
The `categories` setting specifies the [coingecko categories](https://www.coingecko.com/en/categories) from which to select coins from. The default is an empty list `[]`, meaning no category filtering is applied.
|
The `categories` setting specifies the [coingecko categories](https://www.coingecko.com/en/categories) from which to select coins from. The default is an empty list `[]`, meaning no category filtering is applied.
|
||||||
If an incorrect category string is chosen, the plugin will print the available categories from CoinGecko and fail. The category should be the ID of the category, for example, for `https://www.coingecko.com/en/categories/layer-1`, the category ID would be `layer-1`. You can pass multiple categories such as `["layer-1", "meme-token"]` to select from several categories.
|
If an incorrect category string is chosen, the plugin will print the available categories from CoinGecko and fail. The category should be the ID of the category, for example, for `https://www.coingecko.com/en/categories/layer-1`, the category ID would be `layer-1`. You can pass multiple categories such as `["layer-1", "meme-token"]` to select from several categories.
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,16 @@ class MarketCapPairList(IPairList):
|
|||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
if "number_assets" not in self._pairlistconfig:
|
self._mode = self._pairlistconfig.get("mode", "whitelist")
|
||||||
|
|
||||||
|
if (self._mode == "whitelist") and ("number_assets" not in self._pairlistconfig):
|
||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
"`number_assets` not specified. Please check your configuration "
|
"`number_assets` not specified. Please check your configuration "
|
||||||
'for "pairlist.config.number_assets"'
|
'for "pairlist.config.number_assets"'
|
||||||
)
|
)
|
||||||
|
|
||||||
self._stake_currency = self._config["stake_currency"]
|
self._stake_currency = self._config["stake_currency"]
|
||||||
self._number_assets = self._pairlistconfig["number_assets"]
|
self._number_assets = self._pairlistconfig.get("number_assets", 30)
|
||||||
self._max_rank = self._pairlistconfig.get("max_rank", 30)
|
self._max_rank = self._pairlistconfig.get("max_rank", 30)
|
||||||
self._refresh_period = self._pairlistconfig.get("refresh_period", 86400)
|
self._refresh_period = self._pairlistconfig.get("refresh_period", 86400)
|
||||||
self._categories = self._pairlistconfig.get("categories", [])
|
self._categories = self._pairlistconfig.get("categories", [])
|
||||||
@@ -78,7 +80,9 @@ class MarketCapPairList(IPairList):
|
|||||||
"""
|
"""
|
||||||
num = self._number_assets
|
num = self._number_assets
|
||||||
rank = self._max_rank
|
rank = self._max_rank
|
||||||
msg = f"{self.name} - {num} pairs placed within top {rank} market cap."
|
mode = self._mode
|
||||||
|
pair_text = num if (mode == "whitelist") else "blacklisting"
|
||||||
|
msg = f"{self.name} - {pair_text} pairs placed within top {rank} market cap."
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -115,6 +119,13 @@ class MarketCapPairList(IPairList):
|
|||||||
"description": "Refresh period",
|
"description": "Refresh period",
|
||||||
"help": "Refresh period in seconds",
|
"help": "Refresh period in seconds",
|
||||||
},
|
},
|
||||||
|
"mode": {
|
||||||
|
"type": "option",
|
||||||
|
"default": "whitelist",
|
||||||
|
"options": ["whitelist", "blacklist"],
|
||||||
|
"description": "Mode of operation",
|
||||||
|
"help": "Mode of operation (whitelist/blacklist)",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_markets_exchange(self):
|
def get_markets_exchange(self):
|
||||||
@@ -186,6 +197,9 @@ class MarketCapPairList(IPairList):
|
|||||||
:return: new whitelist
|
:return: new whitelist
|
||||||
"""
|
"""
|
||||||
marketcap_list = self._marketcap_cache.get("marketcap")
|
marketcap_list = self._marketcap_cache.get("marketcap")
|
||||||
|
mode = self._mode
|
||||||
|
is_whitelist_mode = mode == "whitelist"
|
||||||
|
filtered_pairlist: list[str] = []
|
||||||
|
|
||||||
default_kwargs = {
|
default_kwargs = {
|
||||||
"vs_currency": "usd",
|
"vs_currency": "usd",
|
||||||
@@ -219,12 +233,10 @@ class MarketCapPairList(IPairList):
|
|||||||
self._marketcap_cache["marketcap"] = marketcap_list
|
self._marketcap_cache["marketcap"] = marketcap_list
|
||||||
|
|
||||||
if marketcap_list:
|
if marketcap_list:
|
||||||
filtered_pairlist: list[str] = []
|
|
||||||
|
|
||||||
market = self._exchange._config["trading_mode"]
|
market = self._exchange._config["trading_mode"]
|
||||||
pair_format = f"{self._stake_currency.upper()}"
|
pair_format = f"{self._stake_currency.upper()}" + (
|
||||||
if market == "futures":
|
f":{self._stake_currency.upper()}" if market == "futures" else ""
|
||||||
pair_format += f":{self._stake_currency.upper()}"
|
)
|
||||||
|
|
||||||
top_marketcap = marketcap_list[: self._max_rank :]
|
top_marketcap = marketcap_list[: self._max_rank :]
|
||||||
markets = self.get_markets_exchange()
|
markets = self.get_markets_exchange()
|
||||||
@@ -234,13 +246,16 @@ class MarketCapPairList(IPairList):
|
|||||||
resolved = self.resolve_marketcap_pair(pair, pairlist, markets, filtered_pairlist)
|
resolved = self.resolve_marketcap_pair(pair, pairlist, markets, filtered_pairlist)
|
||||||
|
|
||||||
if resolved:
|
if resolved:
|
||||||
filtered_pairlist.append(resolved)
|
if not is_whitelist_mode:
|
||||||
|
pairlist.remove(resolved)
|
||||||
|
continue
|
||||||
|
|
||||||
|
filtered_pairlist.append(resolved)
|
||||||
if len(filtered_pairlist) == self._number_assets:
|
if len(filtered_pairlist) == self._number_assets:
|
||||||
break
|
break
|
||||||
|
|
||||||
if len(filtered_pairlist) > 0:
|
if not is_whitelist_mode:
|
||||||
return filtered_pairlist
|
return pairlist
|
||||||
|
|
||||||
# If no pairs are found, return the original pairlist
|
# If no pairs are found, return the original pairlist
|
||||||
return []
|
return filtered_pairlist
|
||||||
|
|||||||
@@ -2334,6 +2334,36 @@ def test_FullTradesFilter(mocker, default_conf_usdt, fee, caplog) -> None:
|
|||||||
["ETH/USDT:USDT", "ADA/USDT:USDT"],
|
["ETH/USDT:USDT", "ADA/USDT:USDT"],
|
||||||
["layer-1", "protocol"],
|
["layer-1", "protocol"],
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
# Blacklist high MC pairs
|
||||||
|
{"method": "StaticPairList", "allow_inactive": True},
|
||||||
|
{"method": "MarketCapPairList", "mode": "blacklist"},
|
||||||
|
],
|
||||||
|
"spot",
|
||||||
|
["LTC/USDT", "NEO/USDT", "TKN/USDT", "ETC/USDT"],
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
# Blacklist high MC pairs
|
||||||
|
{"method": "StaticPairList", "allow_inactive": True},
|
||||||
|
{"method": "MarketCapPairList", "mode": "blacklist", "max_rank": 2},
|
||||||
|
],
|
||||||
|
"spot",
|
||||||
|
["LTC/USDT", "XRP/USDT", "NEO/USDT", "TKN/USDT", "ETC/USDT", "ADA/USDT"],
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[
|
||||||
|
# Blacklist top 6 MarketCap pairs - removes XRP which is at spot 6.
|
||||||
|
{"method": "StaticPairList", "allow_inactive": True},
|
||||||
|
{"method": "MarketCapPairList", "mode": "blacklist", "max_rank": 6},
|
||||||
|
],
|
||||||
|
"spot",
|
||||||
|
["LTC/USDT", "NEO/USDT", "TKN/USDT", "ETC/USDT", "ADA/USDT"],
|
||||||
|
1,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_MarketCapPairList_filter(
|
def test_MarketCapPairList_filter(
|
||||||
|
|||||||
Reference in New Issue
Block a user