2020-11-28 03:24:40 +00:00
|
|
|
"""
|
|
|
|
Performance pair list filter
|
|
|
|
"""
|
|
|
|
import logging
|
2021-09-18 06:26:48 +00:00
|
|
|
from typing import Any, Dict, List
|
2020-11-28 03:24:40 +00:00
|
|
|
|
|
|
|
import pandas as pd
|
|
|
|
|
2022-09-18 17:36:11 +00:00
|
|
|
from freqtrade.constants import Config
|
2020-11-28 03:24:40 +00:00
|
|
|
from freqtrade.persistence import Trade
|
2020-12-23 16:00:02 +00:00
|
|
|
from freqtrade.plugins.pairlist.IPairList import IPairList
|
2020-11-28 03:24:40 +00:00
|
|
|
|
2020-11-28 07:59:30 +00:00
|
|
|
|
2020-11-28 03:24:40 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2020-11-28 07:34:18 +00:00
|
|
|
|
2020-11-28 03:24:40 +00:00
|
|
|
class PerformanceFilter(IPairList):
|
|
|
|
|
2021-09-16 11:48:02 +00:00
|
|
|
def __init__(self, exchange, pairlistmanager,
|
2022-09-18 11:31:52 +00:00
|
|
|
config: Config, pairlistconfig: Dict[str, Any],
|
2021-09-16 11:48:02 +00:00
|
|
|
pairlist_pos: int) -> None:
|
|
|
|
super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos)
|
|
|
|
|
2021-09-18 06:36:06 +00:00
|
|
|
self._minutes = pairlistconfig.get('minutes', 0)
|
2022-05-17 22:11:10 +00:00
|
|
|
self._min_profit = pairlistconfig.get('min_profit')
|
2021-09-16 11:48:02 +00:00
|
|
|
|
2020-11-28 03:24:40 +00:00
|
|
|
@property
|
|
|
|
def needstickers(self) -> bool:
|
|
|
|
"""
|
|
|
|
Boolean property defining if tickers are necessary.
|
2021-06-25 13:45:49 +00:00
|
|
|
If no Pairlist requires tickers, an empty List is passed
|
2020-11-28 03:24:40 +00:00
|
|
|
as tickers argument to filter_pairlist
|
|
|
|
"""
|
|
|
|
return False
|
|
|
|
|
|
|
|
def short_desc(self) -> str:
|
|
|
|
"""
|
2020-11-28 18:17:03 +00:00
|
|
|
Short allowlist method description - used for startup-messages
|
2020-11-28 03:24:40 +00:00
|
|
|
"""
|
|
|
|
return f"{self.name} - Sorting pairs by performance."
|
|
|
|
|
|
|
|
def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]:
|
|
|
|
"""
|
2020-11-28 18:17:03 +00:00
|
|
|
Filters and sorts pairlist and returns the allowlist again.
|
2020-11-28 03:24:40 +00:00
|
|
|
Called on each bot iteration - please use internal caching if necessary
|
|
|
|
:param pairlist: pairlist to filter or sort
|
|
|
|
:param tickers: Tickers (from exchange.get_tickers()). May be cached.
|
2020-11-28 18:17:03 +00:00
|
|
|
:return: new allowlist
|
2020-11-28 03:24:40 +00:00
|
|
|
"""
|
|
|
|
# Get the trading performance for pairs from database
|
2021-05-16 17:55:13 +00:00
|
|
|
try:
|
2021-09-18 06:36:06 +00:00
|
|
|
performance = pd.DataFrame(Trade.get_overall_performance(self._minutes))
|
2021-05-16 17:55:13 +00:00
|
|
|
except AttributeError:
|
|
|
|
# Performancefilter does not work in backtesting.
|
|
|
|
self.log_once("PerformanceFilter is not available in this mode.", logger.warning)
|
|
|
|
return pairlist
|
2020-11-28 15:45:17 +00:00
|
|
|
|
|
|
|
# Skip performance-based sorting if no performance data is available
|
|
|
|
if len(performance) == 0:
|
|
|
|
return pairlist
|
2020-11-28 18:29:31 +00:00
|
|
|
|
2020-11-28 18:17:03 +00:00
|
|
|
# Get pairlist from performance dataframe values
|
2020-11-28 07:34:18 +00:00
|
|
|
list_df = pd.DataFrame({'pair': pairlist})
|
2022-02-06 15:19:11 +00:00
|
|
|
list_df['prior_idx'] = list_df.index
|
2020-11-28 18:17:03 +00:00
|
|
|
|
|
|
|
# Set initial value for pairs with no trades to 0
|
|
|
|
# Sort the list using:
|
|
|
|
# - primarily performance (high to low)
|
|
|
|
# - then count (low to high, so as to favor same performance with fewer trades)
|
|
|
|
# - then pair name alphametically
|
2020-11-28 15:45:17 +00:00
|
|
|
sorted_df = list_df.merge(performance, on='pair', how='left')\
|
2022-02-06 15:19:11 +00:00
|
|
|
.fillna(0).sort_values(by=['count', 'prior_idx'], ascending=True)\
|
2021-12-12 12:21:24 +00:00
|
|
|
.sort_values(by=['profit_ratio'], ascending=False)
|
2021-10-04 15:49:57 +00:00
|
|
|
if self._min_profit is not None:
|
2021-12-12 12:21:24 +00:00
|
|
|
removed = sorted_df[sorted_df['profit_ratio'] < self._min_profit]
|
2021-10-14 17:33:32 +00:00
|
|
|
for _, row in removed.iterrows():
|
|
|
|
self.log_once(
|
2021-12-12 12:21:24 +00:00
|
|
|
f"Removing pair {row['pair']} since {row['profit_ratio']} is "
|
2021-10-14 17:33:32 +00:00
|
|
|
f"below {self._min_profit}", logger.info)
|
2021-12-12 12:21:24 +00:00
|
|
|
sorted_df = sorted_df[sorted_df['profit_ratio'] >= self._min_profit]
|
2021-10-14 17:33:32 +00:00
|
|
|
|
2020-11-28 03:24:40 +00:00
|
|
|
pairlist = sorted_df['pair'].tolist()
|
|
|
|
|
2020-11-28 07:34:18 +00:00
|
|
|
return pairlist
|