Backtested 2023-01-01 00:00:00 -> 2026-02-20 00:00:00 | Max open trades : 1
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓ ┃ Strategy ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃ Drawdown ┃ ┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩ │ Empty │ 85 │ 1.06 │ 1239.222 │ 123.92 │ 2 days, 12:39:00 │ 54 0 31 63.5 │ 206.862 USDT 8.61% │ └──────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────────┴────────────────────────┴─────────────────────┘
This commit is contained in:
78
Empty.py
78
Empty.py
@@ -324,7 +324,8 @@ class Empty(IStrategy):
|
||||
'force_buy': False,
|
||||
'current_trade': None,
|
||||
'last_trade': None,
|
||||
'force_stop': False
|
||||
'force_stop': False,
|
||||
'count_of_lost': 0
|
||||
}
|
||||
for pair in ["BTC/USDC", "BTC/USDT"]
|
||||
}
|
||||
@@ -432,7 +433,7 @@ class Empty(IStrategy):
|
||||
sl_max = self.wallets.get_available_stake_amount() / 2
|
||||
|
||||
amount = sl_min + (1 - range_pos) * (sl_max - sl_min)
|
||||
# amount = self.wallets.get_available_stake_amount() / 8
|
||||
amount = self.wallets.get_available_stake_amount()
|
||||
|
||||
return min(amount, self.wallets.get_available_stake_amount())
|
||||
|
||||
@@ -535,7 +536,9 @@ class Empty(IStrategy):
|
||||
last_candle_2 = dataframe.iloc[-2].squeeze()
|
||||
last_candle_3 = dataframe.iloc[-3].squeeze()
|
||||
|
||||
condition = True
|
||||
condition = False if self.pairs[pair]['count_of_lost'] >= 1 \
|
||||
and (last_candle['sma12_deriv1_1d'] < 0.001 \
|
||||
or last_candle['sma12_deriv2_1d'] < 0.001) else True
|
||||
|
||||
if condition and last_candle['range_pos'] > 0.05:# and self.pairs[pair]['force_stop']:
|
||||
condition = last_candle['sma5'] > last_candle['sma60']
|
||||
@@ -619,7 +622,6 @@ class Empty(IStrategy):
|
||||
if allow_to_sell:
|
||||
self.pairs[pair]['last_sell'] = rate
|
||||
self.pairs[pair]['last_candle'] = last_candle
|
||||
self.pairs[pair]['max_profit'] = 0
|
||||
profit = trade.calc_profit(rate)
|
||||
self.pairs[pair]['previous_profit'] = profit
|
||||
dispo = round(self.wallets.get_available_stake_amount())
|
||||
@@ -645,6 +647,12 @@ class Empty(IStrategy):
|
||||
self.pairs[pair]['last_date'] = current_time
|
||||
self.pairs[pair]['last_trade'] = trade
|
||||
self.pairs[pair]['current_trade'] = None
|
||||
self.pairs[pair]['max_profit'] = 0
|
||||
|
||||
if profit < 0:
|
||||
self.pairs[pair]['count_of_lost'] += 1
|
||||
else:
|
||||
self.pairs[pair]['count_of_lost'] = 0
|
||||
else:
|
||||
print(f"{current_time} STOP triggered for {pair} ({exit_reason}) but condition blocked", "warning")
|
||||
return (allow_to_sell) | (exit_reason == 'force_exit') | (exit_reason == 'stop_loss') | force
|
||||
@@ -656,12 +664,14 @@ class Empty(IStrategy):
|
||||
before_last_candle = dataframe.iloc[-2]
|
||||
self.pairs[pair]['current_trade'] = trade
|
||||
momentum = last_candle[self.sell_score_indicator.value]
|
||||
|
||||
profit = trade.calc_profit(current_rate) #round(current_profit * trade.stake_amount, 1)
|
||||
count_of_buys = trade.nr_of_successful_entries
|
||||
expected_profit = self.expectedProfit(pair, last_candle)
|
||||
|
||||
self.pairs[pair]['max_profit'] = max(self.pairs[pair]['max_profit'], profit)
|
||||
max_profit = self.pairs[pair]['max_profit']
|
||||
|
||||
baisse = 0
|
||||
if profit > 0:
|
||||
baisse = 1 - (profit / max_profit)
|
||||
@@ -669,22 +679,27 @@ class Empty(IStrategy):
|
||||
self.pairs[pair]['count_of_buys'] = count_of_buys
|
||||
self.pairs[pair]['current_profit'] = profit
|
||||
|
||||
dispo = round(self.wallets.get_available_stake_amount()) + self.pairs[pair]['total_amount']
|
||||
dispo = round(self.wallets.get_available_stake_amount() + self.pairs[pair]['total_amount'])
|
||||
|
||||
self.log_trade(
|
||||
last_candle=last_candle,
|
||||
date=current_time,
|
||||
action=("🔴 NOW" if self.pairs[pair]['stop'] else "🟢 NOW "),
|
||||
dispo=dispo,
|
||||
pair=pair,
|
||||
rate=last_candle['close'],
|
||||
trade_type='momentum' + str(round(momentum, 2)),
|
||||
profit=round(profit, 2),
|
||||
buys=count_of_buys,
|
||||
stake=0
|
||||
)
|
||||
# self.log_trade(
|
||||
# last_candle=last_candle,
|
||||
# date=current_time,
|
||||
# action=("🔴 NOW" if self.pairs[pair]['stop'] else "🟢 NOW "),
|
||||
# dispo=dispo,
|
||||
# pair=pair,
|
||||
# rate=last_candle['close'],
|
||||
# trade_type='momentum' + str(round(momentum, 2)),
|
||||
# profit=round(profit, 2),
|
||||
# buys=count_of_buys,
|
||||
# stake=0
|
||||
# )
|
||||
|
||||
if profit > max(5, expected_profit) and baisse > 0.30:
|
||||
if current_profit < - 0.02 and last_candle[f"close"] <= last_candle['sma60']:
|
||||
self.pairs[pair]['force_sell'] = True
|
||||
return 'sma60'
|
||||
|
||||
if profit > max(5, expected_profit) and baisse > 0.30 and last_candle[f"close"] <= last_candle['sma5']\
|
||||
and last_candle['percent3'] < 0 and last_candle['percent5'] < 0:
|
||||
self.pairs[pair]['force_sell'] = True
|
||||
self.pairs[pair]['force_buy'] = (self.pairs[pair]['count_of_buys'] - self.pairs[pair]['has_gain'] > 3)
|
||||
return str(count_of_buys) + '_' + 'B30_' + pair + '_' + str(self.pairs[pair]['has_gain'])
|
||||
@@ -712,14 +727,15 @@ class Empty(IStrategy):
|
||||
# self.pairs[pair]['force_sell'] = True
|
||||
# return 'Stop'
|
||||
# Si momentum fort → on laisse courir
|
||||
|
||||
if momentum > 1:
|
||||
return None
|
||||
|
||||
# Si momentum faiblit → on prend profit plus tôt
|
||||
if momentum < 0 and current_profit > 0.02 and last_candle[self.sell_score_indicator.value] < before_last_candle[self.sell_score_indicator.value]\
|
||||
and last_candle['close'] < last_candle['sma5']:
|
||||
self.pairs[pair]['last_profit'] = current_profit
|
||||
return "momentum_drop"
|
||||
# if momentum < 0 and current_profit > 0.02 and last_candle[self.sell_score_indicator.value] < before_last_candle[self.sell_score_indicator.value]\
|
||||
# and last_candle['close'] < last_candle['sma5']:
|
||||
# self.pairs[pair]['last_profit'] = current_profit
|
||||
# return "momentum_drop"
|
||||
|
||||
return None
|
||||
|
||||
@@ -801,6 +817,9 @@ class Empty(IStrategy):
|
||||
informative[f"sma{timeperiod}"] = informative['mid'].ewm(span=timeperiod, adjust=False).mean()
|
||||
self.calculeDerivees(informative, f"sma{timeperiod}", timeframe=self.timeframe, ema_period=timeperiod)
|
||||
|
||||
informative['rsi'] = talib.RSI(informative['close'], timeperiod=14)
|
||||
informative['max_rsi_12'] = talib.MAX(informative['rsi'], timeperiod=12)
|
||||
informative['max_rsi_24'] = talib.MAX(informative['rsi'], timeperiod=24)
|
||||
|
||||
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True)
|
||||
# ######################################################################################################
|
||||
@@ -809,9 +828,13 @@ class Empty(IStrategy):
|
||||
range_max = dataframe[f"max48"]
|
||||
|
||||
dataframe[f"range_pos"] = ((dataframe['mid'] - range_min) / (range_max)).rolling(5).mean()
|
||||
dataframe['cross_sma60'] = qtpylib.crossed_above(dataframe['sma5'], dataframe['sma60'])
|
||||
dataframe['cross_sma60'] = qtpylib.crossed_below(dataframe['sma12'], dataframe['sma5_1d'])
|
||||
dataframe[f'stop_buying'] = qtpylib.crossed_below(dataframe[f"sma12"], dataframe['sma48'])
|
||||
|
||||
dataframe['rsi'] = talib.RSI(dataframe['close'], timeperiod=14)
|
||||
dataframe['max_rsi_12'] = talib.MAX(dataframe['rsi'], timeperiod=12)
|
||||
dataframe['max_rsi_24'] = talib.MAX(dataframe['rsi'], timeperiod=24)
|
||||
|
||||
# récupérer le dernier trade fermé
|
||||
trades = Trade.get_trades_proxy(pair=pair,is_open=False)
|
||||
if trades:
|
||||
@@ -883,7 +906,10 @@ class Empty(IStrategy):
|
||||
conditions.append(dataframe['sma5_deriv1_1d'] > self.buy_deriv_sma5d.value)
|
||||
conditions.append(dataframe['sma12_deriv1_1d'] > self.buy_deriv_sma12d.value)
|
||||
conditions.append(dataframe['hapercent'] > 0)
|
||||
# # conditions.append(dataframe[f"range_pos"] <= 0.5)
|
||||
conditions.append(dataframe['max_rsi_24'] < 80)
|
||||
conditions.append(dataframe['max_rsi_12_1d'] < 65)
|
||||
|
||||
conditions.append(dataframe[f"close"] > dataframe['sma60'])
|
||||
conditions.append(((dataframe[f"range_pos"] < 0.05) ) | ((dataframe['sma12_deriv1'] > 0) & (dataframe['sma12_deriv2'] > 0)))
|
||||
|
||||
# print(f"BUY indicators tested \n"
|
||||
@@ -1076,7 +1102,7 @@ class Empty(IStrategy):
|
||||
self.printLog(
|
||||
f"| {'Date':<16} | {'Action':<10} |{'Pair':<5}| {'Trade Type':<18} |{'Rate':>8} | {'Dispo':>6} | {'Profit':>8} "
|
||||
f"| {'Pct':>6} | {'max_touch':>11} | {'last_lost':>12} | {'last_max':>7}| {'last_max':>7}|{'Buys':>5}| {'Stake':>5} |"
|
||||
f"{'rsi':>6}|Distmax|s201d|s5_1d|s5_2d|s51h|s52h|smt1h|smt2h|tdc1d|tdc1h"
|
||||
f"{'rsi':>6}|"
|
||||
)
|
||||
self.printLineLog()
|
||||
df = pd.DataFrame.from_dict(self.pairs, orient='index')
|
||||
@@ -1150,7 +1176,7 @@ class Empty(IStrategy):
|
||||
last_min = int(self.pairs[pair]['last_min']) if self.pairs[pair]['last_min'] > 1 else round(
|
||||
self.pairs[pair]['last_min'], 3)
|
||||
|
||||
profit = str(profit) + '/' + str(round(self.pairs[pair]['max_profit'], 2))
|
||||
profit = str(round(profit, 2)) + '/' + str(round(self.pairs[pair]['max_profit'], 2))
|
||||
|
||||
# 🟢 Dérivée 1 > 0 et dérivée 2 > 0: tendance haussière qui s’accélère.
|
||||
# 🟡 Dérivée 1 > 0 et dérivée 2 < 0: tendance haussière qui ralentit → essoufflement potentiel.
|
||||
|
||||
Reference in New Issue
Block a user