Merge pull request #5936 from rokups/rk/decorator-fix
Use market data to get base and quote currencies in @informative() decorator
This commit is contained in:
		| @@ -67,7 +67,7 @@ class Backtesting: | |||||||
|         self.all_results: Dict[str, Dict] = {} |         self.all_results: Dict[str, Dict] = {} | ||||||
|  |  | ||||||
|         self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config) |         self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config) | ||||||
|         self.dataprovider = DataProvider(self.config, None) |         self.dataprovider = DataProvider(self.config, self.exchange) | ||||||
|  |  | ||||||
|         if self.config.get('strategy_list', None): |         if self.config.get('strategy_list', None): | ||||||
|             for strat in list(self.config['strategy_list']): |             for strat in list(self.config['strategy_list']): | ||||||
|   | |||||||
| @@ -80,12 +80,11 @@ def _create_and_merge_informative_pair(strategy, dataframe: DataFrame, metadata: | |||||||
|         # 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'] | ||||||
|  |  | ||||||
|     if '/' in asset: |     market = strategy.dp.market(asset) | ||||||
|         base, quote = asset.split('/') |     if market is None: | ||||||
|     else: |         raise OperationalException(f'Market {asset} is not available.') | ||||||
|         # When futures are supported this may need reevaluation. |     base = market['base'] | ||||||
|         # base, quote = asset, '' |     quote = market['quote'] | ||||||
|         raise OperationalException('Not implemented.') |  | ||||||
|  |  | ||||||
|     # 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. | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ class InformativeDecoratorTest(IStrategy): | |||||||
|     startup_candle_count: int = 20 |     startup_candle_count: int = 20 | ||||||
|  |  | ||||||
|     def informative_pairs(self): |     def informative_pairs(self): | ||||||
|         return [('BTC/USDT', '5m')] |         return [('NEO/USDT', '5m')] | ||||||
|  |  | ||||||
|     def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: |     def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: | ||||||
|         dataframe['buy'] = 0 |         dataframe['buy'] = 0 | ||||||
| @@ -38,8 +38,8 @@ class InformativeDecoratorTest(IStrategy): | |||||||
|         return dataframe |         return dataframe | ||||||
|  |  | ||||||
|     # Simple informative test. |     # Simple informative test. | ||||||
|     @informative('1h', 'BTC/{stake}') |     @informative('1h', 'NEO/{stake}') | ||||||
|     def populate_indicators_btc_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame: |     def populate_indicators_neo_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame: | ||||||
|         dataframe['rsi'] = 14 |         dataframe['rsi'] = 14 | ||||||
|         return dataframe |         return dataframe | ||||||
|  |  | ||||||
| @@ -50,7 +50,7 @@ class InformativeDecoratorTest(IStrategy): | |||||||
|         return dataframe |         return dataframe | ||||||
|  |  | ||||||
|     # Formatting test. |     # Formatting test. | ||||||
|     @informative('30m', 'BTC/{stake}', '{column}_{BASE}_{QUOTE}_{base}_{quote}_{asset}_{timeframe}') |     @informative('30m', 'NEO/{stake}', '{column}_{BASE}_{QUOTE}_{base}_{quote}_{asset}_{timeframe}') | ||||||
|     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'] = 14 |         dataframe['rsi'] = 14 | ||||||
|         return dataframe |         return dataframe | ||||||
| @@ -68,7 +68,7 @@ class InformativeDecoratorTest(IStrategy): | |||||||
|         dataframe['rsi_less'] = dataframe['rsi'] < dataframe['rsi_1h'] |         dataframe['rsi_less'] = dataframe['rsi'] < dataframe['rsi_1h'] | ||||||
|  |  | ||||||
|         # Mixing manual informative pairs with decorators. |         # Mixing manual informative pairs with decorators. | ||||||
|         informative = self.dp.get_pair_dataframe('BTC/USDT', '5m') |         informative = self.dp.get_pair_dataframe('NEO/USDT', '5m') | ||||||
|         informative['rsi'] = 14 |         informative['rsi'] = 14 | ||||||
|         dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '5m', ffill=True) |         dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '5m', ffill=True) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import pytest | |||||||
| from freqtrade.data.dataprovider import DataProvider | from freqtrade.data.dataprovider import DataProvider | ||||||
| from freqtrade.strategy import (merge_informative_pair, stoploss_from_absolute, stoploss_from_open, | from freqtrade.strategy import (merge_informative_pair, stoploss_from_absolute, stoploss_from_open, | ||||||
|                                 timeframe_to_minutes) |                                 timeframe_to_minutes) | ||||||
|  | from tests.conftest import get_patched_exchange | ||||||
|  |  | ||||||
|  |  | ||||||
| def generate_test_data(timeframe: str, size: int, start: str = '2020-07-05'): | def generate_test_data(timeframe: str, size: int, start: str = '2020-07-05'): | ||||||
| @@ -155,9 +156,9 @@ def test_informative_decorator(mocker, default_conf): | |||||||
|         ('LTC/USDT', '5m'): test_data_5m, |         ('LTC/USDT', '5m'): test_data_5m, | ||||||
|         ('LTC/USDT', '30m'): test_data_30m, |         ('LTC/USDT', '30m'): test_data_30m, | ||||||
|         ('LTC/USDT', '1h'): test_data_1h, |         ('LTC/USDT', '1h'): test_data_1h, | ||||||
|         ('BTC/USDT', '30m'): test_data_30m, |         ('NEO/USDT', '30m'): test_data_30m, | ||||||
|         ('BTC/USDT', '5m'): test_data_5m, |         ('NEO/USDT', '5m'): test_data_5m, | ||||||
|         ('BTC/USDT', '1h'): test_data_1h, |         ('NEO/USDT', '1h'): test_data_1h, | ||||||
|         ('ETH/USDT', '1h'): test_data_1h, |         ('ETH/USDT', '1h'): test_data_1h, | ||||||
|         ('ETH/USDT', '30m'): test_data_30m, |         ('ETH/USDT', '30m'): test_data_30m, | ||||||
|         ('ETH/BTC', '1h'): test_data_1h, |         ('ETH/BTC', '1h'): test_data_1h, | ||||||
| @@ -165,15 +166,16 @@ def test_informative_decorator(mocker, default_conf): | |||||||
|     from .strats.informative_decorator_strategy import InformativeDecoratorTest |     from .strats.informative_decorator_strategy import InformativeDecoratorTest | ||||||
|     default_conf['stake_currency'] = 'USDT' |     default_conf['stake_currency'] = 'USDT' | ||||||
|     strategy = InformativeDecoratorTest(config=default_conf) |     strategy = InformativeDecoratorTest(config=default_conf) | ||||||
|     strategy.dp = DataProvider({}, None, None) |     exchange = get_patched_exchange(mocker, default_conf) | ||||||
|  |     strategy.dp = DataProvider({}, exchange, None) | ||||||
|     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', 'NEO/USDT' | ||||||
|     ]) |     ]) | ||||||
|  |  | ||||||
|     assert len(strategy._ft_informative) == 6   # Equal to number of decorators used |     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'), ('NEO/USDT', '1h'), ('NEO/USDT', '30m'), | ||||||
|                          ('BTC/USDT', '5m'), ('ETH/BTC', '1h'), ('ETH/USDT', '30m')] |                          ('NEO/USDT', '5m'), ('ETH/BTC', '1h'), ('ETH/USDT', '30m')] | ||||||
|     for inf_pair in informative_pairs: |     for inf_pair in informative_pairs: | ||||||
|         assert inf_pair in strategy.gather_informative_pairs() |         assert inf_pair in strategy.gather_informative_pairs() | ||||||
|  |  | ||||||
| @@ -186,8 +188,8 @@ def test_informative_decorator(mocker, default_conf): | |||||||
|         {p: data[(p, strategy.timeframe)] for p in ('XRP/USDT', 'LTC/USDT')}) |         {p: data[(p, strategy.timeframe)] for p in ('XRP/USDT', 'LTC/USDT')}) | ||||||
|     expected_columns = [ |     expected_columns = [ | ||||||
|         'rsi_1h', 'rsi_30m',                    # Stacked informative decorators |         'rsi_1h', 'rsi_30m',                    # Stacked informative decorators | ||||||
|         'btc_usdt_rsi_1h',                      # BTC 1h informative |         'neo_usdt_rsi_1h',                      # NEO 1h informative | ||||||
|         'rsi_BTC_USDT_btc_usdt_BTC/USDT_30m',   # Column formatting |         'rsi_NEO_USDT_neo_usdt_NEO/USDT_30m',   # Column formatting | ||||||
|         'rsi_from_callable',                    # Custom column formatter |         'rsi_from_callable',                    # Custom column formatter | ||||||
|         'eth_btc_rsi_1h',                       # Quote currency not matching stake currency |         'eth_btc_rsi_1h',                       # Quote currency not matching stake currency | ||||||
|         'rsi', 'rsi_less',                      # Non-informative columns |         'rsi', 'rsi_less',                      # Non-informative columns | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user