Use "combined" enter_tag column
This commit is contained in:
parent
2a678bdbb4
commit
4fd00db630
@ -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):
|
||||||
|
@ -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'),
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user