Use "combined" enter_tag column

This commit is contained in:
Matthias 2021-09-26 15:20:59 +02:00
parent 2a678bdbb4
commit 4fd00db630
6 changed files with 20 additions and 25 deletions

View File

@ -15,8 +15,7 @@ class SignalTagType(Enum):
""" """
Enum for signal columns Enum for signal columns
""" """
LONG_TAG = "long_tag" ENTER_TAG = "enter_tag"
SHORT_TAG = "short_tag"
class SignalDirection(Enum): class SignalDirection(Enum):

View File

@ -46,7 +46,6 @@ ELONG_IDX = 6 # Exit long
SHORT_IDX = 7 SHORT_IDX = 7
ESHORT_IDX = 8 # Exit short ESHORT_IDX = 8 # Exit short
ENTER_TAG_IDX = 9 ENTER_TAG_IDX = 9
SHORT_TAG_IDX = 10
class Backtesting: class Backtesting:
@ -253,7 +252,7 @@ class Backtesting:
# Every change to this headers list must evaluate further usages of the resulting tuple # Every change to this headers list must evaluate further usages of the resulting tuple
# and eventually change the constants for indexes at the top # and eventually change the constants for indexes at the top
headers = ['date', 'open', 'high', 'low', 'close', 'enter_long', 'exit_long', 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 = {} data: Dict = {}
self.progress.init_step(BacktestState.CONVERT, len(processed)) self.progress.init_step(BacktestState.CONVERT, len(processed))
@ -271,8 +270,7 @@ class Backtesting:
if 'exit_long' in pair_data.columns: if 'exit_long' in pair_data.columns:
pair_data.loc[:, 'exit_long'] = 0 pair_data.loc[:, 'exit_long'] = 0
pair_data.loc[:, 'exit_short'] = 0 pair_data.loc[:, 'exit_short'] = 0
pair_data.loc[:, 'long_tag'] = None pair_data.loc[:, 'enter_tag'] = None
pair_data.loc[:, 'short_tag'] = None
df_analyzed = self.strategy.advise_exit( df_analyzed = self.strategy.advise_exit(
self.strategy.advise_entry(pair_data, {'pair': pair}), 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[:, '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_long'] = df_analyzed.loc[:, 'exit_long'].shift(1)
df_analyzed.loc[:, 'exit_short'] = df_analyzed.loc[:, 'exit_short'].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 # Update dataprovider cache
self.dataprovider._set_cached_df(pair, self.timeframe, df_analyzed) 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): if stake_amount and (not min_stake_amount or stake_amount > min_stake_amount):
# Enter trade # Enter trade
# TODO-lev: SHORT_TAG ... has_enter_tag = len(row) >= ENTER_TAG_IDX + 1
has_buy_tag = len(row) >= ENTER_TAG_IDX + 1
trade = LocalTrade( trade = LocalTrade(
pair=pair, pair=pair,
open_rate=row[OPEN_IDX], open_rate=row[OPEN_IDX],
@ -465,7 +462,7 @@ class Backtesting:
fee_open=self.fee, fee_open=self.fee,
fee_close=self.fee, fee_close=self.fee,
is_open=True, 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, exchange=self._exchange_name,
is_short=(direction == 'short'), is_short=(direction == 'short'),
) )

View File

@ -519,8 +519,7 @@ class IStrategy(ABC, HyperStrategyMixin):
dataframe[SignalType.EXIT_LONG.value] = 0 dataframe[SignalType.EXIT_LONG.value] = 0
dataframe[SignalType.ENTER_SHORT.value] = 0 dataframe[SignalType.ENTER_SHORT.value] = 0
dataframe[SignalType.EXIT_SHORT.value] = 0 dataframe[SignalType.EXIT_SHORT.value] = 0
dataframe[SignalTagType.LONG_TAG.value] = None dataframe[SignalTagType.ENTER_TAG.value] = None
dataframe[SignalTagType.SHORT_TAG.value] = None
# Other Defs in strategy that want to be called every loop here # Other Defs in strategy that want to be called every loop here
# twitter_sell = self.watch_twitter_feed(dataframe, metadata) # twitter_sell = self.watch_twitter_feed(dataframe, metadata)
@ -690,10 +689,10 @@ class IStrategy(ABC, HyperStrategyMixin):
enter_tag_value: Optional[str] = None enter_tag_value: Optional[str] = None
if enter_long == 1 and not any([exit_long, enter_short]): if enter_long == 1 and not any([exit_long, enter_short]):
enter_signal = SignalDirection.LONG 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]): if enter_short == 1 and not any([exit_short, enter_long]):
enter_signal = SignalDirection.SHORT 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) timeframe_seconds = timeframe_to_seconds(timeframe)
@ -963,7 +962,7 @@ class IStrategy(ABC, HyperStrategyMixin):
else: else:
df = self.populate_buy_trend(dataframe, metadata) df = self.populate_buy_trend(dataframe, metadata)
if 'enter_long' not in df.columns: 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 return df

View File

@ -18,7 +18,7 @@ class BTrade(NamedTuple):
sell_reason: SellType sell_reason: SellType
open_tick: int open_tick: int
close_tick: int close_tick: int
buy_tag: Optional[str] = None enter_tag: Optional[str] = None
class BTContainer(NamedTuple): class BTContainer(NamedTuple):
@ -49,15 +49,13 @@ def _build_backtest_dataframe(data):
if len(data[0]) == 8: if len(data[0]) == 8:
# No short columns # No short columns
data = [d + [0, 0] for d in data] 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 = DataFrame.from_records(data, columns=columns)
frame['date'] = frame['date'].apply(_get_frame_time_from_offset) frame['date'] = frame['date'].apply(_get_frame_time_from_offset)
# Ensure floats are in place # Ensure floats are in place
for column in ['open', 'high', 'low', 'close', 'volume']: for column in ['open', 'high', 'low', 'close', 'volume']:
frame[column] = frame[column].astype('float64') frame[column] = frame[column].astype('float64')
if 'long_tag' not in columns: if 'enter_tag' not in columns:
frame['long_tag'] = None frame['enter_tag'] = None
if 'short_tag' not in columns:
frame['short_tag'] = None
return frame return frame

View File

@ -532,7 +532,7 @@ tc33 = BTContainer(data=[
sell_reason=SellType.TRAILING_STOP_LOSS, sell_reason=SellType.TRAILING_STOP_LOSS,
open_tick=1, open_tick=1,
close_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): for c, trade in enumerate(data.trades):
res = results.iloc[c] res = results.iloc[c]
assert res.sell_reason == trade.sell_reason.value 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.open_date == _get_frame_time_from_offset(trade.open_tick)
assert res.close_date == _get_frame_time_from_offset(trade.close_tick) assert res.close_date == _get_frame_time_from_offset(trade.close_tick)

View File

@ -59,7 +59,7 @@ def test_returns_latest_signal(ohlcv_history):
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, False) assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (False, False)
mocked_history.loc[1, 'exit_long'] = 0 mocked_history.loc[1, 'exit_long'] = 0
mocked_history.loc[1, 'enter_long'] = 1 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( assert _STRATEGY.get_entry_signal(
'ETH/BTC', '5m', mocked_history) == (SignalDirection.LONG, 'buy_signal_01') '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_long'] = 0
mocked_history.loc[1, 'enter_short'] = 1 mocked_history.loc[1, 'enter_short'] = 1
mocked_history.loc[1, 'exit_short'] = 0 mocked_history.loc[1, 'exit_short'] = 0
mocked_history.loc[1, 'enter_tag'] = 'sell_signal_01'
assert _STRATEGY.get_entry_signal( 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) == (False, False)
assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (True, False) assert _STRATEGY.get_exit_signal('ETH/BTC', '5m', mocked_history, True) == (True, False)