Renamd volatilityFilter to RangeStabilityFilter
This commit is contained in:
parent
29c6a9263d
commit
8f1d2ff070
@ -69,8 +69,8 @@
|
||||
{"method": "PriceFilter", "low_price_ratio": 0.01, "min_price": 0.00000010},
|
||||
{"method": "SpreadFilter", "max_spread_ratio": 0.005},
|
||||
{
|
||||
"method": "VolatilityFilter",
|
||||
"volatility_over_days": 10,
|
||||
"method": "RangeStabilityFilter",
|
||||
"lookback_days": 10,
|
||||
"min_volatility": 0.01,
|
||||
"refresh_period": 1440
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ Inactive markets are always removed from the resulting pairlist. Explicitly blac
|
||||
* [`PriceFilter`](#pricefilter)
|
||||
* [`ShuffleFilter`](#shufflefilter)
|
||||
* [`SpreadFilter`](#spreadfilter)
|
||||
* [`VolatilityFilter`](#volatilityfilter)
|
||||
* [`RangeStabilityFilter`](#rangestabilityfilter)
|
||||
|
||||
!!! Tip "Testing pairlists"
|
||||
Pairlist configurations can be quite tricky to get right. Best use the [`test-pairlist`](utils.md#test-pairlist) utility sub-command to test your configuration quickly.
|
||||
@ -119,26 +119,26 @@ Example:
|
||||
|
||||
If `DOGE/BTC` maximum bid is 0.00000026 and minimum ask is 0.00000027, the ratio is calculated as: `1 - bid/ask ~= 0.037` which is `> 0.005` and this pair will be filtered out.
|
||||
|
||||
#### VolatilityFilter
|
||||
#### RangeStabilityFilter
|
||||
|
||||
Removes pairs where the difference between lowest low and highest high over `volatility_over_days` days is below `min_volatility`. Since this is a filter that requires additional data, the results are cached for `refresh_period`.
|
||||
Removes pairs where the difference between lowest low and highest high over `lookback_days` days is below `min_rate_of_change`. Since this is a filter that requires additional data, the results are cached for `refresh_period`.
|
||||
|
||||
In the below example:
|
||||
If volatility over the last 10 days is <1%, remove the pair from the whitelist.
|
||||
If the trading range over the last 10 days is <1%, remove the pair from the whitelist.
|
||||
|
||||
```json
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "VolatilityFilter",
|
||||
"volatility_over_days": 10,
|
||||
"min_volatility": 0.01,
|
||||
"method": "RangeStabilityFilter",
|
||||
"lookback_days": 10,
|
||||
"min_rate_of_change": 0.01,
|
||||
"refresh_period": 1440
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
!!! Tip
|
||||
This Filter can be used to automatically remove stable coin pairs, which have a very low volatility, and are therefore extremely difficult to trade with profit.
|
||||
This Filter can be used to automatically remove stable coin pairs, which have a very low trading range, and are therefore extremely difficult to trade with profit.
|
||||
|
||||
### Full example of Pairlist Handlers
|
||||
|
||||
@ -160,9 +160,9 @@ The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets,
|
||||
{"method": "PriceFilter", "low_price_ratio": 0.01},
|
||||
{"method": "SpreadFilter", "max_spread_ratio": 0.005},
|
||||
{
|
||||
"method": "VolatilityFilter",
|
||||
"volatility_over_days": 10,
|
||||
"min_volatility": 0.01,
|
||||
"method": "RangeStabilityFilter",
|
||||
"lookback_days": 10,
|
||||
"min_rate_of_change": 0.01,
|
||||
"refresh_period": 1440
|
||||
},
|
||||
{"method": "ShuffleFilter", "seed": 42}
|
||||
|
@ -25,7 +25,7 @@ HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss',
|
||||
'SortinoHyperOptLoss', 'SortinoHyperOptLossDaily']
|
||||
AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList',
|
||||
'AgeFilter', 'PrecisionFilter', 'PriceFilter',
|
||||
'ShuffleFilter', 'SpreadFilter', 'VolatilityFilter']
|
||||
'RangeStabilityFilter', 'ShuffleFilter', 'SpreadFilter']
|
||||
AVAILABLE_DATAHANDLERS = ['json', 'jsongz', 'hdf5']
|
||||
DRY_RUN_WALLET = 1000
|
||||
DATETIME_PRINT_FORMAT = '%Y-%m-%d %H:%M:%S'
|
||||
|
@ -15,23 +15,23 @@ from freqtrade.pairlist.IPairList import IPairList
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VolatilityFilter(IPairList):
|
||||
class RangeStabilityFilter(IPairList):
|
||||
|
||||
def __init__(self, exchange, pairlistmanager,
|
||||
config: Dict[str, Any], pairlistconfig: Dict[str, Any],
|
||||
pairlist_pos: int) -> None:
|
||||
super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos)
|
||||
|
||||
self._days = pairlistconfig.get('volatility_over_days', 10)
|
||||
self._min_volatility = pairlistconfig.get('min_volatility', 0.01)
|
||||
self._days = pairlistconfig.get('lookback_days', 10)
|
||||
self._min_rate_of_change = pairlistconfig.get('min_rate_of_change', 0.01)
|
||||
self._refresh_period = pairlistconfig.get('refresh_period', 1440)
|
||||
|
||||
self._pair_cache: TTLCache = TTLCache(maxsize=100, ttl=self._refresh_period)
|
||||
|
||||
if self._days < 1:
|
||||
raise OperationalException("VolatilityFilter requires volatility_over_days to be >= 1")
|
||||
raise OperationalException("RangeStabilityFilter requires lookback_days to be >= 1")
|
||||
if self._days > exchange.ohlcv_candle_limit:
|
||||
raise OperationalException("VolatilityFilter requires volatility_over_days to not "
|
||||
raise OperationalException("RangeStabilityFilter requires lookback_days to not "
|
||||
"exceed exchange max request size "
|
||||
f"({exchange.ohlcv_candle_limit})")
|
||||
|
||||
@ -48,12 +48,12 @@ class VolatilityFilter(IPairList):
|
||||
"""
|
||||
Short whitelist method description - used for startup-messages
|
||||
"""
|
||||
return (f"{self.name} - Filtering pairs with volatility below {self._min_volatility} "
|
||||
f"over the last {plural(self._days, 'day')}.")
|
||||
return (f"{self.name} - Filtering pairs with rate of change below "
|
||||
f"{self._min_rate_of_change} over the last {plural(self._days, 'day')}.")
|
||||
|
||||
def _validate_pair(self, ticker: Dict) -> bool:
|
||||
"""
|
||||
Validate volatility
|
||||
Validate trading range
|
||||
:param ticker: ticker dict as returned from ccxt.load_markets()
|
||||
:return: True if the pair can stay, False if it should be removed
|
||||
"""
|
||||
@ -75,14 +75,14 @@ class VolatilityFilter(IPairList):
|
||||
highest_high = daily_candles['high'].max()
|
||||
lowest_low = daily_candles['low'].min()
|
||||
pct_change = ((highest_high - lowest_low) / lowest_low) if lowest_low > 0 else 0
|
||||
if pct_change >= self._min_volatility:
|
||||
if pct_change >= self._min_rate_of_change:
|
||||
result = True
|
||||
else:
|
||||
self.log_on_refresh(logger.info,
|
||||
f"Removed {pair} from whitelist, "
|
||||
f"because volatility over {plural(self._days, 'day')} is "
|
||||
f"because rate of change over {plural(self._days, 'day')} is "
|
||||
f"{pct_change:.3f}, which is below the "
|
||||
f"threshold of {self._min_volatility}.")
|
||||
f"threshold of {self._min_rate_of_change}.")
|
||||
result = False
|
||||
self._pair_cache[pair] = result
|
||||
|
@ -341,8 +341,8 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf):
|
||||
{"method": "PriceFilter", "low_price_ratio": 0.02}],
|
||||
"USDT", ['ETH/USDT', 'NANO/USDT']),
|
||||
([{"method": "StaticPairList"},
|
||||
{"method": "VolatilityFilter", "volatility_over_days": 10,
|
||||
"min_volatility": 0.01, "refresh_period": 1440}],
|
||||
{"method": "RangeStabilityFilter", "lookback_days": 10,
|
||||
"min_rate_of_change": 0.01, "refresh_period": 1440}],
|
||||
"BTC", ['ETH/BTC', 'TKN/BTC', 'HOT/BTC']),
|
||||
])
|
||||
def test_VolumePairList_whitelist_gen(mocker, whitelist_conf, shitcoinmarkets, tickers,
|
||||
@ -586,9 +586,9 @@ def test_agefilter_caching(mocker, markets, whitelist_conf_agefilter, tickers, o
|
||||
assert freqtrade.exchange.get_historic_ohlcv.call_count == previous_call_count
|
||||
|
||||
|
||||
def test_volatilityfilter_checks(mocker, default_conf, markets, tickers):
|
||||
def test_rangestabilityfilter_checks(mocker, default_conf, markets, tickers):
|
||||
default_conf['pairlists'] = [{'method': 'VolumePairList', 'number_assets': 10},
|
||||
{'method': 'VolatilityFilter', 'volatility_over_days': 99999}]
|
||||
{'method': 'RangeStabilityFilter', 'lookback_days': 99999}]
|
||||
|
||||
mocker.patch.multiple('freqtrade.exchange.Exchange',
|
||||
markets=PropertyMock(return_value=markets),
|
||||
@ -597,27 +597,27 @@ def test_volatilityfilter_checks(mocker, default_conf, markets, tickers):
|
||||
)
|
||||
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'VolatilityFilter requires volatility_over_days to not exceed '
|
||||
match=r'RangeStabilityFilter requires lookback_days to not exceed '
|
||||
r'exchange max request size \([0-9]+\)'):
|
||||
get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
default_conf['pairlists'] = [{'method': 'VolumePairList', 'number_assets': 10},
|
||||
{'method': 'VolatilityFilter', 'volatility_over_days': 0}]
|
||||
{'method': 'RangeStabilityFilter', 'lookback_days': 0}]
|
||||
|
||||
with pytest.raises(OperationalException,
|
||||
match='VolatilityFilter requires volatility_over_days to be >= 1'):
|
||||
match='RangeStabilityFilter requires lookback_days to be >= 1'):
|
||||
get_patched_freqtradebot(mocker, default_conf)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('min_volatility,expected_length', [
|
||||
@pytest.mark.parametrize('min_rate_of_change,expected_length', [
|
||||
(0.01, 5),
|
||||
(0.05, 0), # Setting volatility to 5% removes all pairs from the whitelist.
|
||||
(0.05, 0), # Setting rate_of_change to 5% removes all pairs from the whitelist.
|
||||
])
|
||||
def test_volatilityfilter_caching(mocker, markets, default_conf, tickers, ohlcv_history_list,
|
||||
min_volatility, expected_length):
|
||||
def test_rangestabilityfilter_caching(mocker, markets, default_conf, tickers, ohlcv_history_list,
|
||||
min_rate_of_change, expected_length):
|
||||
default_conf['pairlists'] = [{'method': 'VolumePairList', 'number_assets': 10},
|
||||
{'method': 'VolatilityFilter', 'volatility_over_days': 2,
|
||||
'min_volatility': min_volatility}]
|
||||
{'method': 'RangeStabilityFilter', 'lookback_days': 2,
|
||||
'min_rate_of_change': min_rate_of_change}]
|
||||
|
||||
mocker.patch.multiple('freqtrade.exchange.Exchange',
|
||||
markets=PropertyMock(return_value=markets),
|
||||
@ -677,9 +677,9 @@ def test_volatilityfilter_caching(mocker, markets, default_conf, tickers, ohlcv_
|
||||
None,
|
||||
"PriceFilter requires max_price to be >= 0"
|
||||
), # OperationalException expected
|
||||
({"method": "VolatilityFilter", "volatility_over_days": 10, "min_volatility": 0.01},
|
||||
"[{'VolatilityFilter': 'VolatilityFilter - Filtering pairs with volatility below 0.01 "
|
||||
"over the last days.'}]",
|
||||
({"method": "RangeStabilityFilter", "lookback_days": 10, "min_rate_of_change": 0.01},
|
||||
"[{'RangeStabilityFilter': 'RangeStabilityFilter - Filtering pairs with rate of change below "
|
||||
"0.01 over the last days.'}]",
|
||||
None
|
||||
),
|
||||
])
|
||||
|
Loading…
Reference in New Issue
Block a user