From 117d4667225e9f20348390a727b84d17f52621a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Delacotte?= Date: Sat, 22 Mar 2025 17:54:06 +0100 Subject: [PATCH] synchronise HeikinAshi --- HammerReversalStrategy.py | 1 - HeikinAshi.py | 459 +++++++++++++++++++++++++++++++++----- Zeus_8_3_2_B_4_2.py | 268 ++++++---------------- 3 files changed, 478 insertions(+), 250 deletions(-) diff --git a/HammerReversalStrategy.py b/HammerReversalStrategy.py index 34cf2c5..e6e3d8c 100644 --- a/HammerReversalStrategy.py +++ b/HammerReversalStrategy.py @@ -274,7 +274,6 @@ class HammerReversalStrategy(IStrategy): self.pairs[pair]['max_touch'] = max(last_candle['haclose'], self.pairs[pair]['max_touch']) - # On ne déclenche le trailing stop que si un profit mini a déjà été atteint # and (limit_sell < -0.01) if (current_profit > 0.01) and (last_candle['percent12'] < 0) and (last_candle['percent5'] < 0): diff --git a/HeikinAshi.py b/HeikinAshi.py index b4d86b0..ea6e866 100644 --- a/HeikinAshi.py +++ b/HeikinAshi.py @@ -32,23 +32,14 @@ from ta.utils import dropna import freqtrade.vendor.qtpylib.indicators as qtpylib from functools import reduce import numpy as np +from scipy.special import binom +from ta.trend import SMAIndicator, EMAIndicator, MACD, ADXIndicator +from ta.momentum import RSIIndicator, StochasticOscillator class HeikinAshi(IStrategy): plot_config = { "main_plot": { - "min12": { - "color": "#197260" - }, - 'max12': { - 'color': 'green' - }, - "haclose": { - "color": "red" - }, - 'haopen': { - 'color': 'blue' - }, "min288": { "color": "#197260" }, @@ -57,13 +48,47 @@ class HeikinAshi(IStrategy): }, 'mid288': { 'color': 'blue' - } + }, + 'hasma5': { + 'color': 'red' + }, + 'max48': { + 'color': 'yellow' + }, + 'min48': { + 'color': 'yellow' + }, + 'sma12': { + 'color': 'pink' + }, + 'ema5_1d': { + 'color': "#74effc" + }, + 'ema20_1d': { + 'color': "cyan" + }, }, "subplots": { "Percent": { "hapercent": { "color": "#74effc" } + }, + 'up_down': { + 'up_pct': { + 'color': 'red' + }, + 'down_pct': { + 'color': 'blue' + } + }, + 'tag': { + 'rsi_downtrend': { + 'color': 'red' + }, + 'ma_downtrend': { + 'color': 'blue' + } } } @@ -92,7 +117,7 @@ class HeikinAshi(IStrategy): # Optimal timeframe use it in your config timeframe = '5m' columns_logged = False - max_entry_position_adjustment = 20 + max_entry_position_adjustment = 30 startup_candle_count = 288 # Trailing stoploss @@ -100,7 +125,7 @@ class HeikinAshi(IStrategy): # trailing_stop_positive = 0.001 # trailing_stop_positive_offset = 0.015 # trailing_only_offset_is_reached = True - position_adjustment_enable = False + position_adjustment_enable = True pairs = { pair: { @@ -108,12 +133,18 @@ class HeikinAshi(IStrategy): "trade_info": {}, "max_touch": 0.0, "last_sell": 0.0, - "last_buy": 0.0 + "last_buy": 0.0, + 'count_of_buys': 0, + 'current_profit': 0, + 'expected_profit': 0, + "last_candle": {}, + "last_trade": None, + 'base_stake_amount': 0 } for pair in ["BTC/USDT", "ETH/USDT", "DOGE/USDT", "DASH/USDT", "XRP/USDT", "SOL/USDT"] } - decalage = IntParameter(0, 48, default=12, space='buy') + decalage = IntParameter(0, 10, default=3, space='buy') ########################################## END RESULT PASTE PLACE ##################################### # ------------------------------------------------------------------------------------------------------------------ @@ -125,26 +156,95 @@ class HeikinAshi(IStrategy): **kwargs ) -> Union[Optional[float], Tuple[Optional[float], Optional[str]]]: - # ne rien faire si ordre deja en cours if trade.has_open_orders: return None + if (self.wallets.get_available_stake_amount() < 50): # or trade.stake_amount >= max_stake: + return 0 dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() - last_candle_24 = dataframe.iloc[-25].squeeze() + # last_candle_decalage = dataframe.iloc[-1 - self.decalage.value].squeeze() + # last_candle_24 = dataframe.iloc[-25].squeeze() + + # if (last_candle['sma5_diff_1d'] < -0.1): + # return None # prépare les données count_of_buys = trade.nr_of_successful_entries current_time = current_time.astimezone(timezone.utc) open_date = trade.open_date.astimezone(timezone.utc) dispo = round(self.wallets.get_available_stake_amount()) + hours = (current_time - trade.date_last_filled_utc).total_seconds() / 3600.0 - limit_buy = 4 + # if (current_profit > 0.008) \ + # and (last_candle['up_pct'] >= 1)\ + # and (last_candle['volume'] >= 250) \ + # and (hours >= 1): + # additional_stake = self.config['stake_amount'] + # self.log_trade( + # last_candle=last_candle, + # date=current_time, + # action="Gain +", + # dispo=dispo, + # pair=trade.pair, + # rate=current_rate, + # trade_type='Increase', + # profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2), + # buys=trade.nr_of_successful_entries, + # stake=round(additional_stake, 2) + # ) + # # self.pairs[trade.pair]['last_max'] = last_candle['haclose'] + # self.pairs[trade.pair]['max_touch'] = last_candle['haclose'] + # return additional_stake + + # if (last_candle['percent'] > 0.001) and (current_profit > 0): + # # and (last_candle_decalage['min12'] == last_candle['min12']) \ + # # and (last_candle_decalage['close'] < last_candle_decalage['mid288']): + # additional_stake = self.config['stake_amount'] / 10 + # self.log_trade( + # last_candle=last_candle, + # date=current_time, + # action="Gain +", + # dispo=dispo, + # pair=trade.pair, + # rate=current_rate, + # trade_type='Increase', + # profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2), + # buys=trade.nr_of_successful_entries, + # stake=round(additional_stake, 2) + # ) + # return additional_stake + max_touch = self.pairs[trade.pair]['max_touch'] + pct_max = - round(100 * (last_candle['close'] - max_touch) / max_touch, 1) + + # if (last_candle['enter_long'] == 1) and (current_profit < - 0.0075 or hours >= 1) and (count_of_buys == 1): + # additional_stake = self.config['stake_amount'] / 2 + # self.log_trade( + # last_candle=last_candle, + # date=current_time, + # action="Long", + # dispo=dispo, + # pair=trade.pair, + # rate=current_rate, + # trade_type='Increase', + # profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2), + # buys=trade.nr_of_successful_entries + 1, + # stake=round(additional_stake, 2) + # ) + # self.expectedProfit(trade.pair, last_candle, current_rate) + # self.pairs[trade.pair]['last_buy'] = current_rate + # self.pairs[trade.pair]['max_touch'] = last_candle['close'] + # self.pairs[trade.pair]['last_candle'] = last_candle + # + # return additional_stake + + limit_buy = 5 if (count_of_buys < limit_buy) \ - and (last_candle['min288'] == last_candle_24['min288']) \ - and (current_profit < -0.01 * count_of_buys) \ - and (last_candle['close'] < last_candle['mid288']): - additional_stake = self.config['stake_amount'] + and ((last_candle['enter_long'] == 1)) \ + and (current_profit < -0.015 * count_of_buys): + # and (last_candle_decalage['min12'] == last_candle['min12']) \ + # and (last_candle_decalage['close'] < last_candle_decalage['mid288']): + additional_stake = self.calculate_stake(trade.pair, last_candle, 1) # self.config['stake_amount'] self.log_trade( last_candle=last_candle, date=current_time, @@ -154,12 +254,39 @@ class HeikinAshi(IStrategy): rate=current_rate, trade_type='Decrease', profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2), - buys=trade.nr_of_successful_entries, + buys=trade.nr_of_successful_entries + 1, stake=round(additional_stake, 2) ) + self.expectedProfit(trade.pair, last_candle, current_rate) + self.pairs[trade.pair]['last_buy'] = current_rate + self.pairs[trade.pair]['max_touch'] = last_candle['close'] + self.pairs[trade.pair]['last_candle'] = last_candle + return additional_stake - if (count_of_buys >= limit_buy) & (current_profit < - 0.03 * count_of_buys): - additional_stake = self.config['stake_amount'] * 2 + + # if (count_of_buys == limit_buy) & (current_profit < - 0.03 * count_of_buys)\ + # and ((last_candle['enter_long'] == 1) or last_candle['percent48'] < - 0.03): + # additional_stake = - trade.stake_amount / 2 #self.config['stake_amount'] * (-current_profit / 0.10) + # self.log_trade( + # last_candle=last_candle, + # date=current_time, + # action="Loss -", + # dispo=dispo, + # pair=trade.pair, + # rate=current_rate, + # trade_type='Decrease', + # profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2), + # buys=trade.nr_of_successful_entries, + # stake=round(additional_stake, 2) + # ) + # # self.pairs[trade.pair]['last_max'] = last_candle['haclose'] + # self.pairs[trade.pair]['max_touch'] = last_candle['haclose'] + # return additional_stake + + pct_limit = (-0.015 * limit_buy) + (- 0.03 * (count_of_buys - limit_buy)) + if (count_of_buys >= limit_buy) & (current_profit < pct_limit) \ + and ((last_candle['enter_long'] == 1) or last_candle['percent48'] < - 0.03): + additional_stake = self.calculate_stake(trade.pair, last_candle, 1) * (-current_profit / 0.10) self.log_trade( last_candle=last_candle, date=current_time, @@ -169,15 +296,49 @@ class HeikinAshi(IStrategy): rate=current_rate, trade_type='Decrease', profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2), - buys=trade.nr_of_successful_entries, + buys=trade.nr_of_successful_entries + 1, stake=round(additional_stake, 2) ) + self.expectedProfit(trade.pair, last_candle, current_rate) + self.pairs[trade.pair]['last_buy'] = current_rate + self.pairs[trade.pair]['max_touch'] = last_candle['close'] + self.pairs[trade.pair]['last_candle'] = last_candle + return additional_stake return None + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + + # Obtenir les données actuelles pour cette paire + last_candle = dataframe.iloc[-1].squeeze() + stake_amount = self.config['stake_amount'] + # if last_candle['close'] < last_candle['max5_1d'] * 0.98 : + # stake_amount = 2 * stake_amount + # else: + # if last_candle['close'] > last_candle['max5_1d'] * 1.02: + # stake_amount = 0.5 * stake_amount + # if last_candle['entry_tag'] == 'buy_hammer': + # stake_amount = stake_amount * 2 + + return stake_amount + def calculate_stake(self, pair, last_candle, factor=1): - amount = self.config['stake_amount'] * factor #1000 / self.first_stack_factor.value self.protection_stake_amount.value # + + # if self.pairs[pair]['count_of_buys'] == 1 and factor == 1: + # if last_candle['close'] > last_candle['min5_1d'] + (last_candle['max5_1d'] - last_candle['min5_1d']) / 2: + # factor = 0.5 + # amount = self.config['stake_amount'] * factor + # else: + # amount = self.config['stake_amount'] + # self.pairs[pair]['base_stake_amount'] = amount + # else: + # amount = max(self.config['stake_amount'], self.pairs[pair]['base_stake_amount']) + + amount = self.config['stake_amount'] return amount def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, @@ -185,8 +346,32 @@ class HeikinAshi(IStrategy): dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() dispo = round(self.wallets.get_available_stake_amount()) + + # if (self.pairs[pair]['last_sell'] > 0) and (last_candle['close'] * 1.01 > self.pairs[pair]['last_sell']): + # self.log_trade( + # last_candle=last_candle, + # date=current_time, + # action="CANCEL BUY", + # pair=pair, + # rate=rate, + # dispo=dispo, + # profit=0, + # stake=round(stake_amount, 2) + # ) + # return False + self.pairs[pair]['last_buy'] = rate + self.pairs[pair]['max_touch'] = last_candle['close'] + self.pairs[pair]['last_max'] = last_candle['close'] + self.pairs[pair]['last_candle'] = last_candle + self.pairs[pair]['count_of_buys'] = 1 + self.pairs[pair]['current_profit'] = 0 stake_amount = self.calculate_stake(pair, last_candle, 1) + # self.columns_logged = False + print( + f"|{'-' * 18}+{'-' * 12}+{'-' * 12}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 7}+{'-' * 13}+{'-' * 14}+{'-' * 14}+{'-' * 7}+{'-' * 12}|" + ) + self.log_trade( last_candle=last_candle, date=current_time, @@ -195,8 +380,11 @@ class HeikinAshi(IStrategy): rate=rate, dispo=dispo, profit=0, + trade_type=entry_tag, + buys=1, stake=round(stake_amount, 2) ) + self.expectedProfit(pair, last_candle, rate) return True def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float, @@ -210,10 +398,9 @@ class HeikinAshi(IStrategy): allow_to_sell = (last_candle['percent5'] < -0.00) ok = (allow_to_sell) | (exit_reason == 'force_exit') if ok: - # self.pairs[pair]['last_max'] = 0 - # self.pairs[pair]['max_touch'] = 0 - self.pairs[pair]['last_buy'] = 0 self.pairs[pair]['last_sell'] = rate + self.pairs[pair]['last_trade'] = trade + self.pairs[pair]['last_candle'] = last_candle self.log_trade( last_candle=last_candle, date=current_time, @@ -224,7 +411,11 @@ class HeikinAshi(IStrategy): dispo=dispo, profit=round(trade.calc_profit(rate, amount), 2) ) - #print(f"Sell {current_time} {exit_reason} rate={rate:.3f} amount={amount} profit={amount * rate:.3f}") + self.pairs[pair]['last_max'] = 0 + self.pairs[pair]['max_touch'] = 0 + self.pairs[pair]['last_buy'] = 0 + + # print(f"Sell {current_time} {exit_reason} rate={rate:.3f} amount={amount} profit={amount * rate:.3f}") return ok @@ -232,23 +423,94 @@ class HeikinAshi(IStrategy): dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() + before_last_candle = dataframe.iloc[-2].squeeze() - if (current_profit > 0.004) \ - & (last_candle['hapercent'] < 0.0) \ - & (last_candle['percent'] < 0.0): - count_of_buys = trade.nr_of_successful_entries - return 'profit_' + str(count_of_buys) + max_touch_before = self.pairs[pair]['max_touch'] + last_max_before = self.pairs[pair]['last_max'] + self.pairs[pair]['last_max'] = max(last_candle['haclose'], self.pairs[pair]['last_max']) - def log_trade(self, action, pair, date, trade_type=None, rate=None, dispo=None, profit=None, buys=None, stake=None, last_candle=None): + last_lost = (last_candle['close'] - max_touch_before) / max_touch_before + count_of_buys = trade.nr_of_successful_entries + + self.pairs[pair]['count_of_buys'] = count_of_buys + self.pairs[pair]['current_profit'] = current_profit + + days = (current_time - trade.open_date_utc).days + days = max(1, days) + factor = 1 + # if days > 10: + # factor = 1 + days / 10 + expected_profit = self.pairs[pair]['expected_profit'] / factor + + # print( + # f"{current_time} days={days} expected={expected_profit:.3f} rate={current_rate} max_touch={max_touch_before:.1f} profit={current_profit:.3f} last_lost={last_lost:.3f} buys={count_of_buys} percent={last_candle['percent']:.4f}") + + if (current_profit > expected_profit) \ + & (last_candle['percent'] < 0.0) \ + & (last_lost > - current_profit / 5): + # & (before_last_candle['hasma5'] < last_candle['hasma5']): + # & (last_lost < min(-0.003, - min(0.006, current_profit / 4))): + # & (last_candle['up_count'] > 0): + + return 'last_lost_' + str(count_of_buys) + self.pairs[pair]['max_touch'] = max(last_candle['haclose'], self.pairs[pair]['max_touch']) + + # if (current_profit > 0.004) \ + # & (last_candle['hapercent'] < 0.0) \ + # & (last_candle['percent3'] < - min(0.01, current_profit / 4)): + # return 'profit_' + str(count_of_buys) + + def detect_loose_hammer(self, df: DataFrame) -> DataFrame: + """ + Détection large de marteaux : accepte des corps plus gros, ne vérifie pas le volume, + ne demande pas de divergence, juste un pattern visuel simple. + """ + + body = abs(df['close'] - df['open']) + upper_shadow = abs(df['high'] - np.maximum(df['close'], df['open'])) + lower_shadow = abs(np.minimum(df['close'], df['open']) - df['low']) + + # Critères simplifiés : + df['loose_hammer'] = ( + (lower_shadow > body * 2.5) # mèche basse > 1.5x corps + & (upper_shadow < body) # petite mèche haute + & (df['low'] < df['bb_lowerband']) # bougie verte (optionnel, on peut prendre aussi les rouges) + ).astype(int) + df['won_hammer'] = ( + (upper_shadow > body * 2.5) # mèche basse > 1.5x corps + & (lower_shadow < body) # petite mèche haute + & (df['high'] > df['bb_upperband']) # bougie verte (optionnel, on peut prendre aussi les rouges) + ).astype(int) + + return df + + def expectedProfit(self, pair: str, last_candle, current_rate): + + last_buy = self.pairs[pair]['last_buy'] + max_touch = self.pairs[pair]['max_touch'] + last_max = self.pairs[pair]['last_max'] + + expected_profit = ((max_touch - last_buy) / max_touch) + self.pairs[pair]['expected_profit'] = max(0.004, expected_profit) + + # print(f"expected max_touch={max_touch:.1f} last_buy={last_buy:.1f} expected={expected_profit:.3f} max5_1d={last_candle['max5_1d']:.1f}") + + return expected_profit + + def log_trade(self, action, pair, date, trade_type=None, rate=None, dispo=None, profit=None, buys=None, stake=None, + last_candle=None): # Afficher les colonnes une seule fois if self.config.get('runmode') == 'hyperopt': return if self.columns_logged % 30 == 0: + # print( + # f"|{'-' * 18}+{'-' * 12}+{'-' * 12}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 7}+{'-' * 13}+{'-' * 14}+{'-' * 14}+{'-' * 7}+{'-' * 12}|" + # ) print( - f"| {'Date':<16} | {'Action':<10} | {'Pair':<10} | {'Trade Type':<18} | {'Rate':>12} | {'Dispo':>6} | {'Profit':>8} | {'Pct':>5} | {'max7_1d':>11} | {'max_touch':>12} | {'last_max':>12} | {'Buys':>5} | {'Stake':>10} |" + f"| {'Date':<16} | {'Action':<10} | {'Pair':<10} | {'Trade Type':<18} | {'Rate':>12} | {'Dispo':>6} | {'Profit':>8} | {'Pct':>5} | {'max_touch':>11} | {'last_lost':>12} | {'last_max':>12} | {'Buys':>5} | {'Stake':>10} |" ) print( - f"|{'-' * 18}|{'-' * 12}|{'-' * 12}|{'-' * 20}|{'-' * 14}|{'-' * 8}|{'-' * 10}|{'-' * 7}|{'-' * 13}|{'-' * 14}|{'-' * 14}|{'-' * 7}|{'-' * 12}|" + f"|{'-' * 18}+{'-' * 12}+{'-' * 12}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 7}+{'-' * 13}+{'-' * 14}+{'-' * 14}+{'-' * 7}+{'-' * 12}|" ) self.columns_logged += 1 date = str(date)[:16] if date else "-" @@ -279,28 +541,46 @@ class HeikinAshi(IStrategy): # if action != 'Sell': # profit = round((last_candle['close'] - self.pairs[pair]['last_max']) / self.pairs[pair]['last_max'], 2) + last_lost = round((last_candle['haclose'] - self.pairs[pair]['max_touch']) / self.pairs[pair]['max_touch'], 3) limit_sell = rsi_pct # round((last_candle['close'] - self.pairs[pair]['last_max']) / self.pairs[pair]['last_max'], 4) - max7_1d = round(self.pairs[pair]['max_touch'], 1) #last_candle['max7_1d'] #round(100 * (last_candle['close'] - self.pairs[pair]['last_max']) / self.pairs[pair]['last_max'], 1) - pct_max = round(100 * (last_candle['close'] - max7_1d) / max7_1d, 1) + max_touch = round(self.pairs[pair]['max_touch'], + 1) # last_candle['max7_1d'] #round(100 * (last_candle['close'] - self.pairs[pair]['last_max']) / self.pairs[pair]['last_max'], 1) + pct_max = round(100 * self.pairs[pair]['current_profit'], + 1) # round(100 * (last_candle['close'] - max_touch) / max_touch, 1) + + if trade_type is not None: + trade_type = trade_type + " " + str(round(100 * self.pairs[pair]['expected_profit'], 1)) + print( - f"| {date:<16} | {action:<10} | {pair:<10} | {trade_type or '-':<18} | {rate or '-':>12} | {dispo or '-':>6} | {profit or '-':>8} | {pct_max or '-':>5} | {max7_1d or '-':>11} | {round(self.pairs[pair]['max_touch'], 2) or '-':>12} | {round(self.pairs[pair]['last_max'],2) or '-':>12} | {buys or '-':>5} | {stake or '-':>10} |" + f"| {date:<16} | {action:<10} | {pair:<10} | {trade_type or '-':<18} | {rate or '-':>12} | {dispo or '-':>6} | {profit or '-':>8} | {pct_max or '-':>5} | {max_touch or '-':>11} | {last_lost or '-':>12} | {round(self.pairs[pair]['last_max'], 2) or '-':>12} | {self.pairs[pair]['count_of_buys'] or '-':>5} | {stake or '-':>10} |" ) def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: heikinashi = qtpylib.heikinashi(dataframe) dataframe['haopen'] = heikinashi['open'] dataframe['haclose'] = heikinashi['close'] + dataframe['hamid'] = dataframe['haclose'] + (dataframe['haopen'] - dataframe['haclose']) / 2 + dataframe['mid'] = dataframe['open'] + (dataframe['close'] - dataframe['open']) / 2 + dataframe['sma12'] = dataframe['mid'].rolling(12).sum() / 12 + + dataframe['hasma5'] = dataframe['hamid'].rolling(5).sum() / 5 + dataframe['hasma5_diff'] = dataframe['hasma5'] - dataframe['hasma5'].shift(1) dataframe['halow'] = heikinashi['low'] dataframe['hapercent'] = (dataframe['haclose'] - dataframe['haopen']) / dataframe['haclose'] dataframe['min12'] = talib.MIN(dataframe['close'], timeperiod=12) dataframe['max12'] = talib.MAX(dataframe['close'], timeperiod=12) + dataframe['min48'] = talib.MIN(dataframe['close'], timeperiod=48) + dataframe['max48'] = talib.MAX(dataframe['close'], timeperiod=48) dataframe['min288'] = talib.MIN(dataframe['close'], timeperiod=288) dataframe['max288'] = talib.MAX(dataframe['close'], timeperiod=288) dataframe['mid288'] = dataframe['min288'] + (dataframe['max288'] - dataframe['min288']) / 2 dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent3"] = dataframe['close'].pct_change(3) dataframe["percent5"] = dataframe['close'].pct_change(5) + dataframe["percent12"] = dataframe['close'].pct_change(12) + dataframe["percent48"] = dataframe['close'].pct_change(48) # Bollinger Bands bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2) @@ -309,26 +589,95 @@ class HeikinAshi(IStrategy): dataframe['bb_upperband'] = bollinger['upper'] dataframe['bb_diff'] = (dataframe['bb_upperband'] - dataframe['bb_lowerband']) / dataframe['bb_lowerband'] + # Compter les baisses consécutives + dataframe['down'] = dataframe['hapercent'] <= 0.001 + dataframe['up'] = dataframe['hapercent'] >= -0.001 + dataframe['down_count'] = - dataframe['down'].astype(int) * ( + dataframe['down'].groupby((dataframe['down'] != dataframe['down'].shift()).cumsum()).cumcount() + 1) + dataframe['up_count'] = dataframe['up'].astype(int) * ( + dataframe['up'].groupby((dataframe['up'] != dataframe['up'].shift()).cumsum()).cumcount() + 1) + dataframe['down_tag'] = (dataframe['down_count'] < -7) + dataframe['up_tag'] = (dataframe['up_count'] > 7) + + # Créer une colonne vide + dataframe['down_pct'] = self.calculateUpDownPct(dataframe, 'down_count') + dataframe['up_pct'] = self.calculateUpDownPct(dataframe, 'up_count') + + # # ======================================================================================Decrease + # ################### INFORMATIVE 1d + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + # # Moving Averages + # informative['ema5'] = EMAIndicator(informative['close'], window=5).ema_indicator() + # informative['ema20'] = EMAIndicator(informative['close'], window=20).ema_indicator() + # informative['ma_downtrend'] = (informative['close'] < informative['ema5']) & (informative['ema5'] < informative['ema20']) + # + # # RSI + # informative['rsi'] = RSIIndicator(informative['close'], window=14).rsi() + # informative['rsi_downtrend'] = informative['rsi'] < 50 + informative['max5'] = talib.MAX(informative['close'], timeperiod=5) + informative['max12'] = talib.MAX(informative['close'], timeperiod=12) + informative['min5'] = talib.MIN(informative['close'], timeperiod=5) + informative['min12'] = talib.MIN(informative['close'], timeperiod=12) + informative['sma5'] = talib.SMA(informative, timeperiod=25) + informative['sma5_diff'] = 100 * (informative['sma5'] - informative['sma5'].shift(1)) / informative['sma5'] + # informative = self.detect_loose_hammer(informative) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + dataframe = self.detect_loose_hammer(dataframe) + return dataframe + def calculateUpDownPct(self, dataframe, key): + down_pct_values = np.full(len(dataframe), np.nan) + # Remplir la colonne avec les bons calculs + for i in range(len(dataframe)): + shift_value = abs(int(dataframe[key].iloc[i])) # Récupérer le shift actuel + if i - shift_value > 1: # Vérifier que le shift ne dépasse pas l'index + down_pct_values[i] = 100 * (dataframe['close'].iloc[i] - dataframe['close'].iloc[i - shift_value]) / \ + dataframe['close'].iloc[i - shift_value] + return down_pct_values + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Buy strategy Hyperopt will build and use. """ + d = self.decalage.value # dataframe.loc[ - # (dataframe['halow'] <= dataframe['min12']) + # (dataframe['halow'].shift(d) <= dataframe['min12'].shift(d)) + # & (dataframe['min12'].shift(d) == dataframe['min12']) + # # & (dataframe['close'] < dataframe['hasma5']) + # # & (dataframe['bb_diff'] > 0.01) + # , + # ['enter_long', 'enter_tag']] = [1, 'buy_halow'] + + # dataframe.loc[ + # (dataframe['hasma5_diff'].shift(2) >= dataframe['hasma5_diff'].shift(1)) + # & (dataframe['hasma5_diff'].shift(1) <= dataframe['hasma5_diff']) + # # & (dataframe['bb_diff'] > 0.01) + # , + # ['enter_long', 'enter_tag']] = [1, 'buy_hasma5_diff'] + + # dataframe.loc[ + # (dataframe['halow'].shift(decalage) <= dataframe['min288'].shift(decalage)) + # # & (dataframe['min288'].shift(decalage) == dataframe['min288']) # # & (dataframe['open'] <= dataframe['bb_middleband']) # # & (dataframe['bb_diff'] > 0.01) # , # 'buy']=1 - decalage = 3 + dataframe.loc[ - (dataframe['halow'].shift(decalage) <= dataframe['min288'].shift(decalage)) - & (dataframe['min288'].shift(decalage) == dataframe['min288']) - # & (dataframe['open'] <= dataframe['bb_middleband']) - # & (dataframe['bb_diff'] > 0.01) + ( + (dataframe['down_count'].shift(1) <= -8) + | (dataframe['percent12'] <= -0.012) + ) + & (dataframe['down_count'] == 0) , - 'buy']=1 + ['enter_long', 'enter_tag']] = [1, 'buy_down'] + + dataframe.loc[(dataframe['loose_hammer'] == 1) + , + ['enter_long', 'enter_tag']] = [1, 'buy_hammer'] return dataframe @@ -340,3 +689,11 @@ class HeikinAshi(IStrategy): # (qtpylib.crossed_above(dataframe['haclose'], dataframe['haopen'])), # 'sell']=1 return dataframe + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs diff --git a/Zeus_8_3_2_B_4_2.py b/Zeus_8_3_2_B_4_2.py index 6b2925d..0fa223a 100644 --- a/Zeus_8_3_2_B_4_2.py +++ b/Zeus_8_3_2_B_4_2.py @@ -39,28 +39,6 @@ def normalize(df): df = (df - df.min()) / (df.max() - df.min()) return df - -def get_limit_from_config(section, pair): - file_path = '/HOME/home/souti/freqtrade2/user_data/strategies/Zeus_8_3_2_B_4_2.txt' - # Créez un objet ConfigParser - config = configparser.ConfigParser() - - try: - # Lisez le fichier avec les valeurs - config.read(file_path) - - # Vérifiez si la section existe - if config.has_section(section): - # Obtenez les valeurs à partir de la section et de la clé (pair) - limit = config.get(section, pair) - return limit - else: - raise ValueError(f"La section '{section}' n'existe pas dans le fichier de configuration.") - except Exception as e: - print(f"Erreur lors de la lecture du fichier de configuration : {e}") - return None - - class Zeus_8_3_2_B_4_2(IStrategy): levels = [1, 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20] @@ -198,14 +176,14 @@ class Zeus_8_3_2_B_4_2(IStrategy): # hard stoploss profit sell_allow_decrease = DecimalParameter(0.005, 0.02, default=0.2, decimals=2, space='sell', optimize=True, load=True) - pHSL = DecimalParameter(-0.200, -0.040, default=-0.08, decimals=3, space='sell', optimize=False, load=True) - # profit threshold 1, trigger point, SL_1 is used - pPF_1 = DecimalParameter(0.008, 0.020, default=0.016, decimals=3, space='sell', optimize=True, load=True) - pSL_1 = DecimalParameter(0.008, 0.020, default=0.011, decimals=3, space='sell', optimize=True, load=True) - - # profit threshold 2, SL_2 is used - pPF_2 = DecimalParameter(0.040, 0.100, default=0.080, decimals=3, space='sell', optimize=True, load=True) - pSL_2 = DecimalParameter(0.020, 0.070, default=0.040, decimals=3, space='sell', optimize=True, load=True) + # pHSL = DecimalParameter(-0.200, -0.040, default=-0.08, decimals=3, space='sell', optimize=False, load=True) + # # profit threshold 1, trigger point, SL_1 is used + # pPF_1 = DecimalParameter(0.008, 0.020, default=0.016, decimals=3, space='sell', optimize=True, load=True) + # pSL_1 = DecimalParameter(0.008, 0.020, default=0.011, decimals=3, space='sell', optimize=True, load=True) + # + # # profit threshold 2, SL_2 is used + # pPF_2 = DecimalParameter(0.040, 0.100, default=0.080, decimals=3, space='sell', optimize=True, load=True) + # pSL_2 = DecimalParameter(0.020, 0.070, default=0.040, decimals=3, space='sell', optimize=True, load=True) def min_max_scaling(self, series: pd.Series) -> pd.Series: """Normaliser les données en les ramenant entre 0 et 100.""" @@ -223,18 +201,15 @@ class Zeus_8_3_2_B_4_2(IStrategy): # filled_buys = trade.select_filled_orders('buy') # count_buys = len(filled_buys) - print('entry_tag' + str(entry_tag)) dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() # last_candle_12 = dataframe.iloc[-13].squeeze() - limit = get_limit_from_config('Achats', pair) # allow_to_buy = True #(not self.stop_all) #& (not self.all_down) allow_to_buy = True # (rate <= float(limit)) | (entry_tag == 'force_entry') - # allow_to_buy = rate <= dataframe['lbp_3'] self.trades = list() dispo = round(self.wallets.get_available_stake_amount()) - logger.info(f"BUY {pair} allow_to_buy {allow_to_buy} limit={limit} Buy {entry_tag} {current_time} dispo={dispo}") + print(f"BUY {pair} {entry_tag} {current_time} allow_to_buy={allow_to_buy} dispo={dispo}") return allow_to_buy @@ -242,23 +217,17 @@ class Zeus_8_3_2_B_4_2(IStrategy): time_in_force: str, exit_reason: str, current_time, **kwargs, ) -> bool: # allow_to_sell = (minutes > 30) - limit = get_limit_from_config('Ventes', pair) dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() - allow_to_sell = (last_candle['percent'] < 0) # rate > float(limit) - string = "" + allow_to_sell = (last_candle['percent'] < 0) if allow_to_sell: self.trades = list() - logger.info('Sell ' + exit_reason + ' ' + str(current_time) + ' ' + pair + " dispo=" + str( - round(self.wallets.get_available_stake_amount())) # "+ str(amount) + ' ' + str(rate) - + " open_rate=" + str(trade.open_rate) + " rate=" + str(rate) + " profit=" + str( - trade.calc_profit(rate, amount)) - + " " + string) - # del self.max_profit_pairs[pair] + dispo= round(self.wallets.get_available_stake_amount()) + print(f"Sell {pair} {current_time} {exit_reason} dispo={dispo} amount={amount} rate={rate} open_rate={trade.open_rate}") else: - logger.info('Cancel Sell ' + exit_reason + ' ' + str(current_time) + ' ' + pair) + print('Cancel Sell ' + exit_reason + ' ' + str(current_time) + ' ' + pair) return (allow_to_sell) | (exit_reason == 'force_exit') def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, @@ -269,83 +238,10 @@ class Zeus_8_3_2_B_4_2(IStrategy): current_candle = dataframe.iloc[-1].squeeze() adjusted_stake_amount = self.adjust_stake_amount(pair, current_candle) - logger.info(f"{pair} adjusted_stake_amount{adjusted_stake_amount}") + # print(f"{pair} adjusted_stake_amount{adjusted_stake_amount}") # Use default stake amount. return adjusted_stake_amount - # - # def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, - # current_rate: float, current_profit: float, **kwargs) -> float: - # - # # # hard stoploss profit - # # HSL = self.pHSL.value - # # PF_1 = self.pPF_1.value - # # SL_1 = self.pSL_1.value - # # PF_2 = self.pPF_2.value - # # SL_2 = self.pSL_2.value - # # - # # # For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated - # # # between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value - # # # rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used. - # # - # # if current_profit > PF_2: - # # sl_profit = SL_2 + (current_profit - PF_2) - # # elif current_profit > PF_1: - # # sl_profit = SL_1 + ((current_profit - PF_1) * (SL_2 - SL_1) / (PF_2 - PF_1)) - # # else: - # # sl_profit = HSL - # - # #print(f"entry_tag={trade.entry_tag} max={trade.max_rate} min={trade.min_rate} ") - # if current_profit > 0.0125: - # sl_profit = 0.75 * current_profit # 75% du profit en cours - # else: - # sl_profit = self.pHSL.value # Hard stop-loss - # stoploss = stoploss_from_open(sl_profit, current_profit) - # return stoploss - - # - # dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) - # last_candle = dataframe.iloc[-1].squeeze() - # limit = get_limit_from_config('Ventes', pair) - # - # print(pair + " " + str(current_rate) + " " + str(limit)) - # - # #stop_loss = self.adjust_stop_loss(dataframe.iloc[-1]) - # - # #if current_rate < float(limit): - # # return -1 - # - # # "pHSL": -0.99, - # # "pPF_1": 0.022, - # # "pSL_1": 0.021, - # # "pPF_2": 0.08, - # # "pSL_2": 0.04, - # # - # # hard stoploss profit - # HSL = self.pHSL.value - # PF_1 = self.pPF_1.value - # SL_1 = self.pSL_1.value - # PF_2 = self.pPF_2.value - # SL_2 = self.pSL_2.value - # - # # For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated - # # between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value - # # rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used. - # - # # 0.04 - # if current_profit > PF_2: - # # 0.04 + (current_profit - 0.08) - # sl_profit = SL_2 + (current_profit - PF_2) - # # 0.022 - # elif current_profit > PF_1: - # # 0.021 + ((current_profit - 0.022) * (0.04 - 0.021) / (0.08 - 0.022)) - # sl_profit = SL_1 + ((current_profit - PF_1) * (SL_2 - SL_1) / (PF_2 - PF_1)) - # else: - # sl_profit = HSL - # - # slfo = stoploss_from_open(sl_profit, current_profit) - # print('current_profit=' + str(current_profit) + ' stop from open=' + str(slfo)) - # return slfo def custom_exit(self, pair: str, trade: Trade, current_time, current_rate, current_profit, **kwargs): @@ -360,12 +256,12 @@ class Zeus_8_3_2_B_4_2(IStrategy): # Calcul du prix cible basé sur l'ATR atr_take_profit = trade.open_rate + (last_candle['atr'] * 2) # Prendre profit à 2x l'ATR - # logger.info(f"{pair} Custom exit atr_take_profit={atr_take_profit:.4f}") + # print(f"{pair} Custom exit atr_take_profit={atr_take_profit:.4f}") # if current_rate >= atr_take_profit: # return 'sell_atr_take_profit' if (last_candle['percent3'] < -0.002) & (last_candle['percent12'] < 0) & ( - current_profit > last_candle['min_max200'] / 2): + current_profit > last_candle['min_max200'] / 3): self.trades = list() return 'min_max200' if (last_candle['percent12'] <= -0.01) & (current_profit >= expected_profit): @@ -384,9 +280,6 @@ class Zeus_8_3_2_B_4_2(IStrategy): # Add all ta features pair = metadata['pair'] - dataframe['achats'] = get_limit_from_config('Achats', pair) - dataframe['ventes'] = get_limit_from_config('Ventes', pair) - heikinashi = qtpylib.heikinashi(dataframe) dataframe['haopen'] = heikinashi['open'] dataframe['haclose'] = heikinashi['close'] @@ -546,27 +439,27 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe['amount'] = amount print(f"amount= {amount}") - # trades = Trade.get_trades([Trade.is_open is False]).all() - trades = Trade.get_trades_proxy(is_open=False, pair=metadata['pair']) - if trades: - trade = trades[-1] - print('closed trade pair is : ') - print(trade) - dataframe['expected_profit'] = (1 + self.expectedProfit(pair, dataframe.iloc[-1])) * dataframe[ - 'last_price'] - dataframe['lbp'] = dataframe['last_price'] - dataframe['lbp_3'] = dataframe['lbp'] * 0.97 # 3 - dataframe['lbp_6'] = dataframe['lbp'] * 0.94 # 6 - dataframe['lbp_9'] = dataframe['lbp'] * 0.90 # 10 - dataframe['lbp_12'] = dataframe['lbp'] * 0.85 # 15 - dataframe['lbp_20'] = dataframe['lbp'] * 0.8 # 20 - dataframe['fbp'] = trade.open_rate - # else: - # last_trade = self.get_trades(pair=pair).order_by('-close_date').first() - # filled_buys = last_trade.select_filled_orders('buy') - # print(last_trade) - # for buy in filled_buys: - # print(filled_buys) + # # trades = Trade.get_trades([Trade.is_open is False]).all() + # trades = Trade.get_trades_proxy(is_open=False, pair=metadata['pair']) + # if trades: + # trade = trades[-1] + # print('closed trade pair is : ') + # print(trade) + # dataframe['expected_profit'] = (1 + self.expectedProfit(pair, dataframe.iloc[-1])) * dataframe[ + # 'last_price'] + # dataframe['lbp'] = dataframe['last_price'] + # dataframe['lbp_3'] = dataframe['lbp'] * 0.97 # 3 + # dataframe['lbp_6'] = dataframe['lbp'] * 0.94 # 6 + # dataframe['lbp_9'] = dataframe['lbp'] * 0.90 # 10 + # dataframe['lbp_12'] = dataframe['lbp'] * 0.85 # 15 + # dataframe['lbp_20'] = dataframe['lbp'] * 0.8 # 20 + # dataframe['fbp'] = trade.open_rate + # # else: + # # last_trade = self.get_trades(pair=pair).order_by('-close_date').first() + # # filled_buys = last_trade.select_filled_orders('buy') + # # print(last_trade) + # # for buy in filled_buys: + # # print(filled_buys) dataframe['buy_level'] = dataframe['lowest_4_average'] * (1 - self.levels[count_buys] / 100) # ---------------------------------------------------------- @@ -615,7 +508,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe['amplitude_pct_60'] = dataframe['amplitude_pct'].rolling(60).sum() # ---------------------------------------------------------- - self.getBinanceOrderBook(pair, dataframe) + # self.getBinanceOrderBook(pair, dataframe) return dataframe @@ -641,9 +534,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): expected_profit = self.expectedProfit(pair, dataframe.iloc[-1]) # self.getBinanceOrderBook(pair, dataframe) last_candle = dataframe.iloc[-1].squeeze() - # limit = last_candle['first_price'] * (1 - self.baisse[last_candle['count_buys']] / 100) - # self.updateLastValue(dataframe, 'expected_profit', expected_profit) print("---------------" + pair + "----------------") print('adjust stake amount ' + str(self.adjust_stake_amount(pair, dataframe.iloc[-1]))) # print('adjust exit price ' + str(self.adjust_exit_price(dataframe.iloc[-1]))) @@ -772,13 +663,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): & (dataframe['min50'].shift(3) == dataframe['min50']) & (dataframe['close'] <= dataframe['min50'] * 1.002) ), ['enter_long', 'enter_tag']] = (1, 'buy_close_02') - # dataframe.loc[ - # ( - # (dataframe['close'] <= dataframe['lowest_4_average'] * 1.002) - # & (dataframe['haopen'] >= dataframe['lbp_3']) - # & (dataframe['haclose'] <= dataframe['lbp_3']) - # & (dataframe['haopen'] < buy_level) - # ), ['enter_long', 'enter_tag']] = (1, 'buy_lbp_3') + dataframe.loc[ ( (dataframe['close'] <= dataframe['lowest_4_average'] * 1.002) @@ -801,38 +686,26 @@ class Zeus_8_3_2_B_4_2(IStrategy): return dataframe - # def get_buy_level(self, pair, dataframe): - # limit = get_limit_from_config('Achats', pair) - # - # filled_buys = {} - # for trade in self.trades: - # if trade.pair != pair: - # continue - # filled_buys = trade.select_filled_orders('enter_long') - # print('populate_buy_trend filled_buys : ' + str(len(filled_buys))) - # # Affichez les valeurs - # print(pair, limit) - # # BUY_LEVELS = { - # # 'BTC/USDT': [int(btc_limit), 42600, 41000, 40000, 39000, 38000, 37000, 36000, 35000], - # # 'ETH/USDT': [int(eth_limit), 2290, 1900, 1800, 1700, 1600, 1500, 1400, 1300], - # # 'ETC/USDT': [int(eth_limit), 2290, 1900, 1800, 1700, 1600, 1500, 1400, 1300], - # # 'DOGE/USDT': [int(eth_limit), 2290, 1900, 1800, 1700, 1600, 1500, 1400, 1300], - # # # Ajoutez d'autres paires avec leurs niveaux d'achat ici... - # # } - # count_of_buys = len(filled_buys) - # buy_level = dataframe['lbp'] * (1 - self.levels[count_of_buys] / 100) # float(limit) #BUY_LEVELS.get(pair, [])[0] #dataframe['lbp_3'] #" - # return buy_level - def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: return dataframe def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, min_stake: float, max_stake: float, **kwargs): + # ne rien faire si ordre deja en cours + if trade.has_open_orders: + return None + if (self.wallets.get_available_stake_amount() < 50): # or trade.stake_amount >= max_stake: + return 0 + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) - # print(dataframe) last_candle = dataframe.iloc[-1].squeeze() - last_candle_12 = dataframe.iloc[-13].squeeze() + # prépare les données + count_of_buys = trade.nr_of_successful_entries + current_time = current_time.astimezone(timezone.utc) + open_date = trade.open_date.astimezone(timezone.utc) + dispo = round(self.wallets.get_available_stake_amount()) + hours = (current_time - trade.date_last_filled_utc).total_seconds() / 3600.0 if (len(dataframe) < 1): return None @@ -851,25 +724,24 @@ class Zeus_8_3_2_B_4_2(IStrategy): # else: # condition = False # self.protection_nb_buy_lost.value - # limits = ['lbp_3', 'lbp_6', 'lbp_9', 'lbp_12', 'lbp_20'] - # limit = last_candle[limits[count_of_buys]] limit = last_candle['limit'] stake_amount = min(200, self.adjust_stake_amount(pair, last_candle) * self.fibo[count_of_buys]) - # print("Adjust " + trade.pair + " time=" + str(current_time) + ' rate=' + str(current_rate) + " buys=" + str(count_of_buys) + " limit=" + str(limit) + " stake=" + str(stake_amount)) - # logger.info( - # f"Adjust price={trade.pair} buy={condition} rate={current_rate:.4f} buys={count_of_buys} limit={limit:.4f} stake={stake_amount:.4f}") current_time_utc = current_time.astimezone(timezone.utc) open_date = trade.open_date.astimezone(timezone.utc) days_since_open = (current_time_utc - open_date).days - if (days_since_open > count_of_buys) & (0 < count_of_buys <= max_buys) & (current_rate <= limit) & (last_candle['enter_long'] == 1): + # if (days_since_open > count_of_buys) & (0 < count_of_buys <= max_buys) & (current_rate <= limit) & (last_candle['enter_long'] == 1): + limit_buy = 5 + if (count_of_buys < limit_buy) \ + and ((last_candle['enter_long'] == 1) or last_candle['percent48'] < - 0.03) \ + and (current_profit < -0.015 * count_of_buys) \ + and (last_candle['enter_long'] == 1): try: # This then calculates current safety order size # stake_amount = stake_amount * pow(1.5, count_of_buys) - # print("Effective Adjust " + trade.pair + " time=" + str(current_time) + ' rate=' + str(current_rate) + " buys=" + str(count_of_buys) + " limit=" + str(limit) + " stake=" + str(stake_amount)) - logger.info( + print( f"Adjust {current_time} price={trade.pair} rate={current_rate:.4f} buys={count_of_buys} limit={limit:.4f} stake={stake_amount:.4f}") return stake_amount @@ -901,7 +773,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): # max_min = max_14_days / min_14_days # Stack amount ajusté price=2473.47 min_max=0.15058074985054215 percent=0.8379141364642171 amount=20.0 - adjusted_stake_amount = max(base_stake_amount / 2.5, min(75, base_stake_amount * percent_4)) + adjusted_stake_amount = max(base_stake_amount / 2.5, min(100, base_stake_amount * percent_4)) # if pair in ('BTC/USDT', 'ETH/USDT'): # if percent_4 > 0.5: # adjusted_stake_amount = 300 @@ -927,17 +799,17 @@ class Zeus_8_3_2_B_4_2(IStrategy): # # return exit_price - def adjust_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, - current_rate: float, current_profit: float, **kwargs) -> float: - dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) - # print(dataframe) - last_candle = dataframe.iloc[-1].squeeze() - - # Utiliser l'ATR pour ajuster le stoploss - atr_stoploss = current_rate - (last_candle['atr'] * 1.5) # Stoploss à 1.5x l'ATR - - # Retourner le stoploss dynamique en pourcentage du prix actuel - return (atr_stoploss / current_rate) - 1 + # def adjust_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + # current_rate: float, current_profit: float, **kwargs) -> float: + # dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + # # print(dataframe) + # last_candle = dataframe.iloc[-1].squeeze() + # + # # Utiliser l'ATR pour ajuster le stoploss + # atr_stoploss = current_rate - (last_candle['atr'] * 1.5) # Stoploss à 1.5x l'ATR + # + # # Retourner le stoploss dynamique en pourcentage du prix actuel + # return (atr_stoploss / current_rate) - 1 def expectedProfit(self, pair: str, dataframe: DataFrame):