Merge pull request #9369 from freqtrade/feat/informative_base

informative assets -> {base}
This commit is contained in:
Matthias
2023-11-02 06:36:55 +01:00
committed by GitHub
5 changed files with 59 additions and 25 deletions
+5 -4
View File
@@ -486,17 +486,18 @@ for more information.
:param timeframe: Informative timeframe. Must always be equal or 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. Also supports limited pair format strings (see below)
: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: specified, defaults to:
* {base}_{quote}_{column}_{timeframe} if asset is specified. * {base}_{quote}_{column}_{timeframe} if asset is specified.
* {column}_{timeframe} if asset is not specified. * {column}_{timeframe} if asset is not specified.
Format string supports these format variables: Pair format supports these format variables:
* {asset} - full name of the asset, for example 'BTC/USDT'.
* {base} - base currency in lower case, for example 'eth'. * {base} - base currency in lower case, for example 'eth'.
* {BASE} - same as {base}, except in upper case. * {BASE} - same as {base}, except in upper case.
* {quote} - quote currency in lower case, for example 'usdt'. * {quote} - quote currency in lower case, for example 'usdt'.
* {QUOTE} - same as {quote}, except in upper case. * {QUOTE} - same as {quote}, except in upper case.
Format string additionally supports this variables.
* {asset} - full name of the asset, for example 'BTC/USDT'.
* {column} - name of dataframe column. * {column} - name of dataframe column.
* {timeframe} - timeframe of informative dataframe. * {timeframe} - timeframe of informative dataframe.
:param ffill: ffill dataframe after merging informative pair. :param ffill: ffill dataframe after merging informative pair.
+27 -14
View File
@@ -1,5 +1,5 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any, Callable, Optional, Union from typing import Any, Callable, Dict, Optional, Union
from pandas import DataFrame from pandas import DataFrame
@@ -38,17 +38,18 @@ def informative(timeframe: str, asset: str = '',
:param timeframe: Informative timeframe. Must always be equal or 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. Also supports limited pair format strings (see below)
: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: specified, defaults to:
* {base}_{quote}_{column}_{timeframe} if asset is specified. * {base}_{quote}_{column}_{timeframe} if asset is specified.
* {column}_{timeframe} if asset is not specified. * {column}_{timeframe} if asset is not specified.
Format string supports these format variables: Pair format supports these format variables:
* {asset} - full name of the asset, for example 'BTC/USDT'.
* {base} - base currency in lower case, for example 'eth'. * {base} - base currency in lower case, for example 'eth'.
* {BASE} - same as {base}, except in upper case. * {BASE} - same as {base}, except in upper case.
* {quote} - quote currency in lower case, for example 'usdt'. * {quote} - quote currency in lower case, for example 'usdt'.
* {QUOTE} - same as {quote}, except in upper case. * {QUOTE} - same as {quote}, except in upper case.
Format string additionally supports this variables.
* {asset} - full name of the asset, for example 'BTC/USDT'.
* {column} - name of dataframe column. * {column} - name of dataframe column.
* {timeframe} - timeframe of informative dataframe. * {timeframe} - timeframe of informative dataframe.
:param ffill: ffill dataframe after merging informative pair. :param ffill: ffill dataframe after merging informative pair.
@@ -68,9 +69,25 @@ def informative(timeframe: str, asset: str = '',
return decorator return decorator
def _format_pair_name(config, pair: str) -> str: def __get_pair_formats(market: Optional[Dict[str, Any]]) -> Dict[str, str]:
return pair.format(stake_currency=config['stake_currency'], if not market:
stake=config['stake_currency']).upper() return {}
base = market['base']
quote = market['quote']
return {
'base': base.lower(),
'BASE': base.upper(),
'quote': quote.lower(),
'QUOTE': quote.upper(),
}
def _format_pair_name(config, pair: str, market: Optional[Dict[str, Any]] = None) -> str:
return pair.format(
stake_currency=config['stake_currency'],
stake=config['stake_currency'],
**__get_pair_formats(market),
).upper()
def _create_and_merge_informative_pair(strategy, dataframe: DataFrame, metadata: dict, def _create_and_merge_informative_pair(strategy, dataframe: DataFrame, metadata: dict,
@@ -85,7 +102,8 @@ def _create_and_merge_informative_pair(strategy, dataframe: DataFrame, metadata:
if asset: if asset:
# Insert stake currency if needed. # Insert stake currency if needed.
asset = _format_pair_name(config, asset) market1 = strategy.dp.market(metadata['pair'])
asset = _format_pair_name(config, asset, market1)
else: else:
# Not specifying an asset will define informative dataframe for current pair. # Not specifying an asset will define informative dataframe for current pair.
asset = metadata['pair'] asset = metadata['pair']
@@ -93,8 +111,6 @@ def _create_and_merge_informative_pair(strategy, dataframe: DataFrame, metadata:
market = strategy.dp.market(asset) market = strategy.dp.market(asset)
if market is None: if market is None:
raise OperationalException(f'Market {asset} is not available.') raise OperationalException(f'Market {asset} is not available.')
base = market['base']
quote = market['quote']
# Default format. This optimizes for the common case: informative pairs using same stake # Default format. This optimizes for the common case: informative pairs using same stake
# currency. When quote currency matches stake currency, column name will omit base currency. # currency. When quote currency matches stake currency, column name will omit base currency.
@@ -117,10 +133,7 @@ def _create_and_merge_informative_pair(strategy, dataframe: DataFrame, metadata:
formatter = fmt.format # A default string formatter. formatter = fmt.format # A default string formatter.
fmt_args = { fmt_args = {
'BASE': base.upper(), **__get_pair_formats(market),
'QUOTE': quote.upper(),
'base': base.lower(),
'quote': quote.lower(),
'asset': asset, 'asset': asset,
'timeframe': timeframe, 'timeframe': timeframe,
} }
+17 -6
View File
@@ -756,12 +756,23 @@ class IStrategy(ABC, HyperStrategyMixin):
candle_type = (inf_data.candle_type if inf_data.candle_type candle_type = (inf_data.candle_type if inf_data.candle_type
else self.config.get('candle_type_def', CandleType.SPOT)) else self.config.get('candle_type_def', CandleType.SPOT))
if inf_data.asset: if inf_data.asset:
pair_tf = ( if any(s in inf_data.asset for s in ("{BASE}", "{base}")):
_format_pair_name(self.config, inf_data.asset), for pair in self.dp.current_whitelist():
inf_data.timeframe,
candle_type, pair_tf = (
) _format_pair_name(self.config, inf_data.asset, self.dp.market(pair)),
informative_pairs.append(pair_tf) inf_data.timeframe,
candle_type,
)
informative_pairs.append(pair_tf)
else:
pair_tf = (
_format_pair_name(self.config, inf_data.asset),
inf_data.timeframe,
candle_type,
)
informative_pairs.append(pair_tf)
else: else:
for pair in self.dp.current_whitelist(): for pair in self.dp.current_whitelist():
informative_pairs.append((pair, inf_data.timeframe, candle_type)) informative_pairs.append((pair, inf_data.timeframe, candle_type))
@@ -47,6 +47,11 @@ class InformativeDecoratorTest(IStrategy):
dataframe['rsi'] = 14 dataframe['rsi'] = 14
return dataframe return dataframe
@informative('1h', '{base}/BTC')
def populate_indicators_base_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = 14
return dataframe
# Quote currency different from stake currency test. # Quote currency different from stake currency test.
@informative('1h', 'ETH/BTC', candle_type='spot') @informative('1h', 'ETH/BTC', candle_type='spot')
def populate_indicators_eth_btc_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def populate_indicators_eth_btc_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
+5 -1
View File
@@ -277,9 +277,11 @@ def test_informative_decorator(mocker, default_conf_usdt, trading_mode):
('XRP/USDT', '5m', candle_def): test_data_5m, ('XRP/USDT', '5m', candle_def): test_data_5m,
('XRP/USDT', '30m', candle_def): test_data_30m, ('XRP/USDT', '30m', candle_def): test_data_30m,
('XRP/USDT', '1h', candle_def): test_data_1h, ('XRP/USDT', '1h', candle_def): test_data_1h,
('XRP/BTC', '1h', candle_def): test_data_1h, # from {base}/BTC
('LTC/USDT', '5m', candle_def): test_data_5m, ('LTC/USDT', '5m', candle_def): test_data_5m,
('LTC/USDT', '30m', candle_def): test_data_30m, ('LTC/USDT', '30m', candle_def): test_data_30m,
('LTC/USDT', '1h', candle_def): test_data_1h, ('LTC/USDT', '1h', candle_def): test_data_1h,
('LTC/BTC', '1h', candle_def): test_data_1h, # from {base}/BTC
('NEO/USDT', '30m', candle_def): test_data_30m, ('NEO/USDT', '30m', candle_def): test_data_30m,
('NEO/USDT', '5m', CandleType.SPOT): test_data_5m, # Explicit request with '' as candletype ('NEO/USDT', '5m', CandleType.SPOT): test_data_5m, # Explicit request with '' as candletype
('NEO/USDT', '15m', candle_def): test_data_5m, # Explicit request with '' as candletype ('NEO/USDT', '15m', candle_def): test_data_5m, # Explicit request with '' as candletype
@@ -296,10 +298,12 @@ def test_informative_decorator(mocker, default_conf_usdt, trading_mode):
'XRP/USDT', 'LTC/USDT', 'NEO/USDT' 'XRP/USDT', 'LTC/USDT', 'NEO/USDT'
]) ])
assert len(strategy._ft_informative) == 6 # Equal to number of decorators used assert len(strategy._ft_informative) == 7 # Equal to number of decorators used
informative_pairs = [ informative_pairs = [
('XRP/USDT', '1h', candle_def), ('XRP/USDT', '1h', candle_def),
('XRP/BTC', '1h', candle_def),
('LTC/USDT', '1h', candle_def), ('LTC/USDT', '1h', candle_def),
('LTC/BTC', '1h', candle_def),
('XRP/USDT', '30m', candle_def), ('XRP/USDT', '30m', candle_def),
('LTC/USDT', '30m', candle_def), ('LTC/USDT', '30m', candle_def),
('NEO/USDT', '1h', candle_def), ('NEO/USDT', '1h', candle_def),