┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┓

┃ Strategy ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃     Avg Duration ┃  Win  Draw  Loss  Win% ┃             Drawdown ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━┩
│    Empty │     49 │         2.64 │         680.535 │        68.05 │ 14 days, 0:38:00 │   44     0     5  89.8 │ 629.763 USDT  27.26% │
└──────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────────┴────────────────────────┴──────────────────────┘
This commit is contained in:
Jérôme Delacotte
2026-02-21 18:40:21 +01:00
parent a228e56172
commit 60ed27529a
3 changed files with 178 additions and 159 deletions

117
Empty.py
View File

@@ -266,7 +266,7 @@ class Empty(IStrategy):
# trailing_only_offset_is_reached = False
position_adjustment_enable = True
use_custom_stoploss = False
use_custom_stoploss = True
#max_open_trades = 3
@@ -385,9 +385,11 @@ class Empty(IStrategy):
sell_score_indicator = CategoricalParameter(score_indicators, default="sma24_score", space='sell')
stoploss_indicator = CategoricalParameter(stoploss_indicators, default="stop_buying12_1d", space='protection')
range_pos_stoploss = DecimalParameter(0, 0.1, decimals=2, default=0.05, space='protection')
stoploss_force = DecimalParameter(-0.2, 0, decimals=2, default=-0.05, space='protection')
stoploss_indicator = CategoricalParameter(god_genes_with_timeperiod, default="stop_buying12_1d", space='protection')
stop_buying_indicator = CategoricalParameter(stoploss_indicators, default="stop_buying12_1d", space='protection')
stoploss_timeperiod = CategoricalParameter(timeperiods, default="12", space='protection')
# stoploss_timeperiod = CategoricalParameter(timeperiods, default="12", space='protection')
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
proposed_stake: float, min_stake: float, max_stake: float,
@@ -409,8 +411,8 @@ class Empty(IStrategy):
# range_pos = (last_candle['close'] - range_min) / (range_max - range_min)
range_pos = last_candle[f"range_pos"]
sl_min = self.wallets.get_available_stake_amount() / 2
sl_max = self.wallets.get_available_stake_amount() / 6
sl_min = self.wallets.get_available_stake_amount() / 6
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
@@ -470,13 +472,18 @@ class Empty(IStrategy):
last_buy = max(filled_buys, key=lambda o: o.order_date)
last_entry_price = last_buy.price
drop_from_last_entry = (current_rate - last_entry_price) / last_entry_price
if last_entry_price:
drop_from_last_entry = (current_rate - last_entry_price) / last_entry_price
if drop_from_last_entry <= -0.025 and last_candle['min60'] == last_candle_3['min60']:
# stake_amount = trade.stake_amount
print(f"adjust {current_time} {stake_amount}")
print(f"adjust {pair} {current_time} dispo={dispo} amount={stake_amount} rate={current_rate}")
return stake_amount
if drop_from_last_entry <= -0.025 and last_candle['min60'] == last_candle_3['min60'] \
and last_candle[self.stop_buying_indicator.value] == False\
and ((last_candle['stop_buying5_1d'] == False) or (last_candle['range_pos'] < 0)) \
and last_candle['range_pos'] <= -0.01:
# stake_amount = trade.stake_amount
self.pairs[trade.pair]['last_buy'] = current_rate
print(f"adjust {current_time} {stake_amount}")
print(f"adjust {pair} {current_time} dispo={dispo} amount={stake_amount} rate={current_rate}")
return stake_amount
return None
@@ -494,7 +501,8 @@ class Empty(IStrategy):
condition = True
if self.pairs[pair]['last_trade'] and self.pairs[pair]['last_trade'].close_date:
if False and self.pairs[pair]['last_trade'].close_date is not None:
# base cooldown = n bougies / cooldown proportionnel au profit
# bougies de plus par %
cooldown_candles = 12 + 6 * (int(self.pairs[pair]['last_profit'] / 0.01)) # réglable
@@ -504,7 +512,7 @@ class Empty(IStrategy):
condition = (candles_since_close >= cooldown_candles)
print(f"Cool down {round(self.pairs[pair]['last_profit'], 3)} {cooldown_candles} {candles_since_close}")
print(f"Cool close date = trade={self.pairs[pair]['last_trade'].close_date} down {round(self.pairs[pair]['last_profit'], 3)} {cooldown_candles} {candles_since_close}")
# self.should_enter_trade(pair, last_candle, current_time)
allow_to_buy = (condition and not self.pairs[pair]['stop']) | (entry_tag == 'force_entry')
@@ -530,6 +538,7 @@ class Empty(IStrategy):
self.pairs[pair]['last_min'] = min(last_candle['close'], self.pairs[pair]['last_min'])
self.pairs[pair]['last_date'] = current_time
dispo = round(self.wallets.get_available_stake_amount())
# self.printLineLog()
@@ -563,7 +572,7 @@ class Empty(IStrategy):
profit = trade.calc_profit(rate)
force = self.pairs[pair]['force_sell']
allow_to_sell = (last_candle['hapercent'] < 0 and profit > 0) or force or (exit_reason == 'force_exit') or (exit_reason == 'stop_loss') or (exit_reason == 'trailing_stop_loss')
allow_to_sell = (last_candle['hapercent'] < 0 and profit > 0) or force or (exit_reason == 'god') or (exit_reason == 'force_exit') or (exit_reason == 'stop_loss') or (exit_reason == 'trailing_stop_loss')
minutes = int(round((current_time - trade.date_last_filled_utc).total_seconds() / 60, 0))
@@ -594,7 +603,7 @@ class Empty(IStrategy):
self.pairs[pair]['max_touch'] = 0
self.pairs[pair]['last_buy'] = 0
self.pairs[pair]['last_date'] = current_time
self.pairs[pair]['last_trade'] = self.pairs[pair]['current_trade']
self.pairs[pair]['last_trade'] = trade
self.pairs[pair]['current_trade'] = None
else:
print(f"{current_time} STOP triggered for {pair} ({exit_reason}) but condition blocked", "warning")
@@ -620,36 +629,41 @@ class Empty(IStrategy):
return None
# def custom_stoploss(self, pair, trade, current_time, current_rate, current_profit, **kwargs):
# dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
# last_candle = dataframe.iloc[-1]
# profit = trade.calc_profit(current_rate)
#
# # print(f'test stop loss {self.stoploss} {last_candle["stop_buying12_1d"]}')
# if last_candle[self.stoploss_indicator.value] and (trade.nr_of_successful_entries >= 4 or self.wallets.get_available_stake_amount() < 300): # and profit < - 30 :
# range_min = last_candle[f"min{self.stoploss_timeperiod.value}_1d"]
# range_max = last_candle[f"max{self.stoploss_timeperiod.value}_1d"]
#
# if range_max == range_min:
# print(f'ranges={range_min}')
# return -0.1 # sécurité
#
# range_pos = (current_rate - range_min) / (range_max - range_min)
#
# if (range_pos > 1):
# return -1
#
# sl_min = -0.02
# sl_max = -0.1 #self.stoploss
#
# dynamic_sl = (sl_min + (1 - range_pos) * (sl_max - sl_min))
#
# print(f'{current_time} Loss ranges={round(range_min,0)} {round(range_max, 0)} range_pos={round(range_pos, 3)} dynamic_sl={round(dynamic_sl, 3)} '
# f'profit={profit} current={current_profit} {self.stoploss_indicator.value} {self.stoploss_timeperiod.value} {last_candle[self.stoploss_indicator.value]}')
#
# return dynamic_sl
#
# return -1
def custom_stoploss(self, pair, trade, current_time, current_rate, current_profit, **kwargs):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1]
profit = trade.calc_profit(current_rate)
candle_at_buy = self.pairs[pair]['last_candle']
if candle_at_buy['range_pos'] > self.range_pos_stoploss.value and candle_at_buy[self.stoploss_indicator.value] < 0:
return self.stoploss_force.value
# # print(f'test stop loss {self.stoploss} {last_candle["stop_buying12_1d"]}')
# if last_candle[self.stoploss_indicator.value] and (trade.nr_of_successful_entries >= 4 or self.wallets.get_available_stake_amount() < 300): # and profit < - 30 :
# range_min = last_candle[f"min{self.stoploss_timeperiod.value}_1d"]
# range_max = last_candle[f"max{self.stoploss_timeperiod.value}_1d"]
#
# if range_max == range_min:
# print(f'ranges={range_min}')
# return -0.1 # sécurité
#
# range_pos = (current_rate - range_min) / (range_max - range_min)
#
# if (range_pos > 1):
# return -1
#
# sl_min = -0.02
# sl_max = -0.1 #self.stoploss
#
# dynamic_sl = (sl_min + (1 - range_pos) * (sl_max - sl_min))
#
# print(f'{current_time} Loss ranges={round(range_min,0)} {round(range_max, 0)} range_pos={round(range_pos, 3)} dynamic_sl={round(dynamic_sl, 3)} '
# f'profit={profit} current={current_profit} {self.stoploss_indicator.value} {self.stoploss_timeperiod.value} {last_candle[self.stoploss_indicator.value]}')
#
# return dynamic_sl
return -1
def informative_pairs(self):
# get access to all pairs available in whitelist.
@@ -725,7 +739,7 @@ class Empty(IStrategy):
range_min = dataframe[f"min12_1d"]
range_max = dataframe[f"max48"]
dataframe[f"range_pos"] = (dataframe['close'] - range_min) / (range_max - range_min)
dataframe[f"range_pos"] = ((dataframe['mid'] - range_min) / (range_max)).rolling(5).mean()
# récupérer le dernier trade fermé
@@ -791,11 +805,11 @@ class Empty(IStrategy):
# buy_real_num
# )
# conditions.append(condition)
conditions.append((dataframe[self.stop_buying_indicator.value] == False))
conditions.append((dataframe[self.stop_buying_indicator.value] == False) | (dataframe['range_pos'] < 0))
# conditions.append(dataframe['hapercent'] > 0)
conditions.append(dataframe['hapercent'] > 0)
# # conditions.append(dataframe[f"range_pos"] <= 0.5)
# conditions.append(dataframe[f"sma5_deriv1"] > 0)
# conditions.append((dataframe[f"range_pos"] < 0.01) | ((dataframe[f"sma5_deriv1"] > 0) & (dataframe[f"sma12_deriv1"] > 0) & (dataframe[f"sma24_deriv1"] > 0)))
print(f"BUY indicators tested \n"
f"{self.buy_indicator0.value} {self.buy_crossed_indicator0.value} {self.buy_operator0.value} {self.buy_real_num0.value} \n"
@@ -812,7 +826,7 @@ class Empty(IStrategy):
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# conditions = list()
conditions = list()
# # TODO: Its not dry code!
# sell_indicator = self.sell_indicator0.value
# sell_crossed_indicator = self.sell_crossed_indicator0.value
@@ -861,6 +875,9 @@ class Empty(IStrategy):
# )
#
#
# conditions.append(qtpylib.crossed_below(dataframe['mid'], dataframe['sma24']))
# conditions.append((dataframe['range_pos'] > 0.04))
#
# if conditions:
# dataframe.loc[reduce(lambda x, y: x & y, conditions), ['exit_long', 'exit_tag']] = (1, 'god')
return dataframe