Merge pull request #6312 from freqtrade/short_informative_decorator
Short informative decorator
This commit is contained in:
@@ -78,8 +78,9 @@ class DataProvider:
|
||||
:param timeframe: timeframe to get data for
|
||||
:param candle_type: '', mark, index, premiumIndex, or funding_rate
|
||||
"""
|
||||
candleType = CandleType.from_string(candle_type)
|
||||
saved_pair = (pair, str(timeframe), candleType)
|
||||
_candle_type = CandleType.from_string(
|
||||
candle_type) if candle_type != '' else self._config['candle_type_def']
|
||||
saved_pair = (pair, str(timeframe), _candle_type)
|
||||
if saved_pair not in self.__cached_pairs_backtesting:
|
||||
timerange = TimeRange.parse_timerange(None if self._config.get(
|
||||
'timerange') is None else str(self._config.get('timerange')))
|
||||
@@ -93,7 +94,7 @@ class DataProvider:
|
||||
datadir=self._config['datadir'],
|
||||
timerange=timerange,
|
||||
data_format=self._config.get('dataformat_ohlcv', 'json'),
|
||||
candle_type=candleType,
|
||||
candle_type=_candle_type,
|
||||
|
||||
)
|
||||
return self.__cached_pairs_backtesting[saved_pair].copy()
|
||||
@@ -221,8 +222,10 @@ class DataProvider:
|
||||
if self._exchange is None:
|
||||
raise OperationalException(NO_EXCHANGE_EXCEPTION)
|
||||
if self.runmode in (RunMode.DRY_RUN, RunMode.LIVE):
|
||||
_candle_type = CandleType.from_string(
|
||||
candle_type) if candle_type != '' else self._config['candle_type_def']
|
||||
return self._exchange.klines(
|
||||
(pair, timeframe or self._config['timeframe'], CandleType.from_string(candle_type)),
|
||||
(pair, timeframe or self._config['timeframe'], _candle_type),
|
||||
copy=copy
|
||||
)
|
||||
else:
|
||||
|
@@ -1,4 +1,5 @@
|
||||
from typing import Any, Callable, NamedTuple, Optional, Union
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Callable, Optional, Union
|
||||
|
||||
from pandas import DataFrame
|
||||
|
||||
@@ -10,16 +11,19 @@ from freqtrade.strategy.strategy_helper import merge_informative_pair
|
||||
PopulateIndicators = Callable[[Any, DataFrame, dict], DataFrame]
|
||||
|
||||
|
||||
class InformativeData(NamedTuple):
|
||||
@dataclass
|
||||
class InformativeData:
|
||||
asset: Optional[str]
|
||||
timeframe: str
|
||||
fmt: Union[str, Callable[[Any], str], None]
|
||||
ffill: bool
|
||||
candle_type: CandleType
|
||||
candle_type: Optional[CandleType]
|
||||
|
||||
|
||||
def informative(timeframe: str, asset: str = '',
|
||||
fmt: Optional[Union[str, Callable[[Any], str]]] = None,
|
||||
*,
|
||||
candle_type: Optional[CandleType] = None,
|
||||
ffill: bool = True) -> Callable[[PopulateIndicators], PopulateIndicators]:
|
||||
"""
|
||||
A decorator for populate_indicators_Nn(self, dataframe, metadata), allowing these functions to
|
||||
@@ -54,12 +58,11 @@ def informative(timeframe: str, asset: str = '',
|
||||
_timeframe = timeframe
|
||||
_fmt = fmt
|
||||
_ffill = ffill
|
||||
_candle_type = CandleType.from_string(candle_type) if candle_type else None
|
||||
|
||||
def decorator(fn: PopulateIndicators):
|
||||
informative_pairs = getattr(fn, '_ft_informative', [])
|
||||
# TODO-lev: Add candle_type to InformativeData
|
||||
informative_pairs.append(InformativeData(_asset, _timeframe, _fmt, _ffill,
|
||||
CandleType.SPOT))
|
||||
informative_pairs.append(InformativeData(_asset, _timeframe, _fmt, _ffill, _candle_type))
|
||||
setattr(fn, '_ft_informative', informative_pairs)
|
||||
return fn
|
||||
return decorator
|
||||
@@ -76,6 +79,8 @@ def _create_and_merge_informative_pair(strategy, dataframe: DataFrame, metadata:
|
||||
asset = inf_data.asset or ''
|
||||
timeframe = inf_data.timeframe
|
||||
fmt = inf_data.fmt
|
||||
candle_type = inf_data.candle_type
|
||||
|
||||
config = strategy.config
|
||||
|
||||
if asset:
|
||||
@@ -102,7 +107,7 @@ def _create_and_merge_informative_pair(strategy, dataframe: DataFrame, metadata:
|
||||
fmt = '{base}_{quote}_' + fmt # Informatives of other pairs
|
||||
|
||||
inf_metadata = {'pair': asset, 'timeframe': timeframe}
|
||||
inf_dataframe = strategy.dp.get_pair_dataframe(asset, timeframe)
|
||||
inf_dataframe = strategy.dp.get_pair_dataframe(asset, timeframe, candle_type)
|
||||
inf_dataframe = populate_indicators(strategy, inf_dataframe, inf_metadata)
|
||||
|
||||
formatter: Any = None
|
||||
|
@@ -147,7 +147,8 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
cls_method = getattr(self.__class__, attr_name)
|
||||
if not callable(cls_method):
|
||||
continue
|
||||
informative_data_list = getattr(cls_method, '_ft_informative', None)
|
||||
informative_data_list = getattr(
|
||||
cls_method, '_ft_informative', None)
|
||||
if not isinstance(informative_data_list, list):
|
||||
# Type check is required because mocker would return a mock object that evaluates to
|
||||
# True, confusing this code.
|
||||
@@ -157,6 +158,8 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
if timeframe_to_minutes(informative_data.timeframe) < strategy_timeframe_minutes:
|
||||
raise OperationalException('Informative timeframe must be equal or higher than '
|
||||
'strategy timeframe!')
|
||||
if not informative_data.candle_type:
|
||||
informative_data.candle_type = config['candle_type_def']
|
||||
self._ft_informative.append((informative_data, cls_method))
|
||||
|
||||
@abstractmethod
|
||||
@@ -465,14 +468,17 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
# Compatibility code for 2 tuple informative pairs
|
||||
informative_pairs = [
|
||||
(p[0], p[1], CandleType.from_string(p[2]) if len(
|
||||
p) > 2 else self.config.get('candle_type_def', CandleType.SPOT))
|
||||
p) > 2 and p[2] != '' else self.config.get('candle_type_def', CandleType.SPOT))
|
||||
for p in informative_pairs]
|
||||
for inf_data, _ in self._ft_informative:
|
||||
# Get default candle type if not provided explicitly.
|
||||
candle_type = (inf_data.candle_type if inf_data.candle_type
|
||||
else self.config.get('candle_type_def', CandleType.SPOT))
|
||||
if inf_data.asset:
|
||||
pair_tf = (
|
||||
_format_pair_name(self.config, inf_data.asset),
|
||||
inf_data.timeframe,
|
||||
inf_data.candle_type
|
||||
candle_type,
|
||||
)
|
||||
informative_pairs.append(pair_tf)
|
||||
else:
|
||||
@@ -480,7 +486,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
||||
raise OperationalException('@informative decorator with unspecified asset '
|
||||
'requires DataProvider instance.')
|
||||
for pair in self.dp.current_whitelist():
|
||||
informative_pairs.append((pair, inf_data.timeframe, inf_data.candle_type))
|
||||
informative_pairs.append((pair, inf_data.timeframe, candle_type))
|
||||
return list(set(informative_pairs))
|
||||
|
||||
def get_strategy_name(self) -> str:
|
||||
|
Reference in New Issue
Block a user