condensed strategy methods down to 2
This commit is contained in:
@@ -130,6 +130,19 @@ class DefaultStrategy(IStrategy):
|
||||
),
|
||||
'buy'] = 1
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['rsi'] > 65) &
|
||||
(dataframe['fastd'] > 65) &
|
||||
(dataframe['adx'] < 70) &
|
||||
(dataframe['plus_di'] < 0.5) # TODO-lev: What to do here
|
||||
) |
|
||||
(
|
||||
(dataframe['adx'] < 35) &
|
||||
(dataframe['plus_di'] < 0.5) # TODO-lev: What to do here
|
||||
),
|
||||
'enter_short'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
@@ -153,37 +166,7 @@ class DefaultStrategy(IStrategy):
|
||||
(dataframe['minus_di'] > 0.5)
|
||||
),
|
||||
'sell'] = 1
|
||||
return dataframe
|
||||
|
||||
def populate_short_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the short signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:param metadata: Additional information, like the currently traded pair
|
||||
:return: DataFrame with short column
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['rsi'] > 65) &
|
||||
(dataframe['fastd'] > 65) &
|
||||
(dataframe['adx'] < 70) &
|
||||
(dataframe['plus_di'] < 0.5) # TODO-lev: What to do here
|
||||
) |
|
||||
(
|
||||
(dataframe['adx'] < 35) &
|
||||
(dataframe['plus_di'] < 0.5) # TODO-lev: What to do here
|
||||
),
|
||||
'short'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_short_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the exit_short signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:param metadata: Additional information, like the currently traded pair
|
||||
:return: DataFrame with exit_short column
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(
|
||||
@@ -198,4 +181,5 @@ class DefaultStrategy(IStrategy):
|
||||
(dataframe['minus_di'] < 0.5) # TODO-lev: what to do here
|
||||
),
|
||||
'exit_short'] = 1
|
||||
|
||||
return dataframe
|
||||
|
@@ -60,7 +60,7 @@ class HyperoptableStrategy(IStrategy):
|
||||
'sell_minusdi': 0.4
|
||||
}
|
||||
|
||||
short_params = {
|
||||
enter_short_params = {
|
||||
'short_rsi': 65,
|
||||
}
|
||||
|
||||
@@ -87,8 +87,8 @@ class HyperoptableStrategy(IStrategy):
|
||||
})
|
||||
return prot
|
||||
|
||||
short_rsi = IntParameter([50, 100], default=70, space='sell')
|
||||
short_plusdi = RealParameter(low=0, high=1, default=0.5, space='sell')
|
||||
enter_short_rsi = IntParameter([50, 100], default=70, space='sell')
|
||||
enter_short_plusdi = RealParameter(low=0, high=1, default=0.5, space='sell')
|
||||
exit_short_rsi = IntParameter(low=0, high=50, default=30, space='buy')
|
||||
exit_short_minusdi = DecimalParameter(low=0, high=1, default=0.4999, decimals=3, space='buy',
|
||||
load=False)
|
||||
@@ -175,6 +175,19 @@ class HyperoptableStrategy(IStrategy):
|
||||
),
|
||||
'buy'] = 1
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['rsi'] > self.enter_short_rsi.value) &
|
||||
(dataframe['fastd'] > 65) &
|
||||
(dataframe['adx'] < 70) &
|
||||
(dataframe['plus_di'] < self.enter_short_plusdi.value)
|
||||
) |
|
||||
(
|
||||
(dataframe['adx'] < 35) &
|
||||
(dataframe['plus_di'] < self.enter_short_plusdi.value)
|
||||
),
|
||||
'enter_short'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
@@ -198,37 +211,7 @@ class HyperoptableStrategy(IStrategy):
|
||||
(dataframe['minus_di'] > self.sell_minusdi.value)
|
||||
),
|
||||
'sell'] = 1
|
||||
return dataframe
|
||||
|
||||
def populate_short_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the short signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:param metadata: Additional information, like the currently traded pair
|
||||
:return: DataFrame with short column
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['rsi'] > self.short_rsi.value) &
|
||||
(dataframe['fastd'] > 65) &
|
||||
(dataframe['adx'] < 70) &
|
||||
(dataframe['plus_di'] < self.short_plusdi.value)
|
||||
) |
|
||||
(
|
||||
(dataframe['adx'] < 35) &
|
||||
(dataframe['plus_di'] < self.short_plusdi.value)
|
||||
),
|
||||
'short'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_short_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the exit_short signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:param metadata: Additional information, like the currently traded pair
|
||||
:return: DataFrame with exit_short column
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(
|
||||
@@ -243,4 +226,5 @@ class HyperoptableStrategy(IStrategy):
|
||||
(dataframe['minus_di'] < self.exit_short_minusdi.value)
|
||||
),
|
||||
'exit_short'] = 1
|
||||
|
||||
return dataframe
|
||||
|
@@ -84,35 +84,5 @@ class TestStrategyLegacy(IStrategy):
|
||||
(dataframe['volume'] > 0)
|
||||
),
|
||||
'sell'] = 1
|
||||
return dataframe
|
||||
|
||||
def populate_short_trend(self, dataframe: DataFrame) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the buy signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:return: DataFrame with buy column
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['adx'] > 30) &
|
||||
(dataframe['tema'] > dataframe['tema'].shift(1)) &
|
||||
(dataframe['volume'] > 0)
|
||||
),
|
||||
'buy'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_short_trend(self, dataframe: DataFrame) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the sell signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:return: DataFrame with buy column
|
||||
"""
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['adx'] > 70) &
|
||||
(dataframe['tema'] < dataframe['tema'].shift(1)) &
|
||||
(dataframe['volume'] > 0)
|
||||
),
|
||||
'sell'] = 1
|
||||
return dataframe
|
||||
|
@@ -14,8 +14,6 @@ def test_default_strategy_structure():
|
||||
assert hasattr(DefaultStrategy, 'populate_indicators')
|
||||
assert hasattr(DefaultStrategy, 'populate_buy_trend')
|
||||
assert hasattr(DefaultStrategy, 'populate_sell_trend')
|
||||
assert hasattr(DefaultStrategy, 'populate_short_trend')
|
||||
assert hasattr(DefaultStrategy, 'populate_exit_short_trend')
|
||||
|
||||
|
||||
def test_default_strategy(result, fee):
|
||||
@@ -29,10 +27,6 @@ def test_default_strategy(result, fee):
|
||||
assert type(indicators) is DataFrame
|
||||
assert type(strategy.populate_buy_trend(indicators, metadata)) is DataFrame
|
||||
assert type(strategy.populate_sell_trend(indicators, metadata)) is DataFrame
|
||||
# TODO-lev: I think these two should be commented out in the strategy by default
|
||||
# TODO-lev: so they can be tested, but the tests can't really remain
|
||||
assert type(strategy.populate_short_trend(indicators, metadata)) is DataFrame
|
||||
assert type(strategy.populate_exit_short_trend(indicators, metadata)) is DataFrame
|
||||
|
||||
trade = Trade(
|
||||
open_rate=19_000,
|
||||
@@ -43,28 +37,11 @@ def test_default_strategy(result, fee):
|
||||
|
||||
assert strategy.confirm_trade_entry(pair='ETH/BTC', order_type='limit', amount=0.1,
|
||||
rate=20000, time_in_force='gtc',
|
||||
is_short=False, current_time=datetime.utcnow()) is True
|
||||
|
||||
current_time=datetime.utcnow()) is True
|
||||
assert strategy.confirm_trade_exit(pair='ETH/BTC', trade=trade, order_type='limit', amount=0.1,
|
||||
rate=20000, time_in_force='gtc', sell_reason='roi',
|
||||
is_short=False, current_time=datetime.utcnow()) is True
|
||||
current_time=datetime.utcnow()) is True
|
||||
|
||||
# TODO-lev: Test for shorts?
|
||||
assert strategy.custom_stoploss(pair='ETH/BTC', trade=trade, current_time=datetime.now(),
|
||||
current_rate=20_000, current_profit=0.05) == strategy.stoploss
|
||||
|
||||
short_trade = Trade(
|
||||
open_rate=21_000,
|
||||
amount=0.1,
|
||||
pair='ETH/BTC',
|
||||
fee_open=fee.return_value
|
||||
)
|
||||
|
||||
assert strategy.confirm_trade_entry(pair='ETH/BTC', order_type='limit', amount=0.1,
|
||||
rate=20000, time_in_force='gtc',
|
||||
is_short=True, current_time=datetime.utcnow()) is True
|
||||
|
||||
assert strategy.confirm_trade_exit(pair='ETH/BTC', trade=short_trade, order_type='limit',
|
||||
amount=0.1, rate=20000, time_in_force='gtc',
|
||||
sell_reason='roi', is_short=True,
|
||||
current_time=datetime.utcnow()) is True
|
||||
|
@@ -482,20 +482,20 @@ def test_custom_sell(default_conf, fee, caplog) -> None:
|
||||
def test_analyze_ticker_default(ohlcv_history, mocker, caplog) -> None:
|
||||
caplog.set_level(logging.DEBUG)
|
||||
ind_mock = MagicMock(side_effect=lambda x, meta: x)
|
||||
enter_mock = MagicMock(side_effect=lambda x, meta, is_short: x)
|
||||
exit_mock = MagicMock(side_effect=lambda x, meta, is_short: x)
|
||||
buy_mock = MagicMock(side_effect=lambda x, meta: x)
|
||||
sell_mock = MagicMock(side_effect=lambda x, meta: x)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.strategy.interface.IStrategy',
|
||||
advise_indicators=ind_mock,
|
||||
advise_enter=enter_mock,
|
||||
advise_exit=exit_mock,
|
||||
advise_buy=buy_mock,
|
||||
advise_sell=sell_mock,
|
||||
|
||||
)
|
||||
strategy = DefaultStrategy({})
|
||||
strategy.analyze_ticker(ohlcv_history, {'pair': 'ETH/BTC'})
|
||||
assert ind_mock.call_count == 1
|
||||
assert enter_mock.call_count == 2
|
||||
assert enter_mock.call_count == 2
|
||||
assert buy_mock.call_count == 1
|
||||
assert buy_mock.call_count == 1
|
||||
|
||||
assert log_has('TA Analysis Launched', caplog)
|
||||
assert not log_has('Skipping TA Analysis for already analyzed candle', caplog)
|
||||
@@ -504,8 +504,8 @@ def test_analyze_ticker_default(ohlcv_history, mocker, caplog) -> None:
|
||||
strategy.analyze_ticker(ohlcv_history, {'pair': 'ETH/BTC'})
|
||||
# No analysis happens as process_only_new_candles is true
|
||||
assert ind_mock.call_count == 2
|
||||
assert enter_mock.call_count == 4
|
||||
assert enter_mock.call_count == 4
|
||||
assert buy_mock.call_count == 2
|
||||
assert buy_mock.call_count == 2
|
||||
assert log_has('TA Analysis Launched', caplog)
|
||||
assert not log_has('Skipping TA Analysis for already analyzed candle', caplog)
|
||||
|
||||
@@ -513,13 +513,13 @@ def test_analyze_ticker_default(ohlcv_history, mocker, caplog) -> None:
|
||||
def test__analyze_ticker_internal_skip_analyze(ohlcv_history, mocker, caplog) -> None:
|
||||
caplog.set_level(logging.DEBUG)
|
||||
ind_mock = MagicMock(side_effect=lambda x, meta: x)
|
||||
enter_mock = MagicMock(side_effect=lambda x, meta, is_short: x)
|
||||
exit_mock = MagicMock(side_effect=lambda x, meta, is_short: x)
|
||||
buy_mock = MagicMock(side_effect=lambda x, meta: x)
|
||||
sell_mock = MagicMock(side_effect=lambda x, meta: x)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.strategy.interface.IStrategy',
|
||||
advise_indicators=ind_mock,
|
||||
advise_enter=enter_mock,
|
||||
advise_exit=exit_mock,
|
||||
advise_buy=buy_mock,
|
||||
advise_sell=sell_mock,
|
||||
|
||||
)
|
||||
strategy = DefaultStrategy({})
|
||||
@@ -532,8 +532,8 @@ def test__analyze_ticker_internal_skip_analyze(ohlcv_history, mocker, caplog) ->
|
||||
assert 'close' in ret.columns
|
||||
assert isinstance(ret, DataFrame)
|
||||
assert ind_mock.call_count == 1
|
||||
assert enter_mock.call_count == 2 # Once for buy, once for short
|
||||
assert enter_mock.call_count == 2
|
||||
assert buy_mock.call_count == 1
|
||||
assert buy_mock.call_count == 1
|
||||
assert log_has('TA Analysis Launched', caplog)
|
||||
assert not log_has('Skipping TA Analysis for already analyzed candle', caplog)
|
||||
caplog.clear()
|
||||
@@ -541,8 +541,8 @@ def test__analyze_ticker_internal_skip_analyze(ohlcv_history, mocker, caplog) ->
|
||||
ret = strategy._analyze_ticker_internal(ohlcv_history, {'pair': 'ETH/BTC'})
|
||||
# No analysis happens as process_only_new_candles is true
|
||||
assert ind_mock.call_count == 1
|
||||
assert enter_mock.call_count == 2
|
||||
assert enter_mock.call_count == 2
|
||||
assert buy_mock.call_count == 1
|
||||
assert buy_mock.call_count == 1
|
||||
# only skipped analyze adds buy and sell columns, otherwise it's all mocked
|
||||
assert 'buy' in ret.columns
|
||||
assert 'sell' in ret.columns
|
||||
|
@@ -117,16 +117,12 @@ def test_strategy(result, default_conf):
|
||||
df_indicators = strategy.advise_indicators(result, metadata=metadata)
|
||||
assert 'adx' in df_indicators
|
||||
|
||||
dataframe = strategy.advise_enter(df_indicators, metadata=metadata, is_short=False)
|
||||
dataframe = strategy.advise_buy(df_indicators, metadata=metadata)
|
||||
assert 'buy' in dataframe.columns
|
||||
assert 'enter_short' in dataframe.columns
|
||||
|
||||
dataframe = strategy.advise_exit(df_indicators, metadata=metadata, is_short=False)
|
||||
dataframe = strategy.advise_sell(df_indicators, metadata=metadata)
|
||||
assert 'sell' in dataframe.columns
|
||||
|
||||
dataframe = strategy.advise_enter(df_indicators, metadata=metadata, is_short=True)
|
||||
assert 'short' in dataframe.columns
|
||||
|
||||
dataframe = strategy.advise_exit(df_indicators, metadata=metadata, is_short=True)
|
||||
assert 'exit_short' in dataframe.columns
|
||||
|
||||
|
||||
@@ -352,7 +348,7 @@ def test_deprecate_populate_indicators(result, default_conf):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
# Cause all warnings to always be triggered.
|
||||
warnings.simplefilter("always")
|
||||
strategy.advise_enter(indicators, {'pair': 'ETH/BTC'}, is_short=False) # TODO-lev
|
||||
strategy.advise_buy(indicators, {'pair': 'ETH/BTC'})
|
||||
assert len(w) == 1
|
||||
assert issubclass(w[-1].category, DeprecationWarning)
|
||||
assert "deprecated - check out the Sample strategy to see the current function headers!" \
|
||||
@@ -361,7 +357,7 @@ def test_deprecate_populate_indicators(result, default_conf):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
# Cause all warnings to always be triggered.
|
||||
warnings.simplefilter("always")
|
||||
strategy.advise_exit(indicators, {'pair': 'ETH_BTC'}, is_short=False) # TODO-lev
|
||||
strategy.advise_sell(indicators, {'pair': 'ETH_BTC'})
|
||||
assert len(w) == 1
|
||||
assert issubclass(w[-1].category, DeprecationWarning)
|
||||
assert "deprecated - check out the Sample strategy to see the current function headers!" \
|
||||
@@ -381,8 +377,6 @@ def test_call_deprecated_function(result, monkeypatch, default_conf, caplog):
|
||||
assert strategy._populate_fun_len == 2
|
||||
assert strategy._buy_fun_len == 2
|
||||
assert strategy._sell_fun_len == 2
|
||||
# assert strategy._short_fun_len == 2
|
||||
# assert strategy._exit_short_fun_len == 2
|
||||
assert strategy.INTERFACE_VERSION == 1
|
||||
assert strategy.timeframe == '5m'
|
||||
assert strategy.ticker_interval == '5m'
|
||||
@@ -391,22 +385,14 @@ def test_call_deprecated_function(result, monkeypatch, default_conf, caplog):
|
||||
assert isinstance(indicator_df, DataFrame)
|
||||
assert 'adx' in indicator_df.columns
|
||||
|
||||
buydf = strategy.advise_enter(result, metadata=metadata, is_short=False)
|
||||
buydf = strategy.advise_buy(result, metadata=metadata)
|
||||
assert isinstance(buydf, DataFrame)
|
||||
assert 'buy' in buydf.columns
|
||||
|
||||
selldf = strategy.advise_exit(result, metadata=metadata, is_short=False)
|
||||
selldf = strategy.advise_sell(result, metadata=metadata)
|
||||
assert isinstance(selldf, DataFrame)
|
||||
assert 'sell' in selldf
|
||||
|
||||
# shortdf = strategy.advise_enter(result, metadata=metadata, is_short=True)
|
||||
# assert isinstance(shortdf, DataFrame)
|
||||
# assert 'short' in shortdf.columns
|
||||
|
||||
# exit_shortdf = strategy.advise_exit(result, metadata=metadata, is_short=True)
|
||||
# assert isinstance(exit_shortdf, DataFrame)
|
||||
# assert 'exit_short' in exit_shortdf
|
||||
|
||||
assert log_has("DEPRECATED: Please migrate to using 'timeframe' instead of 'ticker_interval'.",
|
||||
caplog)
|
||||
|
||||
@@ -420,26 +406,18 @@ def test_strategy_interface_versioning(result, monkeypatch, default_conf):
|
||||
assert strategy._populate_fun_len == 3
|
||||
assert strategy._buy_fun_len == 3
|
||||
assert strategy._sell_fun_len == 3
|
||||
assert strategy._short_fun_len == 3
|
||||
assert strategy._exit_short_fun_len == 3
|
||||
assert strategy.INTERFACE_VERSION == 2
|
||||
|
||||
indicator_df = strategy.advise_indicators(result, metadata=metadata)
|
||||
assert isinstance(indicator_df, DataFrame)
|
||||
assert 'adx' in indicator_df.columns
|
||||
|
||||
buydf = strategy.advise_enter(result, metadata=metadata, is_short=False)
|
||||
assert isinstance(buydf, DataFrame)
|
||||
assert 'buy' in buydf.columns
|
||||
enterdf = strategy.advise_buy(result, metadata=metadata)
|
||||
assert isinstance(enterdf, DataFrame)
|
||||
assert 'buy' in enterdf.columns
|
||||
assert 'enter_short' in enterdf.columns
|
||||
|
||||
selldf = strategy.advise_exit(result, metadata=metadata, is_short=False)
|
||||
assert isinstance(selldf, DataFrame)
|
||||
assert 'sell' in selldf
|
||||
|
||||
shortdf = strategy.advise_enter(result, metadata=metadata, is_short=True)
|
||||
assert isinstance(shortdf, DataFrame)
|
||||
assert 'short' in shortdf.columns
|
||||
|
||||
exit_shortdf = strategy.advise_exit(result, metadata=metadata, is_short=True)
|
||||
assert isinstance(exit_shortdf, DataFrame)
|
||||
assert 'exit_short' in exit_shortdf
|
||||
exitdf = strategy.advise_sell(result, metadata=metadata)
|
||||
assert isinstance(exitdf, DataFrame)
|
||||
assert 'sell' in exitdf
|
||||
assert 'exit_short' in exitdf.columns
|
||||
|
Reference in New Issue
Block a user