Skip to content

Commit 77745be

Browse files
committed
Update to v0.2a
1 parent f0fac5e commit 77745be

File tree

2 files changed

+120
-102
lines changed

2 files changed

+120
-102
lines changed

backtest results/v0.2a results.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Tested using fixed stake of 15 BUSD
2+
3+
2021-04-01 00:00:00 -> 2021-06-01 00:00:00 | Max open trades : 4
4+
======================================================================== STRATEGY SUMMARY =======================================================================
5+
| Strategy | Buys | Avg Profit % | Cum Profit % | Tot Profit BUSD | Tot Profit % | Avg Duration | Win Draw Loss Win% | Drawdown |
6+
|---------------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------+--------------------|
7+
| MultiMA_TSL | 939 | 1.32 | 1238.99 | 186.035 | 286.21 | 1:03:00 | 750 0 189 79.9 | 6.448 BUSD 42.94% |
8+
| MultiMA_TSL2a | 859 | 1.58 | 1353.50 | 203.228 | 312.66 | 0:57:00 | 713 0 146 83.0 | 6.399 BUSD 42.62% |
9+
=================================================================================================================================================================
10+
11+
2021-06-01 00:00:00 -> 2021-08-29 23:35:00 | Max open trades : 4
12+
======================================================================== STRATEGY SUMMARY =======================================================================
13+
| Strategy | Buys | Avg Profit % | Cum Profit % | Tot Profit BUSD | Tot Profit % | Avg Duration | Win Draw Loss Win% | Drawdown |
14+
|---------------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------+--------------------|
15+
| MultiMA_TSL | 743 | 1.07 | 795.57 | 119.455 | 183.78 | 1:10:00 | 588 0 155 79.1 | 3.983 BUSD 26.52% |
16+
| MultiMA_TSL2a | 640 | 1.16 | 742.44 | 111.477 | 171.50 | 1:02:00 | 520 0 120 81.2 | 4.032 BUSD 26.86% |
17+
=================================================================================================================================================================

user_data/strategies/MultiMA_TSL.py

Lines changed: 103 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
import talib.abstract as ta
44
from freqtrade.strategy.interface import IStrategy
55
from freqtrade.strategy import (merge_informative_pair,
6-
DecimalParameter, IntParameter, CategoricalParameter)
6+
DecimalParameter, IntParameter, BooleanParameter, CategoricalParameter, stoploss_from_open)
77
from pandas import DataFrame
88
from functools import reduce
99
from freqtrade.persistence import Trade
1010
from datetime import datetime, timedelta
11+
from freqtrade.exchange import timeframe_to_prev_date
12+
from technical.indicators import zema
1113

1214
###########################################################################################################
1315
## MultiMA_TSL, modded by stash86, based on SMAOffsetProtectOptV1 (modded by Perkmeister) ##
@@ -20,28 +22,33 @@
2022
# I hope you do enough testing before proceeding, either backtesting and/or dry run.
2123
# Any profits and losses are all your responsibility
2224

23-
class MultiMA_TSL(IStrategy):
25+
class MultiMA_TSL2a(IStrategy):
2426
INTERFACE_VERSION = 2
2527

2628
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,
3441

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,
3844
}
3945

4046
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,
4552
}
4653

4754
# ROI table:
@@ -52,45 +59,53 @@ class MultiMA_TSL(IStrategy):
5259
stoploss = -0.15
5360

5461
# 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)
6065

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)
6469
rsi_buy_ema = IntParameter(30, 70, default=61, space='buy', optimize=False)
6570

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)
6873
rsi_buy_trima = IntParameter(30, 70, default=61, space='buy', optimize=False)
6974

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)
7578

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)
7991

8092
# Trailing stoploss (not used)
8193
trailing_stop = False
8294
trailing_only_offset_is_reached = True
8395
trailing_stop_positive = 0.01
8496
trailing_stop_positive_offset = 0.018
8597

86-
use_custom_stoploss = False
98+
use_custom_stoploss = True
8799

88100
# Protection hyperspace params:
89101
protection_params = {
90102
"low_profit_lookback": 60,
91103
"low_profit_min_req": 0.03,
92104
"low_profit_stop_duration": 29,
105+
93106
"cooldown_lookback": 2, # value loaded from strategy
107+
"stoploss_lookback": 72, # value loaded from strategy
108+
"stoploss_stop_duration": 20, # value loaded from strategy
94109
}
95110

96111
cooldown_lookback = IntParameter(2, 48, default=2, space="protection", optimize=False)
@@ -131,123 +146,99 @@ def protections(self):
131146
# Number of candles the strategy requires before producing valid signals
132147
startup_candle_count: int = 200
133148

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
140153

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
142160

143-
return True
161+
return sl_new
144162

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])
148165

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-
166166
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-
170167
# EWO
171168
dataframe['ewo'] = EWO(dataframe, self.fast_ewo.value, self.slow_ewo.value)
172169

173170
# RSI
174171
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
175172
dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4)
176173

174+
dataframe["roc_max"] = dataframe["close"].pct_change(48).rolling(12).max() * 100
175+
177176
return dataframe
178177

179178
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
180179
conditions = []
181180

182-
dataframe['sma_offset_buy'] = ta.SMA(dataframe, int(self.base_nb_candles_buy_sma.value)) *self.low_offset_sma.value
183181
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
184183
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+
187185
dataframe.loc[:, 'buy_tag'] = ''
186+
dataframe.loc[:, 'buy_copy'] = 0
187+
dataframe.loc[:, 'buy'] = 0
188188

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']) &
206192
(
207193
(dataframe['ewo'] < self.ewo_low.value)
208194
|
209195
(
210196
(dataframe['ewo'] > self.ewo_high.value)
211197
&
212-
(dataframe['rsi'] < self.rsi_buy_ema.value)
198+
(dataframe['rsi'] < self.rsi_buy_trima.value)
213199
)
214200
)
215201
)
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)
218204

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']) &
221208
(
222209
(dataframe['ewo'] < self.ewo_low.value)
223210
|
224211
(
225212
(dataframe['ewo'] > self.ewo_high.value)
226213
&
227-
(dataframe['rsi'] < self.rsi_buy_trima.value)
214+
(dataframe['rsi'] < self.rsi_buy_zema.value)
228215
)
229216
)
230217
)
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)
233220

234221
add_check = (
235-
(dataframe['rsi_fast'] < 35)
222+
(dataframe['rsi_fast'] < self.buy_rsi_fast.value)
236223
&
237-
(dataframe['close'] < dataframe['ema_offset_sell'])
224+
(dataframe['close'] < dataframe['ema_offset_buy'])
238225
&
239226
(dataframe['volume'] > 0)
240227
)
241228

242229
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)
244234

245235
return dataframe
246236

247237
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
251242

252243
conditions = []
253244

@@ -258,11 +249,21 @@ def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame
258249
)
259250
)
260251

252+
conditions.append(
253+
(
254+
(dataframe['close'] > dataframe['trima_offset_sell']) &
255+
(dataframe['volume'] > 0)
256+
)
257+
)
258+
261259
if conditions:
262260
dataframe.loc[
263261
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
266267

267268
return dataframe
268269

0 commit comments

Comments
 (0)