Empty logtrade

This commit is contained in:
Jérôme Delacotte
2026-02-24 13:36:48 +01:00
parent a09189064e
commit 91bf3ca8ae

258
Empty.py
View File

@@ -22,11 +22,21 @@ import freqtrade.vendor.qtpylib.indicators as qtpylib
from functools import reduce from functools import reduce
from random import shuffle from random import shuffle
import logging
logger = logging.getLogger(__name__)
# Couleurs ANSI de base
RED = "\033[31m"
GREEN = "\033[32m"
YELLOW = "\033[33m"
BLUE = "\033[34m"
MAGENTA = "\033[35m"
CYAN = "\033[36m"
RESET = "\033[0m"
timeperiods = [3, 5, 12, 24, 48, 60] timeperiods = [3, 5, 12, 24, 48, 60]
score_indicators = list() score_indicators = list()
stop_buying_indicators = list()
god_genes_with_timeperiod = list() god_genes_with_timeperiod = list()
for timeperiod in timeperiods: for timeperiod in timeperiods:
# god_genes_with_timeperiod.append(f'max{timeperiod}') # god_genes_with_timeperiod.append(f'max{timeperiod}')
@@ -36,10 +46,6 @@ for timeperiod in timeperiods:
god_genes_with_timeperiod.append(f"sma{timeperiod}_deriv1") god_genes_with_timeperiod.append(f"sma{timeperiod}_deriv1")
god_genes_with_timeperiod.append(f"sma{timeperiod}_deriv2") god_genes_with_timeperiod.append(f"sma{timeperiod}_deriv2")
god_genes_with_timeperiod.append(f"sma{timeperiod}_score") god_genes_with_timeperiod.append(f"sma{timeperiod}_score")
# stoploss_indicators.append(f"stop_buying{timeperiod}")
stop_buying_indicators.append(f"stop_buying{timeperiod}_1d")
score_indicators.append(f"sma{timeperiod}_score") score_indicators.append(f"sma{timeperiod}_score")
# score_indicators.append(f"sma{timeperiod}_score_1d") # score_indicators.append(f"sma{timeperiod}_score_1d")
@@ -48,7 +54,6 @@ for timeperiod in timeperiods:
# god_genes_with_timeperiod.append(f"sma{timeperiod}_trend_change_up") # god_genes_with_timeperiod.append(f"sma{timeperiod}_trend_change_up")
# god_genes_with_timeperiod.append(f"sma{timeperiod}_trend_change_down") # god_genes_with_timeperiod.append(f"sma{timeperiod}_trend_change_down")
print(stop_buying_indicators)
operators = [ operators = [
"D", # Disabled gene "D", # Disabled gene
@@ -283,6 +288,7 @@ class Empty(IStrategy):
# Number of candles the strategy requires before producing valid signals # Number of candles the strategy requires before producing valid signals
startup_candle_count: int = 30 startup_candle_count: int = 30
columns_logged = False
pairs = { pairs = {
pair: { pair: {
@@ -388,8 +394,6 @@ class Empty(IStrategy):
drop_from_last_entry = DecimalParameter(-0.1, 0, decimals=2, default=-0.025, space='protection') drop_from_last_entry = DecimalParameter(-0.1, 0, decimals=2, default=-0.025, space='protection')
range_pos_stoploss = DecimalParameter(0, 0.1, decimals=2, default=0.05, 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_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(stop_buying_indicators, default="stop_buying12_1d", space='protection')
# stoploss_timeperiod = CategoricalParameter(timeperiods, default="12", space='protection') # stoploss_timeperiod = CategoricalParameter(timeperiods, default="12", space='protection')
@@ -478,12 +482,31 @@ class Empty(IStrategy):
drop_from_last_entry = (current_rate - last_entry_price) / last_entry_price drop_from_last_entry = (current_rate - last_entry_price) / last_entry_price
if drop_from_last_entry <= self.drop_from_last_entry.value and last_candle['min60'] == last_candle_3['min60'] \ if drop_from_last_entry <= self.drop_from_last_entry.value and last_candle['min60'] == last_candle_3['min60'] \
and (last_candle[self.stop_buying_indicator.value] == False or (last_candle['range_pos'] < 0))\ and (last_candle['range_pos'] < 0)\
and last_candle['hapercent'] > 0: and last_candle['hapercent'] > 0:
# stake_amount = trade.stake_amount # stake_amount = trade.stake_amount
self.pairs[trade.pair]['last_buy'] = current_rate 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}")
print(f"adjust {pair} {current_time} dispo={dispo} amount={stake_amount} rate={current_rate}")
trade_type = last_candle['enter_tag'] if last_candle['enter_long'] == 1 else 'pct48'
self.pairs[trade.pair]['count_of_buys'] += 1
self.pairs[pair]['total_amount'] += stake_amount
self.log_trade(
last_candle=last_candle,
date=current_time,
action="🟧 Loss -",
dispo=dispo,
pair=trade.pair,
rate=current_rate,
trade_type=trade_type,
profit=round(profit, 1),
buys=trade.nr_of_successful_entries + 1,
stake=round(stake_amount, 2)
)
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 stake_amount return stake_amount
return None return None
@@ -539,27 +562,26 @@ class Empty(IStrategy):
self.pairs[pair]['last_min'] = min(last_candle['close'], self.pairs[pair]['last_min']) self.pairs[pair]['last_min'] = min(last_candle['close'], self.pairs[pair]['last_min'])
self.pairs[pair]['last_date'] = current_time self.pairs[pair]['last_date'] = current_time
dispo = round(self.wallets.get_available_stake_amount()) dispo = round(self.wallets.get_available_stake_amount())
# self.printLineLog() # self.printLineLog()
stake_amount = self.adjust_stake_amount(pair, last_candle) stake_amount = self.adjust_stake_amount(pair, last_candle)
self.pairs[pair]['first_amount'] = stake_amount self.pairs[pair]['first_amount'] = stake_amount
self.pairs[pair]['total_amount'] = stake_amount self.pairs[pair]['total_amount'] = stake_amount
print(f"Buy {pair} {current_time} {entry_tag} dispo={dispo} amount={stake_amount} rate={rate} rate={rate}") # print(f"Buy {pair} {current_time} {entry_tag} dispo={dispo} amount={stake_amount} rate={rate} rate={rate}")
# self.log_trade( self.log_trade(
# last_candle=last_candle, last_candle=last_candle,
# date=current_time, date=current_time,
# action=("🟩Buy" if allow_to_buy else "Canceled") + " " + str(minutes), action=("🟩Buy" if allow_to_buy else "Canceled") + " " + str(minutes),
# pair=pair, pair=pair,
# rate=rate, rate=rate,
# dispo=dispo, dispo=dispo,
# profit=0, profit=0,
# trade_type=entry_tag, trade_type=entry_tag,
# buys=1, buys=1,
# stake=round(stake_amount, 2) stake=round(stake_amount, 2)
# ) )
return allow_to_buy return allow_to_buy
@@ -584,17 +606,17 @@ class Empty(IStrategy):
profit = trade.calc_profit(rate) profit = trade.calc_profit(rate)
self.pairs[pair]['previous_profit'] = profit self.pairs[pair]['previous_profit'] = profit
dispo = round(self.wallets.get_available_stake_amount()) dispo = round(self.wallets.get_available_stake_amount())
print(f"Sell {pair} {current_time} {exit_reason} dispo={dispo} rate={rate} open_rate={trade.open_rate} profit={profit}") # print(f"Sell {pair} {current_time} {exit_reason} dispo={dispo} rate={rate} open_rate={trade.open_rate} profit={profit}")
# self.log_trade( self.log_trade(
# last_candle=last_candle, last_candle=last_candle,
# date=current_time, date=current_time,
# action="🟥Sell " + str(minutes), action="🟥Sell " + str(minutes),
# pair=pair, pair=pair,
# trade_type=exit_reason, trade_type=exit_reason,
# rate=last_candle['close'], rate=last_candle['close'],
# dispo=dispo, dispo=dispo,
# profit=round(profit, 2) profit=round(profit, 2)
# ) )
self.pairs[pair]['first_amount'] = 0 self.pairs[pair]['first_amount'] = 0
self.pairs[pair]['force_sell'] = False self.pairs[pair]['force_sell'] = False
self.pairs[pair]['has_gain'] = 0 self.pairs[pair]['has_gain'] = 0
@@ -618,6 +640,11 @@ class Empty(IStrategy):
self.pairs[pair]['current_trade'] = trade self.pairs[pair]['current_trade'] = trade
momentum = last_candle[self.sell_score_indicator.value] momentum = last_candle[self.sell_score_indicator.value]
# if self.pairs[pair]['force_sell'] and self.pairs[pair]['last_trade'].close_profit > 0.02:
# return "Force"
if last_candle['stop_buying']:
self.pairs[pair]['force_sell'] = True
return 'Stop'
# Si momentum fort → on laisse courir # Si momentum fort → on laisse courir
if momentum > 1: if momentum > 1:
return None return None
@@ -637,10 +664,11 @@ class Empty(IStrategy):
candle_at_buy = self.pairs[pair]['last_candle'] 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: # if profit < - 100 :
return self.stoploss_force.value # print("stop loss detected")
# self.pairs[pair]['force_sell'] = True
# return 0
# # 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 : # 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_min = last_candle[f"min{self.stoploss_timeperiod.value}_1d"]
# range_max = last_candle[f"max{self.stoploss_timeperiod.value}_1d"] # range_max = last_candle[f"max{self.stoploss_timeperiod.value}_1d"]
@@ -682,7 +710,7 @@ class Empty(IStrategy):
dataframe['haclose'] = heikinashi['close'] dataframe['haclose'] = heikinashi['close']
dataframe['hapercent'] = (dataframe['haclose'] - dataframe['haopen']) / dataframe['haclose'] dataframe['hapercent'] = (dataframe['haclose'] - dataframe['haopen']) / dataframe['haclose']
dataframe['mid'] = dataframe['haopen'] + (dataframe['haclose'] - dataframe['haopen']) / 2 dataframe['mid'] = dataframe['haopen'] + (dataframe['haclose'] - dataframe['haopen']) / 2
dataframe['zero'] = 0; dataframe['zero'] = 0
for timeperiod in timeperiods: for timeperiod in timeperiods:
dataframe[f'max{timeperiod}'] = talib.MAX(dataframe['close'], timeperiod=timeperiod) dataframe[f'max{timeperiod}'] = talib.MAX(dataframe['close'], timeperiod=timeperiod)
@@ -691,19 +719,6 @@ class Empty(IStrategy):
dataframe[f"sma{timeperiod}"] = dataframe['mid'].ewm(span=timeperiod, adjust=False).mean() dataframe[f"sma{timeperiod}"] = dataframe['mid'].ewm(span=timeperiod, adjust=False).mean()
self.calculeDerivees(dataframe, f"sma{timeperiod}", timeframe=self.timeframe, ema_period=timeperiod) self.calculeDerivees(dataframe, f"sma{timeperiod}", timeframe=self.timeframe, ema_period=timeperiod)
dataframe[f'stop_buying{timeperiod}_deb'] = (dataframe[f'sma{timeperiod}_trend_change_down'] == 1)
dataframe[f'stop_buying{timeperiod}_end'] = (dataframe[f'sma{timeperiod}_trend_change_up'] == 1)
latched = np.zeros(len(dataframe), dtype=bool)
for i in range(1, len(dataframe)):
if dataframe[f'stop_buying{timeperiod}_deb'].iloc[i]:
latched[i] = True
elif dataframe[f'stop_buying{timeperiod}_end'].iloc[i]:
latched[i] = False
else:
latched[i] = latched[i - 1]
dataframe[f'stop_buying{timeperiod}'] = latched
# ###################################################################################################### # ######################################################################################################
################### INFORMATIVE 1d ################### INFORMATIVE 1d
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d")
@@ -721,27 +736,16 @@ class Empty(IStrategy):
informative[f"sma{timeperiod}"] = informative['mid'].ewm(span=timeperiod, adjust=False).mean() informative[f"sma{timeperiod}"] = informative['mid'].ewm(span=timeperiod, adjust=False).mean()
self.calculeDerivees(informative, f"sma{timeperiod}", timeframe=self.timeframe, ema_period=timeperiod) self.calculeDerivees(informative, f"sma{timeperiod}", timeframe=self.timeframe, ema_period=timeperiod)
informative[f'stop_buying_deb{timeperiod}'] = (informative[f'sma{timeperiod}_trend_change_down'] == 1)
informative[f'stop_buying_end{timeperiod}'] = (informative[f'sma{timeperiod}_trend_change_up'] == 1)
latched = np.zeros(len(informative), dtype=bool)
for i in range(1, len(informative)):
if informative[f'stop_buying_deb{timeperiod}'].iloc[i]:
latched[i] = True
elif informative[f'stop_buying_end{timeperiod}'].iloc[i]:
latched[i] = False
else:
latched[i] = latched[i - 1]
informative[f'stop_buying{timeperiod}'] = latched
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True)
# ###################################################################################################### # ######################################################################################################
range_min = dataframe[f"min12_1d"] range_min = dataframe[f"min24_1d"]
range_max = dataframe[f"max48"] range_max = dataframe[f"max48"]
dataframe[f"range_pos"] = ((dataframe['mid'] - range_min) / (range_max)).rolling(5).mean() dataframe[f"range_pos"] = ((dataframe['mid'] - range_min) / (range_max)).rolling(5).mean()
dataframe[f'stop_buying'] = qtpylib.crossed_below(dataframe[f"sma12"], dataframe['sma48'])
# récupérer le dernier trade fermé # récupérer le dernier trade fermé
trades = Trade.get_trades_proxy(pair=pair,is_open=False) trades = Trade.get_trades_proxy(pair=pair,is_open=False)
@@ -806,11 +810,11 @@ class Empty(IStrategy):
# buy_real_num # buy_real_num
# ) # )
# conditions.append(condition) # conditions.append(condition)
conditions.append((dataframe[self.stop_buying_indicator.value] == False) | (dataframe['range_pos'] < 0)) # 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"range_pos"] <= 0.5)
# conditions.append((dataframe[f"range_pos"] < 0.01) | ((dataframe[f"sma5_deriv1"] > 0) & (dataframe[f"sma12_deriv1"] > 0) & (dataframe[f"sma24_deriv1"] > 0))) conditions.append(((dataframe[f"range_pos"] < 0.05) ) | ((dataframe['sma12_deriv1'] > 0) & (dataframe['sma12_deriv2'] > 0)))
print(f"BUY indicators tested \n" 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" f"{self.buy_indicator0.value} {self.buy_crossed_indicator0.value} {self.buy_operator0.value} {self.buy_real_num0.value} \n"
@@ -993,6 +997,109 @@ class Empty(IStrategy):
# } # }
] ]
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' or self.dp.runmode.value in ('hyperopt'):
return
if self.columns_logged % 10 == 0:
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"
)
self.printLineLog()
df = pd.DataFrame.from_dict(self.pairs, orient='index')
colonnes_a_exclure = ['last_candle',
'trade_info', 'last_date', 'last_count_of_buys', 'base_stake_amount', 'stop_buy']
df_filtered = df[df['count_of_buys'] > 0].drop(columns=colonnes_a_exclure)
# df_filtered = df_filtered["first_buy", "last_max", "max_touch", "last_sell","last_buy", 'count_of_buys', 'current_profit']
print(df_filtered)
self.columns_logged += 1
date = str(date)[:16] if date else "-"
limit = None
# if buys is not None:
# limit = round(last_rate * (1 - self.fibo[buys] / 100), 4)
rsi = ''
rsi_pct = ''
# if last_candle is not None:
# if (not np.isnan(last_candle['rsi_1d'])) and (not np.isnan(last_candle['rsi_1h'])):
# rsi = str(int(last_candle['rsi_1d'])) + " " + str(int(last_candle['rsi_1h']))
# if (not np.isnan(last_candle['rsi_pct_1d'])) and (not np.isnan(last_candle['rsi_pct_1h'])):
# rsi_pct = str(int(10000 * last_candle['bb_mid_pct_1d'])) + " " + str(
# int(last_candle['rsi_pct_1d'])) + " " + str(int(last_candle['rsi_pct_1h']))
# first_rate = self.percent_threshold.value
# last_rate = self.threshold.value
# action = self.color_line(action, action)
sma5_1d = ''
sma5_1h = ''
sma5 = str(sma5_1d) + ' ' + str(sma5_1h)
last_lost = self.getLastLost(last_candle, pair)
if buys is None:
buys = ''
max_touch = '' # round(last_candle['max12_1d'], 1) #round(self.pairs[pair]['max_touch'], 1)
pct_max = self.getPctFirstBuy(pair, last_candle)
total_counts = str(buys) + '/' + str(sum(pair_data['count_of_buys'] for pair_data in self.pairs.values()))
dist_max = self.getDistMax(last_candle, pair)
# if trade_type is not None:
# if np.isnan(last_candle['rsi_1d']):
# string = ' '
# else:
# string = (str(int(last_candle['rsi_1d']))) + " " + str(int(last_candle['rsi_deriv1_1d']))
# trade_type = trade_type \
# + " " + string \
# + " " + str(int(last_candle['rsi_1h'])) \
# + " " + str(int(last_candle['rsi_deriv1_1h']))
# val144 = self.getProbaHausse144(last_candle)
# val1h = self.getProbaHausse1h(last_candle)
color = GREEN if profit > 0 else RED
# color_sma24 = GREEN if last_candle['sma24_deriv1_1d'] > 0 else RED
# color_sma24_2 = GREEN if last_candle['sma24_deriv2_1d'] > 0 else RED
# color_sma5 = GREEN if last_candle['mid_smooth_5_deriv1_1d'] > 0 else RED
# color_sma5_2 = GREEN if last_candle['mid_smooth_5_deriv2_1d'] > 0 else RED
# color_sma5_1h = GREEN if last_candle['sma60_deriv1'] > 0 else RED
# color_sma5_2h = GREEN if last_candle['sma60_deriv2'] > 0 else RED
# color_smooth_1h = GREEN if last_candle['mid_smooth_1h_deriv1'] > 0 else RED
# color_smooth2_1h = GREEN if last_candle['mid_smooth_1h_deriv2'] > 0 else RED
last_max = int(self.pairs[pair]['last_max']) if self.pairs[pair]['last_max'] > 1 else round(
self.pairs[pair]['last_max'], 3)
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))
# 🟢 Dérivée 1 > 0 et dérivée 2 > 0: tendance haussière qui saccélère.
# 🟡 Dérivée 1 > 0 et dérivée 2 < 0: tendance haussière qui ralentit → essoufflement potentiel.
# 🔴 Dérivée 1 < 0 et dérivée 2 < 0: tendance baissière qui saccélère.
# 🟠 Dérivée 1 < 0 et dérivée 2 > 0: tendance baissière qui ralentit → possible bottom.
self.printLog(
f"| {date:<16} |{action:<10} | {pair[0:3]:<3} | {trade_type or '-':<18} |{rate or '-':>9}| {dispo or '-':>6} "
f"|{color}{profit or '-':>10}{RESET}| {pct_max or '-':>6} | {round(self.pairs[pair]['max_touch'], 2) or '-':>11} | {last_lost or '-':>12} "
f"| {last_max or '-':>7} | {last_min or '-':>7} |{total_counts or '-':>5}|{stake or '-':>7}"
)
def printLineLog(self):
# f"sum1h|sum1d|Tdc|Tdh|Tdd| drv1 |drv_1h|drv_1d|"
self.printLog(
f"+{'-' * 18}+{'-' * 12}+{'-' * 5}+{'-' * 20}+{'-' * 9}+{'-' * 8}+{'-' * 12}+{'-' * 8}+{'-' * 13}+{'-' * 14}+{'-' * 9}{'-' * 9}+{'-' * 5}+{'-' * 7}+"
f"+{'-' * 6}+{'-' * 7}+{'-' * 5}+{'-' * 5}+{'-' * 5}+{'-' * 5}+{'-' * 5}+{'-' * 5}+"
)
def printLog(self, str): def printLog(self, str):
if self.config.get('runmode') == 'hyperopt' or self.dp.runmode.value in ('hyperopt'): if self.config.get('runmode') == 'hyperopt' or self.dp.runmode.value in ('hyperopt'):
return; return;
@@ -1001,3 +1108,18 @@ class Empty(IStrategy):
else: else:
if not self.dp.runmode.value in ('hyperopt'): if not self.dp.runmode.value in ('hyperopt'):
print(str) print(str)
def getLastLost(self, last_candle, pair):
last_lost = round((last_candle['close'] - self.pairs[pair]['max_touch']) / self.pairs[pair]['max_touch'], 3)
return last_lost
def getDistMax(self, last_candle, pair):
mx = last_candle['max12_1d']
dist_max = round(100 * (mx - last_candle['close']) / mx, 0)
return dist_max
def getPctFirstBuy(self, pair, last_candle):
return round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'], 3)
def getPctLastBuy(self, pair, last_candle):
return round((last_candle['close'] - self.pairs[pair]['last_buy']) / self.pairs[pair]['last_buy'], 4)