3
3
import talib .abstract as ta
4
4
from freqtrade .strategy .interface import IStrategy
5
5
from freqtrade .strategy import (merge_informative_pair ,
6
- DecimalParameter , IntParameter , CategoricalParameter )
6
+ DecimalParameter , IntParameter , BooleanParameter , CategoricalParameter , stoploss_from_open )
7
7
from pandas import DataFrame
8
8
from functools import reduce
9
9
from freqtrade .persistence import Trade
10
10
from datetime import datetime , timedelta
11
+ from freqtrade .exchange import timeframe_to_prev_date
12
+ from technical .indicators import zema
11
13
12
14
###########################################################################################################
13
15
## MultiMA_TSL, modded by stash86, based on SMAOffsetProtectOptV1 (modded by Perkmeister) ##
20
22
# I hope you do enough testing before proceeding, either backtesting and/or dry run.
21
23
# Any profits and losses are all your responsibility
22
24
23
- class MultiMA_TSL (IStrategy ):
25
+ class MultiMA_TSL2a (IStrategy ):
24
26
INTERFACE_VERSION = 2
25
27
26
28
buy_params = {
27
- "base_nb_candles_buy_sma" : 76 ,
28
- "low_offset_sma" : 0.959 ,
29
- "rsi_buy_sma" : 55 ,
30
-
31
- "base_nb_candles_buy_ema" : 6 ,
32
- "low_offset_ema" : 0.985 ,
33
- "rsi_buy_ema" : 61 ,
29
+ "base_nb_candles_buy_ema" : 50 ,
30
+ "low_offset_ema" : 1.061 ,
31
+
32
+ "base_nb_candles_buy_zema" : 30 ,
33
+ "low_offset_zema" : 0.963 ,
34
+ "rsi_buy_zema" : 50 ,
35
+
36
+ "base_nb_candles_buy_trima" : 14 ,
37
+ "low_offset_trima" : 0.963 ,
38
+ "rsi_buy_trima" : 50 ,
39
+
40
+ "buy_roc_max" : 45 ,
34
41
35
- "base_nb_candles_buy_trima" : 6 ,
36
- "low_offset_trima" : 0.981 ,
37
- "rsi_buy_trima" : 59 ,
42
+ "buy_condition_trima_enable" : True ,
43
+ "buy_condition_zema_enable" : True ,
38
44
}
39
45
40
46
sell_params = {
41
- "base_nb_candles_sell" : 30 ,
42
- "high_offset_ema" : 1.004 ,
43
- "sl_filter_candles" : 3 ,
44
- "sl_filter_offset" : 0.992 ,
47
+ "base_nb_candles_sell" : 32 ,
48
+ "high_offset_ema" : 1.002 ,
49
+
50
+ "base_nb_candles_sell_trima" : 48 ,
51
+ "high_offset_trima" : 1.085 ,
45
52
}
46
53
47
54
# ROI table:
@@ -52,45 +59,53 @@ class MultiMA_TSL(IStrategy):
52
59
stoploss = - 0.15
53
60
54
61
# Multi Offset
55
- base_nb_candles_sell = IntParameter (5 , 80 , default = 20 , load = True , space = 'sell' , optimize = False )
56
-
57
- base_nb_candles_buy_sma = IntParameter (5 , 80 , default = 20 , load = True , space = 'buy' , optimize = False )
58
- low_offset_sma = DecimalParameter (0.9 , 0.99 , default = 0.958 , load = True , space = 'buy' , optimize = False )
59
- rsi_buy_sma = IntParameter (30 , 70 , default = 61 , space = 'buy' , optimize = False )
62
+ base_nb_candles_sell = IntParameter (5 , 80 , default = 20 , space = 'sell' , optimize = False )
63
+ base_nb_candles_sell_trima = IntParameter (5 , 80 , default = 20 , space = 'sell' , optimize = False )
64
+ high_offset_trima = DecimalParameter (0.99 , 1.1 , default = 1.012 , space = 'sell' , optimize = False )
60
65
61
- base_nb_candles_buy_ema = IntParameter (5 , 80 , default = 20 , load = True , space = 'buy' , optimize = False )
62
- low_offset_ema = DecimalParameter (0.9 , 0.99 , default = 0.958 , load = True , space = 'buy' , optimize = False )
63
- high_offset_ema = DecimalParameter (0.99 , 1.1 , default = 1.012 , load = True , space = 'sell' , optimize = False )
66
+ base_nb_candles_buy_ema = IntParameter (5 , 80 , default = 20 , space = 'buy' , optimize = False )
67
+ low_offset_ema = DecimalParameter (0.9 , 1.1 , default = 0.958 , space = 'buy' , optimize = False )
68
+ high_offset_ema = DecimalParameter (0.99 , 1.1 , default = 1.012 , space = 'sell' , optimize = False )
64
69
rsi_buy_ema = IntParameter (30 , 70 , default = 61 , space = 'buy' , optimize = False )
65
70
66
- base_nb_candles_buy_trima = IntParameter (5 , 80 , default = 20 , load = True , space = 'buy' , optimize = False )
67
- low_offset_trima = DecimalParameter (0.9 , 0.99 , default = 0.958 , load = True , space = 'buy' , optimize = False )
71
+ base_nb_candles_buy_trima = IntParameter (5 , 80 , default = 20 , space = 'buy' , optimize = False )
72
+ low_offset_trima = DecimalParameter (0.9 , 0.99 , default = 0.958 , space = 'buy' , optimize = False )
68
73
rsi_buy_trima = IntParameter (30 , 70 , default = 61 , space = 'buy' , optimize = False )
69
74
70
- # Protection
71
- ewo_low = DecimalParameter (- 20.0 , - 8.0 , default = - 20.0 , load = True , space = 'buy' , optimize = False )
72
- ewo_high = DecimalParameter (2.0 , 12.0 , default = 6.0 , load = True , space = 'buy' , optimize = False )
73
- fast_ewo = IntParameter (10 , 50 , default = 50 , load = True , space = 'buy' , optimize = False )
74
- slow_ewo = IntParameter (100 , 200 , default = 200 , load = True , space = 'buy' , optimize = False )
75
+ base_nb_candles_buy_zema = IntParameter (5 , 80 , default = 20 , space = 'buy' , optimize = False )
76
+ low_offset_zema = DecimalParameter (0.9 , 0.99 , default = 0.958 , space = 'buy' , optimize = False )
77
+ rsi_buy_zema = IntParameter (30 , 70 , default = 61 , space = 'buy' , optimize = False )
75
78
76
- # stoploss sharp dip filter
77
- sl_filter_candles = IntParameter (2 , 10 , default = 5 , space = 'sell' , optimize = False , load = True )
78
- sl_filter_offset = DecimalParameter (0.960 , 0.999 , default = 0.989 , decimals = 3 , space = 'sell' , optimize = False , load = True )
79
+ buy_condition_enable_optimize = True
80
+ buy_condition_trima_enable = BooleanParameter (default = True , space = 'buy' , optimize = buy_condition_enable_optimize )
81
+ buy_condition_zema_enable = BooleanParameter (default = True , space = 'buy' , optimize = buy_condition_enable_optimize )
82
+
83
+ # Protection
84
+ ewo_low = DecimalParameter (- 20.0 , - 8.0 , default = - 20.0 , space = 'buy' , optimize = False )
85
+ ewo_high = DecimalParameter (2.0 , 12.0 , default = 6.0 , space = 'buy' , optimize = False )
86
+ fast_ewo = IntParameter (10 , 50 , default = 50 , space = 'buy' , optimize = False )
87
+ slow_ewo = IntParameter (100 , 200 , default = 200 , space = 'buy' , optimize = False )
88
+ buy_roc_max = DecimalParameter (20 , 70 , default = 55 , space = 'buy' , optimize = False )
89
+ buy_peak_max = DecimalParameter (1 , 1.1 , default = 1.03 , decimals = 3 , space = 'buy' , optimize = False )
90
+ buy_rsi_fast = IntParameter (0 , 50 , default = 35 , space = 'buy' , optimize = False )
79
91
80
92
# Trailing stoploss (not used)
81
93
trailing_stop = False
82
94
trailing_only_offset_is_reached = True
83
95
trailing_stop_positive = 0.01
84
96
trailing_stop_positive_offset = 0.018
85
97
86
- use_custom_stoploss = False
98
+ use_custom_stoploss = True
87
99
88
100
# Protection hyperspace params:
89
101
protection_params = {
90
102
"low_profit_lookback" : 60 ,
91
103
"low_profit_min_req" : 0.03 ,
92
104
"low_profit_stop_duration" : 29 ,
105
+
93
106
"cooldown_lookback" : 2 , # value loaded from strategy
107
+ "stoploss_lookback" : 72 , # value loaded from strategy
108
+ "stoploss_stop_duration" : 20 , # value loaded from strategy
94
109
}
95
110
96
111
cooldown_lookback = IntParameter (2 , 48 , default = 2 , space = "protection" , optimize = False )
@@ -131,123 +146,99 @@ def protections(self):
131
146
# Number of candles the strategy requires before producing valid signals
132
147
startup_candle_count : int = 200
133
148
134
- def get_ticker_indicator (self ):
135
- return int (self .timeframe [:- 1 ])
136
-
137
- def confirm_trade_entry (self , pair : str , order_type : str , amount : float , rate : float , time_in_force : str , ** kwargs ) -> bool :
138
- dataframe , _ = self .dp .get_analyzed_dataframe (pair , self .timeframe )
139
- last_candle = dataframe .iloc [- 1 ].squeeze ()
149
+ #credit to Perkmeister for this custom stoploss to help the strategy ride a green candle when the sell signal triggered
150
+ def custom_stoploss (self , pair : str , trade : 'Trade' , current_time : datetime ,
151
+ current_rate : float , current_profit : float , ** kwargs ) -> float :
152
+ sl_new = 1
140
153
141
- if ((rate > last_candle ['close' ])) : return False
154
+ if not self .config ['runmode' ].value in ('backtest' , 'hyperopt' ):
155
+ dataframe , _ = self .dp .get_analyzed_dataframe (pair , self .timeframe )
156
+ if (len (dataframe ) >= 1 ):
157
+ last_candle = dataframe .iloc [- 1 ]
158
+ if ((last_candle ['sell_copy' ] == 1 ) & (last_candle ['buy_copy' ] == 0 )):
159
+ sl_new = 0.001
142
160
143
- return True
161
+ return sl_new
144
162
145
- def confirm_trade_exit (self , pair : str , trade : Trade , order_type : str , amount : float ,
146
- rate : float , time_in_force : str , sell_reason : str ,
147
- current_time : datetime , ** kwargs ) -> bool :
163
+ def get_ticker_indicator (self ):
164
+ return int (self .timeframe [:- 1 ])
148
165
149
- # Code from Perkmeister, to check for a sudden dip
150
- if (sell_reason == 'stop_loss' ):
151
- dataframe , _ = self .dp .get_analyzed_dataframe (pair , self .timeframe )
152
- if (len (dataframe ) < 1 ):
153
- return True
154
- last_candle = dataframe .iloc [- 1 ]
155
- current_profit = trade .calc_profit_ratio (rate )
156
-
157
- if (
158
- (trade .initial_stop_loss == trade .stop_loss ) &
159
- (last_candle ['ma_sl_filter_offset' ] > rate )
160
- ):
161
- # Reject hard stoploss on large dip
162
- return False
163
-
164
- return True
165
-
166
166
def populate_indicators (self , dataframe : DataFrame , metadata : dict ) -> DataFrame :
167
- if not self .config ['runmode' ].value == 'hyperopt' :
168
- dataframe ['ma_sl_filter_offset' ] = ta .EMA (dataframe , timeperiod = int (self .sl_filter_candles .value )) * self .sl_filter_offset .value
169
-
170
167
# EWO
171
168
dataframe ['ewo' ] = EWO (dataframe , self .fast_ewo .value , self .slow_ewo .value )
172
169
173
170
# RSI
174
171
dataframe ['rsi' ] = ta .RSI (dataframe , timeperiod = 14 )
175
172
dataframe ['rsi_fast' ] = ta .RSI (dataframe , timeperiod = 4 )
176
173
174
+ dataframe ["roc_max" ] = dataframe ["close" ].pct_change (48 ).rolling (12 ).max () * 100
175
+
177
176
return dataframe
178
177
179
178
def populate_buy_trend (self , dataframe : DataFrame , metadata : dict ) -> DataFrame :
180
179
conditions = []
181
180
182
- dataframe ['sma_offset_buy' ] = ta .SMA (dataframe , int (self .base_nb_candles_buy_sma .value )) * self .low_offset_sma .value
183
181
dataframe ['ema_offset_buy' ] = ta .EMA (dataframe , int (self .base_nb_candles_buy_ema .value )) * self .low_offset_ema .value
182
+ dataframe ['zema_offset_buy' ] = zema (dataframe , int (self .base_nb_candles_buy_zema .value )) * self .low_offset_zema .value
184
183
dataframe ['trima_offset_buy' ] = ta .TRIMA (dataframe , int (self .base_nb_candles_buy_trima .value )) * self .low_offset_trima .value
185
- dataframe ['ema_offset_sell' ] = ta .EMA (dataframe , int (self .base_nb_candles_sell .value )) * self .high_offset_ema .value
186
-
184
+
187
185
dataframe .loc [:, 'buy_tag' ] = ''
186
+ dataframe .loc [:, 'buy_copy' ] = 0
187
+ dataframe .loc [:, 'buy' ] = 0
188
188
189
- buy_offset_sma = (
190
- (dataframe ['close' ] < dataframe ['sma_offset_buy' ]) &
191
- (
192
- (dataframe ['ewo' ] < self .ewo_low .value )
193
- |
194
- (
195
- (dataframe ['ewo' ] > self .ewo_high .value )
196
- &
197
- (dataframe ['rsi' ] < self .rsi_buy_sma .value )
198
- )
199
- )
200
- )
201
- dataframe .loc [buy_offset_sma , 'buy_tag' ] += 'sma '
202
- conditions .append (buy_offset_sma )
203
-
204
- buy_offset_ema = (
205
- (dataframe ['close' ] < dataframe ['ema_offset_buy' ]) &
189
+ buy_offset_trima = (
190
+ self .buy_condition_trima_enable .value &
191
+ (dataframe ['close' ] < dataframe ['trima_offset_buy' ]) &
206
192
(
207
193
(dataframe ['ewo' ] < self .ewo_low .value )
208
194
|
209
195
(
210
196
(dataframe ['ewo' ] > self .ewo_high .value )
211
197
&
212
- (dataframe ['rsi' ] < self .rsi_buy_ema .value )
198
+ (dataframe ['rsi' ] < self .rsi_buy_trima .value )
213
199
)
214
200
)
215
201
)
216
- dataframe .loc [buy_offset_ema , 'buy_tag' ] += 'ema '
217
- conditions .append (buy_offset_ema )
202
+ dataframe .loc [buy_offset_trima , 'buy_tag' ] += 'trima '
203
+ conditions .append (buy_offset_trima )
218
204
219
- buy_offset_trima = (
220
- (dataframe ['close' ] < dataframe ['trima_offset_buy' ]) &
205
+ buy_offset_zema = (
206
+ self .buy_condition_zema_enable .value &
207
+ (dataframe ['close' ] < dataframe ['zema_offset_buy' ]) &
221
208
(
222
209
(dataframe ['ewo' ] < self .ewo_low .value )
223
210
|
224
211
(
225
212
(dataframe ['ewo' ] > self .ewo_high .value )
226
213
&
227
- (dataframe ['rsi' ] < self .rsi_buy_trima .value )
214
+ (dataframe ['rsi' ] < self .rsi_buy_zema .value )
228
215
)
229
216
)
230
217
)
231
- dataframe .loc [buy_offset_trima , 'buy_tag' ] += 'trima '
232
- conditions .append (buy_offset_trima )
218
+ dataframe .loc [buy_offset_zema , 'buy_tag' ] += 'zema '
219
+ conditions .append (buy_offset_zema )
233
220
234
221
add_check = (
235
- (dataframe ['rsi_fast' ] < 35 )
222
+ (dataframe ['rsi_fast' ] < self . buy_rsi_fast . value )
236
223
&
237
- (dataframe ['close' ] < dataframe ['ema_offset_sell ' ])
224
+ (dataframe ['close' ] < dataframe ['ema_offset_buy ' ])
238
225
&
239
226
(dataframe ['volume' ] > 0 )
240
227
)
241
228
242
229
if conditions :
243
- dataframe .loc [:, 'buy' ] = add_check & reduce (lambda x , y : x | y , conditions )
230
+ dataframe .loc [
231
+ (add_check & reduce (lambda x , y : x | y , conditions )),
232
+ ['buy_copy' ,'buy' ]
233
+ ]= (1 ,1 )
244
234
245
235
return dataframe
246
236
247
237
def populate_sell_trend (self , dataframe : DataFrame , metadata : dict ) -> DataFrame :
248
- if self .config ['runmode' ].value == 'hyperopt' :
249
- dataframe ['ema_offset_sell' ] = ta .EMA (dataframe , int (self .base_nb_candles_sell .value )) * self .high_offset_ema .value
250
- dataframe ['ma_sl_filter_offset' ] = ta .EMA (dataframe , timeperiod = int (self .sl_filter_candles .value )) * self .sl_filter_offset .value
238
+ dataframe .loc [:, 'sell_copy' ] = 0
239
+
240
+ dataframe ['ema_offset_sell' ] = ta .EMA (dataframe , int (self .base_nb_candles_sell .value )) * self .high_offset_ema .value
241
+ dataframe ['trima_offset_sell' ] = ta .TRIMA (dataframe , int (self .base_nb_candles_sell_trima .value )) * self .high_offset_trima .value
251
242
252
243
conditions = []
253
244
@@ -258,11 +249,21 @@ def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame
258
249
)
259
250
)
260
251
252
+ conditions .append (
253
+ (
254
+ (dataframe ['close' ] > dataframe ['trima_offset_sell' ]) &
255
+ (dataframe ['volume' ] > 0 )
256
+ )
257
+ )
258
+
261
259
if conditions :
262
260
dataframe .loc [
263
261
reduce (lambda x , y : x | y , conditions ),
264
- 'sell'
265
- ]= 1
262
+ ['sell_copy' , 'sell' ]
263
+ ]= (1 ,1 )
264
+
265
+ if not self .config ['runmode' ].value in ('backtest' , 'hyperopt' ):
266
+ dataframe .loc [:, 'sell' ] = 0
266
267
267
268
return dataframe
268
269
0 commit comments