[SQUASH] Get rid of _initialize() and fix informatives for dynamic pairlists.
This commit is contained in:
parent
f81df19b93
commit
5dc78a0c66
@ -87,8 +87,6 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
self.strategy.dp = self.dataprovider
|
self.strategy.dp = self.dataprovider
|
||||||
# Attach Wallets to strategy instance
|
# Attach Wallets to strategy instance
|
||||||
self.strategy.wallets = self.wallets
|
self.strategy.wallets = self.wallets
|
||||||
# Late initialization (may depend on dp/wallets)
|
|
||||||
self.strategy._initialize()
|
|
||||||
|
|
||||||
# Initializing Edge only if enabled
|
# Initializing Edge only if enabled
|
||||||
self.edge = Edge(self.config, self.exchange, self.strategy) if \
|
self.edge = Edge(self.config, self.exchange, self.strategy) if \
|
||||||
|
@ -159,7 +159,6 @@ class Backtesting:
|
|||||||
# since a "perfect" stoploss-sell is assumed anyway
|
# since a "perfect" stoploss-sell is assumed anyway
|
||||||
# And the regular "stoploss" function would not apply to that case
|
# And the regular "stoploss" function would not apply to that case
|
||||||
self.strategy.order_types['stoploss_on_exchange'] = False
|
self.strategy.order_types['stoploss_on_exchange'] = False
|
||||||
strategy._initialize()
|
|
||||||
|
|
||||||
def _load_protections(self, strategy: IStrategy):
|
def _load_protections(self, strategy: IStrategy):
|
||||||
if self.config.get('enable_protections', False):
|
if self.config.get('enable_protections', False):
|
||||||
|
@ -35,7 +35,6 @@ class EdgeCli:
|
|||||||
self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config)
|
self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config)
|
||||||
self.strategy = StrategyResolver.load_strategy(self.config)
|
self.strategy = StrategyResolver.load_strategy(self.config)
|
||||||
self.strategy.dp = DataProvider(config, None)
|
self.strategy.dp = DataProvider(config, None)
|
||||||
self.strategy._initialize()
|
|
||||||
|
|
||||||
validate_config_consistency(self.config)
|
validate_config_consistency(self.config)
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
# Class level variables (intentional) containing
|
# Class level variables (intentional) containing
|
||||||
# the dataprovider (dp) (access to other candles, historic data, ...)
|
# the dataprovider (dp) (access to other candles, historic data, ...)
|
||||||
# and wallets - access to the current balance.
|
# and wallets - access to the current balance.
|
||||||
dp: Optional[DataProvider] = None
|
dp: DataProvider
|
||||||
wallets: Optional[Wallets] = None
|
wallets: Optional[Wallets] = None
|
||||||
# Filled from configuration
|
# Filled from configuration
|
||||||
stake_currency: str
|
stake_currency: str
|
||||||
@ -137,44 +137,23 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
self._last_candle_seen_per_pair: Dict[str, datetime] = {}
|
self._last_candle_seen_per_pair: Dict[str, datetime] = {}
|
||||||
super().__init__(config)
|
super().__init__(config)
|
||||||
|
|
||||||
def _initialize(self):
|
|
||||||
"""
|
|
||||||
Late initialization tasks, which may depend on availability of dataprovider/wallets/etc.
|
|
||||||
"""
|
|
||||||
# Gather informative pairs from @informative-decorated methods.
|
# Gather informative pairs from @informative-decorated methods.
|
||||||
self._ft_informative: Dict[
|
self._ft_informative: List[Tuple[InformativeData, PopulateIndicators]] = []
|
||||||
Tuple[str, str], List[Tuple[InformativeData, PopulateIndicators]]] = {}
|
|
||||||
for attr_name in dir(self.__class__):
|
for attr_name in dir(self.__class__):
|
||||||
cls_method = getattr(self.__class__, attr_name)
|
cls_method = getattr(self.__class__, attr_name)
|
||||||
if not callable(cls_method):
|
if not callable(cls_method):
|
||||||
continue
|
continue
|
||||||
ft_informative = getattr(cls_method, '_ft_informative', None)
|
informative_data_list = getattr(cls_method, '_ft_informative', None)
|
||||||
if not isinstance(ft_informative, list):
|
if not isinstance(informative_data_list, list):
|
||||||
# Type check is required because mocker would return a mock object that evaluates to
|
# Type check is required because mocker would return a mock object that evaluates to
|
||||||
# True, confusing this code.
|
# True, confusing this code.
|
||||||
continue
|
continue
|
||||||
strategy_timeframe_minutes = timeframe_to_minutes(self.timeframe)
|
strategy_timeframe_minutes = timeframe_to_minutes(self.timeframe)
|
||||||
for informative_data in ft_informative:
|
for informative_data in informative_data_list:
|
||||||
asset = informative_data.asset
|
if timeframe_to_minutes(informative_data.timeframe) < strategy_timeframe_minutes:
|
||||||
timeframe = informative_data.timeframe
|
|
||||||
if timeframe_to_minutes(timeframe) < strategy_timeframe_minutes:
|
|
||||||
raise OperationalException('Informative timeframe must be equal or higher than '
|
raise OperationalException('Informative timeframe must be equal or higher than '
|
||||||
'strategy timeframe!')
|
'strategy timeframe!')
|
||||||
if asset:
|
self._ft_informative.append((informative_data, cls_method))
|
||||||
pair = _format_pair_name(self.config, asset)
|
|
||||||
try:
|
|
||||||
self._ft_informative[(pair, timeframe)].append(
|
|
||||||
(informative_data, cls_method))
|
|
||||||
except KeyError:
|
|
||||||
self._ft_informative[(pair, timeframe)] = [(informative_data, cls_method)]
|
|
||||||
else:
|
|
||||||
for pair in self.dp.current_whitelist():
|
|
||||||
try:
|
|
||||||
self._ft_informative[(pair, timeframe)].append(
|
|
||||||
(informative_data, cls_method))
|
|
||||||
except KeyError:
|
|
||||||
self._ft_informative[(pair, timeframe)] = \
|
|
||||||
[(informative_data, cls_method)]
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
@ -424,8 +403,13 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
Internal method which gathers all informative pairs (user or automatically defined).
|
Internal method which gathers all informative pairs (user or automatically defined).
|
||||||
"""
|
"""
|
||||||
informative_pairs = self.informative_pairs()
|
informative_pairs = self.informative_pairs()
|
||||||
if hasattr(self, '_ft_informative'):
|
for inf_data, _ in self._ft_informative:
|
||||||
informative_pairs += list(self._ft_informative.keys())
|
if inf_data.asset:
|
||||||
|
pair_tf = (_format_pair_name(self.config, inf_data.asset), inf_data.timeframe)
|
||||||
|
informative_pairs.append(pair_tf)
|
||||||
|
else:
|
||||||
|
for pair in self.dp.current_whitelist():
|
||||||
|
informative_pairs.append((pair, inf_data.timeframe))
|
||||||
return list(set(informative_pairs))
|
return list(set(informative_pairs))
|
||||||
|
|
||||||
def get_strategy_name(self) -> str:
|
def get_strategy_name(self) -> str:
|
||||||
@ -845,14 +829,10 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
"""
|
"""
|
||||||
logger.debug(f"Populating indicators for pair {metadata.get('pair')}.")
|
logger.debug(f"Populating indicators for pair {metadata.get('pair')}.")
|
||||||
|
|
||||||
if hasattr(self, '_ft_informative'):
|
|
||||||
# call populate_indicators_Nm() which were tagged with @informative decorator.
|
# call populate_indicators_Nm() which were tagged with @informative decorator.
|
||||||
for (pair, timeframe), informatives in self._ft_informative.items():
|
for inf_data, populate_fn in self._ft_informative:
|
||||||
for (informative_data, populate_fn) in informatives:
|
|
||||||
if not informative_data.asset and pair != metadata['pair']:
|
|
||||||
continue
|
|
||||||
dataframe = _create_and_merge_informative_pair(
|
dataframe = _create_and_merge_informative_pair(
|
||||||
self, dataframe, metadata, informative_data, populate_fn)
|
self, dataframe, metadata, inf_data, populate_fn)
|
||||||
|
|
||||||
if self._populate_fun_len == 2:
|
if self._populate_fun_len == 2:
|
||||||
warnings.warn("deprecated - check out the Sample strategy to see "
|
warnings.warn("deprecated - check out the Sample strategy to see "
|
||||||
|
@ -171,14 +171,13 @@ def _format_pair_name(config, pair: str) -> str:
|
|||||||
stake=config['stake_currency']).upper()
|
stake=config['stake_currency']).upper()
|
||||||
|
|
||||||
|
|
||||||
def _create_and_merge_informative_pair(strategy, dataframe: DataFrame,
|
def _create_and_merge_informative_pair(strategy, dataframe: DataFrame, metadata: dict,
|
||||||
metadata: dict, informative_data: InformativeData,
|
inf_data: InformativeData,
|
||||||
populate_indicators: Callable[[Any, DataFrame, dict],
|
populate_indicators: PopulateIndicators):
|
||||||
DataFrame]):
|
asset = inf_data.asset or ''
|
||||||
asset = informative_data.asset or ''
|
timeframe = inf_data.timeframe
|
||||||
timeframe = informative_data.timeframe
|
fmt = inf_data.fmt
|
||||||
fmt = informative_data.fmt
|
ffill = inf_data.ffill
|
||||||
ffill = informative_data.ffill
|
|
||||||
config = strategy.config
|
config = strategy.config
|
||||||
dp = strategy.dp
|
dp = strategy.dp
|
||||||
|
|
||||||
@ -205,7 +204,7 @@ def _create_and_merge_informative_pair(strategy, dataframe: DataFrame,
|
|||||||
fmt = '{column}_{timeframe}' # Informatives of current pair
|
fmt = '{column}_{timeframe}' # Informatives of current pair
|
||||||
if quote != config['stake_currency']:
|
if quote != config['stake_currency']:
|
||||||
fmt = '{quote}_' + fmt # Informatives of different quote currency
|
fmt = '{quote}_' + fmt # Informatives of different quote currency
|
||||||
if informative_data.asset:
|
if inf_data.asset:
|
||||||
fmt = '{base}_' + fmt # Informatives of other pair
|
fmt = '{base}_' + fmt # Informatives of other pair
|
||||||
|
|
||||||
inf_metadata = {'pair': asset, 'timeframe': timeframe}
|
inf_metadata = {'pair': asset, 'timeframe': timeframe}
|
||||||
|
@ -160,9 +160,8 @@ def test_informative_decorator(mocker, default_conf):
|
|||||||
mocker.patch.object(strategy.dp, 'current_whitelist', return_value=[
|
mocker.patch.object(strategy.dp, 'current_whitelist', return_value=[
|
||||||
'XRP/USDT', 'LTC/USDT', 'BTC/USDT'
|
'XRP/USDT', 'LTC/USDT', 'BTC/USDT'
|
||||||
])
|
])
|
||||||
strategy._initialize()
|
|
||||||
|
|
||||||
assert len(strategy._ft_informative) == 8
|
assert len(strategy._ft_informative) == 6 # Equal to number of decorators used
|
||||||
informative_pairs = [('XRP/USDT', '1h'), ('LTC/USDT', '1h'), ('XRP/USDT', '30m'),
|
informative_pairs = [('XRP/USDT', '1h'), ('LTC/USDT', '1h'), ('XRP/USDT', '30m'),
|
||||||
('LTC/USDT', '30m'), ('BTC/USDT', '1h'), ('BTC/USDT', '30m'),
|
('LTC/USDT', '30m'), ('BTC/USDT', '1h'), ('BTC/USDT', '30m'),
|
||||||
('BTC/USDT', '5m'), ('ETH/BTC', '1h'), ('ETH/USDT', '30m')]
|
('BTC/USDT', '5m'), ('ETH/BTC', '1h'), ('ETH/USDT', '30m')]
|
||||||
|
Loading…
Reference in New Issue
Block a user