From 4fd00db630e27de686ad79f71096929385e5edfd Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Sep 2021 15:20:59 +0200 Subject: [PATCH] Use "combined" enter_tag column --- freqtrade/enums/signaltype.py | 3 +-- freqtrade/optimize/backtesting.py | 13 +++++-------- freqtrade/strategy/interface.py | 9 ++++----- tests/optimize/__init__.py | 10 ++++------ tests/optimize/test_backtest_detail.py | 4 ++-- tests/strategy/test_interface.py | 6 ++++-- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/freqtrade/enums/signaltype.py b/freqtrade/enums/signaltype.py index 1f2b6d331..fc585318c 100644 --- a/freqtrade/enums/signaltype.py +++ b/freqtrade/enums/signaltype.py @@ -15,8 +15,7 @@ class SignalTagType(Enum): """ Enum for signal columns """ - LONG_TAG = "long_tag" - SHORT_TAG = "short_tag" + ENTER_TAG = "enter_tag" class SignalDirection(Enum): diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 63d307908..4a20d9738 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -46,7 +46,6 @@ ELONG_IDX = 6 # Exit long SHORT_IDX = 7 ESHORT_IDX = 8 # Exit short ENTER_TAG_IDX = 9 -SHORT_TAG_IDX = 10 class Backtesting: @@ -253,7 +252,7 @@ class Backtesting: # Every change to this headers list must evaluate further usages of the resulting tuple # and eventually change the constants for indexes at the top headers = ['date', 'open', 'high', 'low', 'close', 'enter_long', 'exit_long', - 'enter_short', 'exit_short', 'long_tag', 'short_tag'] + 'enter_short', 'exit_short', 'enter_tag'] data: Dict = {} self.progress.init_step(BacktestState.CONVERT, len(processed)) @@ -271,8 +270,7 @@ class Backtesting: if 'exit_long' in pair_data.columns: pair_data.loc[:, 'exit_long'] = 0 pair_data.loc[:, 'exit_short'] = 0 - pair_data.loc[:, 'long_tag'] = None - pair_data.loc[:, 'short_tag'] = None + pair_data.loc[:, 'enter_tag'] = None df_analyzed = self.strategy.advise_exit( self.strategy.advise_entry(pair_data, {'pair': pair}), @@ -287,7 +285,7 @@ class Backtesting: df_analyzed.loc[:, 'enter_short'] = df_analyzed.loc[:, 'enter_short'].shift(1) df_analyzed.loc[:, 'exit_long'] = df_analyzed.loc[:, 'exit_long'].shift(1) df_analyzed.loc[:, 'exit_short'] = df_analyzed.loc[:, 'exit_short'].shift(1) - df_analyzed.loc[:, 'long_tag'] = df_analyzed.loc[:, 'long_tag'].shift(1) + df_analyzed.loc[:, 'enter_tag'] = df_analyzed.loc[:, 'enter_tag'].shift(1) # Update dataprovider cache self.dataprovider._set_cached_df(pair, self.timeframe, df_analyzed) @@ -454,8 +452,7 @@ class Backtesting: if stake_amount and (not min_stake_amount or stake_amount > min_stake_amount): # Enter trade - # TODO-lev: SHORT_TAG ... - has_buy_tag = len(row) >= ENTER_TAG_IDX + 1 + has_enter_tag = len(row) >= ENTER_TAG_IDX + 1 trade = LocalTrade( pair=pair, open_rate=row[OPEN_IDX], @@ -465,7 +462,7 @@ class Backtesting: fee_open=self.fee, fee_close=self.fee, is_open=True, - buy_tag=row[ENTER_TAG_IDX] if has_buy_tag else None, + buy_tag=row[ENTER_TAG_IDX] if has_enter_tag else None, exchange=self._exchange_name, is_short=(direction == 'short'), ) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 4e8881295..e50795078 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -519,8 +519,7 @@ class IStrategy(ABC, HyperStrategyMixin): dataframe[SignalType.EXIT_LONG.value] = 0 dataframe[SignalType.ENTER_SHORT.value] = 0 dataframe[SignalType.EXIT_SHORT.value] = 0 - dataframe[SignalTagType.LONG_TAG.value] = None - dataframe[SignalTagType.SHORT_TAG.value] = None + dataframe[SignalTagType.ENTER_TAG.value] = None # Other Defs in strategy that want to be called every loop here # twitter_sell = self.watch_twitter_feed(dataframe, metadata) @@ -690,10 +689,10 @@ class IStrategy(ABC, HyperStrategyMixin): enter_tag_value: Optional[str] = None if enter_long == 1 and not any([exit_long, enter_short]): enter_signal = SignalDirection.LONG - enter_tag_value = latest.get(SignalTagType.LONG_TAG.value, None) + enter_tag_value = latest.get(SignalTagType.ENTER_TAG.value, None) if enter_short == 1 and not any([exit_short, enter_long]): enter_signal = SignalDirection.SHORT - enter_tag_value = latest.get(SignalTagType.SHORT_TAG.value, None) + enter_tag_value = latest.get(SignalTagType.ENTER_TAG.value, None) timeframe_seconds = timeframe_to_seconds(timeframe) @@ -963,7 +962,7 @@ class IStrategy(ABC, HyperStrategyMixin): else: df = self.populate_buy_trend(dataframe, metadata) if 'enter_long' not in df.columns: - df = df.rename({'buy': 'enter_long', 'buy_tag': 'long_tag'}, axis='columns') + df = df.rename({'buy': 'enter_long', 'buy_tag': 'enter_tag'}, axis='columns') return df diff --git a/tests/optimize/__init__.py b/tests/optimize/__init__.py index 2ba9485fd..10518758c 100644 --- a/tests/optimize/__init__.py +++ b/tests/optimize/__init__.py @@ -18,7 +18,7 @@ class BTrade(NamedTuple): sell_reason: SellType open_tick: int close_tick: int - buy_tag: Optional[str] = None + enter_tag: Optional[str] = None class BTContainer(NamedTuple): @@ -49,15 +49,13 @@ def _build_backtest_dataframe(data): if len(data[0]) == 8: # No short columns data = [d + [0, 0] for d in data] - columns = columns + ['long_tag'] if len(data[0]) == 11 else columns + columns = columns + ['enter_tag'] if len(data[0]) == 11 else columns frame = DataFrame.from_records(data, columns=columns) frame['date'] = frame['date'].apply(_get_frame_time_from_offset) # Ensure floats are in place for column in ['open', 'high', 'low', 'close', 'volume']: frame[column] = frame[column].astype('float64') - if 'long_tag' not in columns: - frame['long_tag'] = None - if 'short_tag' not in columns: - frame['short_tag'] = None + if 'enter_tag' not in columns: + frame['enter_tag'] = None return frame diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index 554122bd5..227d778af 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -532,7 +532,7 @@ tc33 = BTContainer(data=[ sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=1, - buy_tag='buy_signal_01' + enter_tag='buy_signal_01' )] ) @@ -621,6 +621,6 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None: for c, trade in enumerate(data.trades): res = results.iloc[c] assert res.sell_reason == trade.sell_reason.value - assert res.buy_tag == trade.buy_tag + assert res.buy_tag == trade.enter_tag assert res.open_date == _get_frame_time_from_offset(trade.open_tick) assert res.close_date == _get_frame_time_from_offset(trade.close_tick) diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 1ec5eef5a..a9334c616 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -59,7 +59,7 @@ def test_returns_latest_signal(ohlcv_history): assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, False) mocked_history.loc[1, 'exit_long'] = 0 mocked_history.loc[1, 'enter_long'] = 1 - mocked_history.loc[1, 'long_tag'] = 'buy_signal_01' + mocked_history.loc[1, 'enter_tag'] = 'buy_signal_01' assert _STRATEGY.get_entry_signal( 'ETH/BTC', '5m', mocked_history) == (SignalDirection.LONG, 'buy_signal_01') @@ -70,8 +70,10 @@ def test_returns_latest_signal(ohlcv_history): mocked_history.loc[1, 'enter_long'] = 0 mocked_history.loc[1, 'enter_short'] = 1 mocked_history.loc[1, 'exit_short'] = 0 + mocked_history.loc[1, 'enter_tag'] = 'sell_signal_01' + assert _STRATEGY.get_entry_signal( - 'ETH/BTC', '5m', mocked_history) == (SignalDirection.SHORT, None) + 'ETH/BTC', '5m', mocked_history) == (SignalDirection.SHORT, 'sell_signal_01') assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history) == (False, False) assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (True, False)