[SQUASH] Address PR comments.
This commit is contained in:
parent
1fdb656334
commit
f2a1d9d2fc
@ -681,9 +681,47 @@ In some situations it may be confusing to deal with stops relative to current ra
|
|||||||
|
|
||||||
### *@informative()*
|
### *@informative()*
|
||||||
|
|
||||||
|
``` python
|
||||||
|
def informative(timeframe: str, asset: str = '',
|
||||||
|
fmt: Optional[Union[str, Callable[[KwArg(str)], str]]] = None,
|
||||||
|
ffill: bool = True) -> Callable[[PopulateIndicators], PopulateIndicators]:
|
||||||
|
"""
|
||||||
|
A decorator for populate_indicators_Nn(self, dataframe, metadata), allowing these functions to
|
||||||
|
define informative indicators.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
@informative('1h')
|
||||||
|
def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
:param timeframe: Informative timeframe. Must always be equal or higher than strategy timeframe.
|
||||||
|
:param asset: Informative asset, for example BTC, BTC/USDT, ETH/BTC. Do not specify to use
|
||||||
|
current pair.
|
||||||
|
:param fmt: Column format (str) or column formatter (callable(name, asset, timeframe)). When not
|
||||||
|
specified, defaults to:
|
||||||
|
* {base}_{column}_{timeframe} if asset is specified and quote currency does match stake
|
||||||
|
curerncy.
|
||||||
|
* {base}_{quote}_{column}_{timeframe} if asset is specified and quote currency does not match
|
||||||
|
stake curerncy.
|
||||||
|
* {column}_{timeframe} if asset is not specified.
|
||||||
|
Format string supports these format variables:
|
||||||
|
* {asset} - full name of the asset, for example 'BTC/USDT'.
|
||||||
|
* {base} - base currency in lower case, for example 'eth'.
|
||||||
|
* {BASE} - same as {base}, except in upper case.
|
||||||
|
* {quote} - quote currency in lower case, for example 'usdt'.
|
||||||
|
* {QUOTE} - same as {quote}, except in upper case.
|
||||||
|
* {column} - name of dataframe column.
|
||||||
|
* {timeframe} - timeframe of informative dataframe.
|
||||||
|
:param ffill: ffill dataframe after merging informative pair.
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
In most common case it is possible to easily define informative pairs by using a decorator. All decorated `populate_indicators_*` methods run in isolation,
|
In most common case it is possible to easily define informative pairs by using a decorator. All decorated `populate_indicators_*` methods run in isolation,
|
||||||
not having access to data from other informative pairs, in the end all informative dataframes are merged and passed to main `populate_indicators()` method.
|
not having access to data from other informative pairs, in the end all informative dataframes are merged and passed to main `populate_indicators()` method.
|
||||||
When hyperopting, please follow instructions of [optimizing an indicator parameter](hyperopt.md#optimizing-an-indicator-parameter).
|
When hyperopting, use of hyperoptable parameter `.value` attribute is not supported. Please use `.range` attribute. See [optimizing an indicator parameter](hyperopt.md#optimizing-an-indicator-parameter)
|
||||||
|
for more information.
|
||||||
|
|
||||||
??? Example "Fast and easy way to define informative pairs"
|
??? Example "Fast and easy way to define informative pairs"
|
||||||
|
|
||||||
@ -725,17 +763,9 @@ When hyperopting, please follow instructions of [optimizing an indicator paramet
|
|||||||
return dataframe
|
return dataframe
|
||||||
|
|
||||||
# Define BTC/STAKE informative pair. A custom formatter may be specified for formatting
|
# Define BTC/STAKE informative pair. A custom formatter may be specified for formatting
|
||||||
# column names. Format string supports these format variables:
|
# column names. A callable `fmt(**kwargs) -> str` may be specified, to implement custom
|
||||||
# * {asset} - full name of the asset, for example 'BTC/USDT'.
|
# formatting. Available in populate_indicators and other methods as 'rsi_upper'.
|
||||||
# * {base} - base currency in lower case, for example 'eth'.
|
@informative('1h', 'BTC/{stake}', '{column}')
|
||||||
# * {BASE} - same as {base}, except in upper case.
|
|
||||||
# * {quote} - quote currency in lower case, for example 'usdt'.
|
|
||||||
# * {QUOTE} - same as {quote}, except in upper case.
|
|
||||||
# * {column} - name of dataframe column.
|
|
||||||
# * {timeframe} - timeframe of informative dataframe.
|
|
||||||
# A callable `fmt(**kwargs) -> str` may be specified, to implement custom formatting.
|
|
||||||
# Available in populate_indicators and other methods as 'rsi_upper'.
|
|
||||||
@informative('1h', 'BTC/{stake}', '{name}')
|
|
||||||
def populate_indicators_btc_1h_2(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
def populate_indicators_btc_1h_2(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
dataframe['rsi_upper'] = ta.RSI(dataframe, timeperiod=14)
|
dataframe['rsi_upper'] = ta.RSI(dataframe, timeperiod=14)
|
||||||
return dataframe
|
return dataframe
|
||||||
@ -749,8 +779,6 @@ When hyperopting, please follow instructions of [optimizing an indicator paramet
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
See docstring of `@informative()` decorator for more information.
|
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
Do not use `@informative` decorator if you need to use data of one informative pair when generating another informative pair. Instead, define informative pairs
|
Do not use `@informative` decorator if you need to use data of one informative pair when generating another informative pair. Instead, define informative pairs
|
||||||
manually as described [in the DataProvider section](#complete-data-provider-sample).
|
manually as described [in the DataProvider section](#complete-data-provider-sample).
|
||||||
|
@ -6,7 +6,7 @@ import logging
|
|||||||
import warnings
|
import warnings
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
from typing import Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
@ -19,7 +19,8 @@ from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
|||||||
from freqtrade.exchange.exchange import timeframe_to_next_date
|
from freqtrade.exchange.exchange import timeframe_to_next_date
|
||||||
from freqtrade.persistence import PairLocks, Trade
|
from freqtrade.persistence import PairLocks, Trade
|
||||||
from freqtrade.strategy.hyper import HyperStrategyMixin
|
from freqtrade.strategy.hyper import HyperStrategyMixin
|
||||||
from freqtrade.strategy.strategy_helper import (InformativeData, _create_and_merge_informative_pair,
|
from freqtrade.strategy.strategy_helper import (InformativeData, PopulateIndicators,
|
||||||
|
_create_and_merge_informative_pair,
|
||||||
_format_pair_name)
|
_format_pair_name)
|
||||||
from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper
|
from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper
|
||||||
from freqtrade.wallets import Wallets
|
from freqtrade.wallets import Wallets
|
||||||
@ -138,20 +139,23 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
|
|
||||||
# Gather informative pairs from @informative-decorated methods.
|
# Gather informative pairs from @informative-decorated methods.
|
||||||
self._ft_informative: Dict[
|
self._ft_informative: Dict[
|
||||||
Tuple[str, str], Tuple[InformativeData,
|
Tuple[str, str], Tuple[InformativeData, PopulateIndicators]] = {}
|
||||||
Callable[[Any, DataFrame, dict], DataFrame]]] = {}
|
|
||||||
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', [])
|
ft_informative = getattr(cls_method, '_ft_informative', None)
|
||||||
if not isinstance(ft_informative, list):
|
if not isinstance(ft_informative, 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)
|
||||||
for informative_data in ft_informative:
|
for informative_data in ft_informative:
|
||||||
asset = informative_data.asset
|
asset = informative_data.asset
|
||||||
timeframe = informative_data.timeframe
|
timeframe = informative_data.timeframe
|
||||||
|
if timeframe_to_minutes(timeframe) < strategy_timeframe_minutes:
|
||||||
|
raise OperationalException('Informative timeframe must be equal or higher than '
|
||||||
|
'strategy timeframe!')
|
||||||
if asset:
|
if asset:
|
||||||
pair = _format_pair_name(self.config, asset)
|
pair = _format_pair_name(self.config, asset)
|
||||||
if (pair, timeframe) in self._ft_informative:
|
if (pair, timeframe) in self._ft_informative:
|
||||||
@ -165,10 +169,6 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
f'not be defined more than once!')
|
f'not be defined more than once!')
|
||||||
self._ft_informative[(pair, timeframe)] = (informative_data, cls_method)
|
self._ft_informative[(pair, timeframe)] = (informative_data, cls_method)
|
||||||
|
|
||||||
def _format_pair(self, pair: str) -> str:
|
|
||||||
return pair.format(stake_currency=self.config['stake_currency'],
|
|
||||||
stake=self.config['stake_currency']).upper()
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
"""
|
"""
|
||||||
|
@ -8,6 +8,9 @@ from freqtrade.exceptions import OperationalException
|
|||||||
from freqtrade.exchange import timeframe_to_minutes
|
from freqtrade.exchange import timeframe_to_minutes
|
||||||
|
|
||||||
|
|
||||||
|
PopulateIndicators = Callable[[Any, DataFrame, dict], DataFrame]
|
||||||
|
|
||||||
|
|
||||||
class InformativeData(NamedTuple):
|
class InformativeData(NamedTuple):
|
||||||
asset: Optional[str]
|
asset: Optional[str]
|
||||||
timeframe: str
|
timeframe: str
|
||||||
@ -118,8 +121,7 @@ def stoploss_from_absolute(stop_rate: float, current_rate: float) -> float:
|
|||||||
|
|
||||||
def informative(timeframe: str, asset: str = '',
|
def informative(timeframe: str, asset: str = '',
|
||||||
fmt: Optional[Union[str, Callable[[KwArg(str)], str]]] = None,
|
fmt: Optional[Union[str, Callable[[KwArg(str)], str]]] = None,
|
||||||
ffill: bool = True) -> Callable[[Callable[[Any, DataFrame, dict], DataFrame]],
|
ffill: bool = True) -> Callable[[PopulateIndicators], PopulateIndicators]:
|
||||||
Callable[[Any, DataFrame, dict], DataFrame]]:
|
|
||||||
"""
|
"""
|
||||||
A decorator for populate_indicators_Nn(self, dataframe, metadata), allowing these functions to
|
A decorator for populate_indicators_Nn(self, dataframe, metadata), allowing these functions to
|
||||||
define informative indicators.
|
define informative indicators.
|
||||||
@ -131,24 +133,32 @@ def informative(timeframe: str, asset: str = '',
|
|||||||
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
|
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
|
||||||
return dataframe
|
return dataframe
|
||||||
|
|
||||||
:param timeframe: Informative timeframe. Must always be higher than strategy timeframe.
|
:param timeframe: Informative timeframe. Must always be equal or higher than strategy timeframe.
|
||||||
:param asset: Informative asset, for example BTC, BTC/USDT, ETH/BTC. Do not specify to use
|
:param asset: Informative asset, for example BTC, BTC/USDT, ETH/BTC. Do not specify to use
|
||||||
current pair.
|
current pair.
|
||||||
:param fmt: Column format (str) or column formatter (callable(name, asset, timeframe)). When not
|
:param fmt: Column format (str) or column formatter (callable(name, asset, timeframe)). When not
|
||||||
specified, defaults to {asset}_{name}_{timeframe} if asset is specified, or {name}_{timeframe}
|
specified, defaults to:
|
||||||
otherwise.
|
* {base}_{column}_{timeframe} if asset is specified and quote currency does match stake
|
||||||
* {asset}: name of informative asset, provided in lower-case, with / replaced with _. Stake
|
curerncy.
|
||||||
currency is not included in this string.
|
* {base}_{quote}_{column}_{timeframe} if asset is specified and quote currency does not match
|
||||||
* {name}: user-specified dataframe column name.
|
stake curerncy.
|
||||||
* {timeframe}: informative timeframe.
|
* {column}_{timeframe} if asset is not specified.
|
||||||
:param ffill: ffill dataframe after mering informative pair.
|
Format string supports these format variables:
|
||||||
|
* {asset} - full name of the asset, for example 'BTC/USDT'.
|
||||||
|
* {base} - base currency in lower case, for example 'eth'.
|
||||||
|
* {BASE} - same as {base}, except in upper case.
|
||||||
|
* {quote} - quote currency in lower case, for example 'usdt'.
|
||||||
|
* {QUOTE} - same as {quote}, except in upper case.
|
||||||
|
* {column} - name of dataframe column.
|
||||||
|
* {timeframe} - timeframe of informative dataframe.
|
||||||
|
:param ffill: ffill dataframe after merging informative pair.
|
||||||
"""
|
"""
|
||||||
_asset = asset
|
_asset = asset
|
||||||
_timeframe = timeframe
|
_timeframe = timeframe
|
||||||
_fmt = fmt
|
_fmt = fmt
|
||||||
_ffill = ffill
|
_ffill = ffill
|
||||||
|
|
||||||
def decorator(fn: Callable[[Any, DataFrame, dict], DataFrame]):
|
def decorator(fn: PopulateIndicators):
|
||||||
informative_pairs = getattr(fn, '_ft_informative', [])
|
informative_pairs = getattr(fn, '_ft_informative', [])
|
||||||
informative_pairs.append(InformativeData(_asset, _timeframe, _fmt, _ffill))
|
informative_pairs.append(InformativeData(_asset, _timeframe, _fmt, _ffill))
|
||||||
setattr(fn, '_ft_informative', informative_pairs)
|
setattr(fn, '_ft_informative', informative_pairs)
|
||||||
|
Loading…
Reference in New Issue
Block a user