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

┃ Strategy ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃     Avg Duration ┃  Win  Draw  Loss  Win% ┃             Drawdown ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━┩
│    Empty │     92 │         1.62 │        2474.507 │       247.45 │ 3 days, 23:07:00 │   45     0    47  48.9 │ 359.078 USDT  10.66% │
└──────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────────┴────────────────────────┴──────────────────────┘
This commit is contained in:
Jérôme Delacotte
2026-02-26 23:15:00 +01:00
parent 26aa1ea32b
commit 42832df325
3 changed files with 198 additions and 106 deletions

View File

@@ -14,15 +14,16 @@
"trailing_only_offset_is_reached": false "trailing_only_offset_is_reached": false
}, },
"max_open_trades": { "max_open_trades": {
"max_open_trades": 20 "max_open_trades": 1
}, },
"buy": { "buy": {
"buy_deriv1_sma12d": -0.06, "buy_deriv1_sma12d": -0.05,
"buy_deriv1_sma5d": -0.01, "buy_deriv1_sma5d": -0.03,
"buy_deriv1_sma60": -0.003, "buy_deriv1_sma60": 0.0,
"buy_deriv2_sma12d": 0.0, "buy_deriv2_sma12d": 0.0,
"buy_deriv2_sma5d": -0.07, "buy_deriv2_sma5d": -0.07,
"buy_deriv2_sma60": -0.004 "buy_deriv2_sma60": -0.003,
"buy_longue": 200
}, },
"protection": { "protection": {
"drop_from_last_entry": 0.0 "drop_from_last_entry": 0.0
@@ -34,5 +35,5 @@
} }
}, },
"ft_stratparam_v": 1, "ft_stratparam_v": 1,
"export_time": "2026-02-25 18:15:42.432169+00:00" "export_time": "2026-02-26 20:23:41.717021+00:00"
} }

View File

@@ -36,6 +36,7 @@ CYAN = "\033[36m"
RESET = "\033[0m" RESET = "\033[0m"
timeperiods = [3, 5, 12, 24, 36, 48, 60] timeperiods = [3, 5, 12, 24, 36, 48, 60]
long_timeperiods = [80, 100, 120, 140, 160, 180, 200]
sma_indicators = list() sma_indicators = list()
score_indicators = list() score_indicators = list()
@@ -256,9 +257,6 @@ def condition_generator(dataframe, operator, indicator, crossed_indicator, real_
return condition, dataframe return condition, dataframe
# ######################################################################################################################### # #########################################################################################################################
# This class is a sample. Feel free to customize it. # This class is a sample. Feel free to customize it.
class Empty(IStrategy): class Empty(IStrategy):
@@ -366,13 +364,15 @@ class Empty(IStrategy):
} }
} }
buy_deriv1_sma60 = DecimalParameter(-0.005, 0.005, decimals=3, default=0, space='buy') buy_deriv1_sma60 = DecimalParameter(-0.005, 0.005, decimals=3, default=0, space='buy', optimize=False, load=True)
buy_deriv1_sma5d = DecimalParameter(-0.07, 0.07, decimals=2, default=0, space='buy') buy_deriv1_sma5d = DecimalParameter(-0.07, 0.07, decimals=2, default=0, space='buy', optimize=False, load=True)
buy_deriv1_sma12d = DecimalParameter(-0.07, 0.07, decimals=2, default=0, space='buy') buy_deriv1_sma12d = DecimalParameter(-0.07, 0.07, decimals=2, default=0, space='buy', optimize=False, load=True)
buy_deriv2_sma60 = DecimalParameter(-0.005, 0.005, decimals=3, default=0, space='buy') buy_deriv2_sma60 = DecimalParameter(-0.005, 0.005, decimals=3, default=0, space='buy', optimize=False, load=True)
buy_deriv2_sma5d = DecimalParameter(-0.07, 0.07, decimals=2, default=0, space='buy') buy_deriv2_sma5d = DecimalParameter(-0.07, 0.07, decimals=2, default=0, space='buy', optimize=False, load=True)
buy_deriv2_sma12d = DecimalParameter(-0.07, 0.07, decimals=2, default=0, space='buy') buy_deriv2_sma12d = DecimalParameter(-0.07, 0.07, decimals=2, default=0, space='buy', optimize=False, load=True)
buy_longue = CategoricalParameter(long_timeperiods, default=120, space='buy')
# Buy Hyperoptable Parameters/Spaces. # Buy Hyperoptable Parameters/Spaces.
# buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy') # buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy')
@@ -851,7 +851,8 @@ 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"sma200"] = informative['mid'].ewm(span=200, adjust=False).mean() for timeperiod in long_timeperiods:
informative[f"sma{timeperiod}"] = informative['mid'].ewm(span=timeperiod, adjust=False).mean()
informative['rsi'] = talib.RSI(informative['close'], timeperiod=14) informative['rsi'] = talib.RSI(informative['close'], timeperiod=14)
self.calculeDerivees(informative, f"rsi", timeframe=self.timeframe, ema_period=14) self.calculeDerivees(informative, f"rsi", timeframe=self.timeframe, ema_period=14)
informative['max_rsi_12'] = talib.MAX(informative['rsi'], timeperiod=12) informative['max_rsi_12'] = talib.MAX(informative['rsi'], timeperiod=12)
@@ -874,6 +875,11 @@ class Empty(IStrategy):
dataframe['max_rsi_12'] = talib.MAX(dataframe['rsi'], timeperiod=12) dataframe['max_rsi_12'] = talib.MAX(dataframe['rsi'], timeperiod=12)
dataframe['max_rsi_24'] = talib.MAX(dataframe['rsi'], timeperiod=24) dataframe['max_rsi_24'] = talib.MAX(dataframe['rsi'], timeperiod=24)
dataframe["dist_sma200_1d"] = (
(dataframe["close_1d"] - dataframe["sma200_1d"])
/ dataframe["sma200_1d"]
)
# 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)
if trades: if trades:
@@ -953,7 +959,9 @@ class Empty(IStrategy):
# conditions.append(dataframe['percent12'] < 0.01) # conditions.append(dataframe['percent12'] < 0.01)
# conditions.append(dataframe['percent5'] < 0.01) # conditions.append(dataframe['percent5'] < 0.01)
conditions.append(dataframe['max_rsi_24'] < 80) conditions.append(dataframe['max_rsi_24'] < 80)
conditions.append((dataframe['max_rsi_12_1d'] < 65))\
dynamic_rsi_threshold = 70 + 15 * np.tanh(dataframe["dist_sma200_1d"] * 5)
conditions.append((dataframe['max_rsi_12_1d'] < dynamic_rsi_threshold))
# | ( # | (
# (dataframe['sma5_deriv1'] > 0) & (dataframe['sma12_deriv1'] > 0) & (dataframe['sma24_deriv1'] > 0) & ( # (dataframe['sma5_deriv1'] > 0) & (dataframe['sma12_deriv1'] > 0) & (dataframe['sma24_deriv1'] > 0) & (
# dataframe['sma48_deriv1'] > 0) & (dataframe['sma60_deriv1'] > 0) & (dataframe['sma5_deriv1_1d'] > 0)) # dataframe['sma48_deriv1'] > 0) & (dataframe['sma60_deriv1'] > 0) & (dataframe['sma5_deriv1_1d'] > 0))
@@ -962,7 +970,10 @@ class Empty(IStrategy):
conditions.append(dataframe[f"close"] > dataframe['sma60']) conditions.append(dataframe[f"close"] > dataframe['sma60'])
conditions.append(((dataframe[f"range_pos"] < 0.05) ) | ((dataframe['sma12_deriv1'] > 0) & (dataframe['sma12_deriv2'] > 0))) conditions.append(((dataframe[f"range_pos"] < 0.05) ) | ((dataframe['sma12_deriv1'] > 0) & (dataframe['sma12_deriv2'] > 0)))
conditions.append(dataframe['close_1d'] > dataframe['sma200_1d']) conditions.append(
(dataframe['close_1d'] > dataframe[f'sma{self.buy_longue.value}_1d'])
| (dataframe['sma60_inv_1d'] == -1)
)
# 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"

252
Empty.txt
View File

@@ -3,97 +3,177 @@
Même si le CAGR bouge légèrement, tout le reste saméliore fortement. Même si le CAGR bouge légèrement, tout le reste saméliore fortement.
📊 Comparaison claire 📊 Comparaison claire
Metric Avant Maintenant Metric Avant Maintenant
Trades 95 53 Trades 95 53
CAGR 21.38% 22.45% CAGR 21.38% 22.45%
Profit Factor 1.89 2.85 Profit Factor 1.89 2.85
SQN 1.87 2.38 SQN 1.87 2.38
Winrate 48% 62% Winrate 48% 62%
Max DD 21.97% 7.37% Max DD 21.97% 7.37%
DD duration 309 jours 28 jours DD duration 309 jours 28 jours
Calmar 7.08 22.51 Calmar 7.08 22.51
🔥 Ce que ça veut dire 🔥 Ce que ça veut dire
Le filtre structurel (SMA200 1D) a fait exactement ce quon attendait : Le filtre structurel (SMA200 1D) a fait exactement ce quon attendait :
Moins de trades Moins de trades
Beaucoup moins de trades pourris Beaucoup moins de trades pourris
Equity beaucoup plus lisse Equity beaucoup plus lisse
Bear market 2022 quasiment neutralisé Bear market 2022 quasiment neutralisé
Et surtout : Et surtout :
👉 Le drawdown long a disparu. 👉 Le drawdown long a disparu.
Cest LE point critique. Cest LE point critique.
🧠 Lecture professionnelle 🧠 Lecture professionnelle
Cette version est : Cette version est :
Plus robuste Plus robuste
Plus stable Plus stable
Plus exploitable en réel Plus exploitable en réel
Psychologiquement viable Psychologiquement viable
Un DD de 309 jours casse un trader. Un DD de 309 jours casse un trader.
Un DD de 28 jours est gérable. Un DD de 28 jours est gérable.
🎯 Ce qui est très intéressant 🎯 Ce qui est très intéressant
Regarde ça : Regarde ça :
Worst trade passe de -4.55% → -4.10% Worst trade passe de -4.55% → -4.10%
Profit factor explose à 2.85 Profit factor explose à 2.85
Expectancy 24.77 (énorme) Expectancy 24.77 (énorme)
Ça veut dire que : Ça veut dire que :
👉 Tu trades maintenant uniquement les phases vraiment favorables. 👉 Tu trades maintenant uniquement les phases vraiment favorables.
📉 Le “un peu moins de gain” 📉 Le “un peu moins de gain”
En réalité ton CAGR est même légèrement plus haut (22.45 vs 21.38). En réalité ton CAGR est même légèrement plus haut (22.45 vs 21.38).
Mais même si cétait un peu plus bas : Mais même si cétait un peu plus bas :
Réduire le drawdown de 22% à 7% vaut largement 23% de CAGR. Réduire le drawdown de 22% à 7% vaut largement 23% de CAGR.
Toujours. Toujours.
🧠 Ce que tu viens de faire 🧠 Ce que tu viens de faire Tu as transformé une stratégie Opportuniste en Régime-aware Et ça change tout.
Tu as transformé une stratégie :
Opportuniste
en
Régime-aware
Et ça change tout.
⚠️ Maintenant la vraie question ⚠️ Maintenant la vraie question
Veux-tu : Veux-tu :
🔬 Tester robustness (walk-forward) 🔬 Tester robustness (walk-forward)
📈 Ajouter un léger boost de performance 📈 Ajouter un léger boost de performance
⚖️ Ajouter un sizing adaptatif selon régime ⚖️ Ajouter un sizing adaptatif selon régime
🚀 Ajouter un second actif 🚀 Ajouter un second actif
Parce que là, on est à létape “optimisation fine”, plus “réparation”. Parce que là, on est à létape “optimisation fine”, plus “réparation”.
=============================================================================
Bon.
Là on va parler sérieusement 😄
Parce que tes résultats ne sont pas mauvais du tout.
📊 Lecture objective de ton backtest
✅ Points très solides
CAGR 35% sur 4 ans → très correct
Max DD 10.6% → excellent
Profit factor 1.86 → bon edge
Calmar 29 → extrêmement bon (drawdown très maîtrisé)
Max underwater 11% → propre
Pas dexplosion du risk
Franchement, cest une stratégie saine.
⚠️ Le vrai problème
Regarde ces deux chiffres :
Sharpe : 0.21
Sortino : 1.31
Sharpe très bas → equity curve irrégulière
Sortino correct → pertes contrôlées
Ce que ça dit :
Tu gagnes bien… mais de manière irrégulière.
🎯 Ce qui saute aux yeux
92 trades en 4 ans
Ça fait :
23 trades par an
Cest extrêmement peu.
Donc :
Quelques gros trades font la perf
Beaucoup de périodes mortes
Equity plate pendant longtemps
Ce nest pas un problème technique. Cest un problème structurel.
🧠Ce que ton système est en réalité Ce nest pas un trend following classique.
Cest Un breakout / impulsion filtrée daily
Regarde :
Best trade : +48%
Avg winner duration : 6 jours
Certains winners : 85 jours
Tu attrapes des swings longs.
Et tu survis entre deux cycles.
Cest cohérent.
🚨 Pourquoi tu as limpression que rien naméliore ?
Parce que tu es déjà dans un bon équilibre.
Quand une stratégie est :
Stable
Faible DD
PF proche de 2
👉 Les gains doptimisation deviennent marginaux.
Tu nes plus dans la phase “je corrige une erreur”.
Tu es dans la phase “je modifie lADN”.
🔍 Ce que je vois comme axe réel damélioration
Pas le stoploss.
Pas le RSI adaptatif.
Le vrai levier est ici :
Winrate = 48.9%
Tu es pile à léquilibre.
Si tu passes à 55% avec même RR,
ta courbe devient radicalement plus stable.
🎯 La vraie question
Tes losers durent :
1d 12h en moyenne.
Tes winners :
6d 12h.
Donc ton edge vient du R:R, pas du winrate.
💡 Deux directions possibles
OPTION 1 — Rendre le système plus agressif
Plus dentrées
Plus de trades
Légèrement plus de DD
Sharpe augmente
→ Transformer ton système en semi-trend.
OPTION 2 — Assumer que cest un cycle catcher
Et optimiser :
La sortie en fin de cycle
Le trailing dynamique
La protection en marché neutre
🎯 Analyse importante
Market change : +44%
Toi : +247%
Tu as largement surperformé le marché.
Donc ton edge est réel.
💬 Question importante
Tu veux :
A) Maximiser le CAGR
B) Maximiser la stabilité (Sharpe > 1)
C) Réduire encore le drawdown
D) Multiplier les trades
Parce que selon ton objectif, on ne touche pas aux mêmes leviers.
Et là tu es à un point où chaque modification change la philosophie du système.
SUMMARY METRICS SUMMARY METRICS
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
@@ -104,51 +184,51 @@ Parce que là, on est à létape “optimisation fine”, plus “réparation
│ Trading Mode │ Spot │ │ Trading Mode │ Spot │
│ Max open trades │ 1 │ │ Max open trades │ 1 │
│ │ │ │ │ │
│ Total/Daily Avg Trades │ 53 / 0.04 │ Total/Daily Avg Trades │ 92 / 0.06
│ Starting balance │ 1000 USDT │ │ Starting balance │ 1000 USDT │
│ Final balance │ 2312.665 USDT │ │ Final balance │ 3474.507 USDT │
│ Absolute profit │ 1312.665 USDT │ │ Absolute profit │ 2474.507 USDT │
│ Total profit % │ 131.27% │ │ Total profit % │ 247.45% │
│ CAGR % │ 22.45% │ │ CAGR % │ 35.10% │
│ Sortino │ 1.81 │ │ Sortino │ 1.31 │
│ Sharpe │ 0.22 │ Sharpe │ 0.21
│ Calmar │ 22.51 │ Calmar │ 29.34
│ SQN │ 2.38 │ SQN │ 1.76
│ Profit factor │ 2.85 │ Profit factor │ 1.86
│ Expectancy (Ratio) │ 24.77 (0.70) │ │ Expectancy (Ratio) │ 26.90 (0.44) │
│ Avg. daily profit │ 0.869 USDT │ │ Avg. daily profit │ 1.638 USDT │
│ Avg. stake amount │ 1534.128 USDT │ │ Avg. stake amount │ 2413.03 USDT
│ Total trade volume │ 164258.371 USDT │ │ Total trade volume │ 447365.827 USDT │
│ │ │ │ │ │
│ Best Pair │ BTC/USDT 131.27% │ │ Best Pair │ BTC/USDT 247.45% │
│ Worst Pair │ BTC/USDT 131.27% │ │ Worst Pair │ BTC/USDT 247.45% │
│ Best trade │ BTC/USDT 38.19% │ │ Best trade │ BTC/USDT 48.98% │
│ Worst trade │ BTC/USDT -4.10% │ │ Worst trade │ BTC/USDT -5.61% │
│ Best day │ 422.364 USDT │ │ Best day │ 806.579 USDT │
│ Worst day │ -51.652 USDT │ Worst day │ -137.268 USDT │
│ Days win/draw/lose │ 33 / 901 / 19 │ Days win/draw/lose │ 44 / 1328 / 47
│ Min/Max/Avg. Duration Winners │ 1d 03:00 / 28d 16:00 / 5d 13:35 │ Min/Max/Avg. Duration Winners │ 1d 03:00 / 85d 12:00 / 6d 12:21
│ Min/Max/Avg. Duration Losers │ 0d 01:00 / 6d 10:00 / 1d 13:21 │ Min/Max/Avg. Duration Losers │ 0d 02:00 / 5d 12:00 / 1d 12:28
│ Max Consecutive Wins / Loss │ 9 / 3 │ Max Consecutive Wins / Loss │ 4 / 4
│ Rejected Entry signals │ 0 │ │ Rejected Entry signals │ 0 │
│ Entry/Exit Timeouts │ 0 / 0 │ │ Entry/Exit Timeouts │ 0 / 0 │
│ │ │ │ │ │
│ Min balance │ 1003.126 USDT │ │ Min balance │ 981.947 USDT
│ Max balance │ 2361.69 USDT │ │ Max balance │ 3630.59 USDT │
│ Max % of account underwater │ 8.27% │ Max % of account underwater │ 11.64%
│ Absolute drawdown │ 116.751 USDT (7.37%) │ Absolute drawdown │ 359.078 USDT (10.66%) │
│ Drawdown duration │ 28 days 14:00:00 │ │ Drawdown duration │ 86 days 03:00:00 │
│ Profit at drawdown start │ 583.353 USDT │ Profit at drawdown start │ 2367.463 USDT │
│ Profit at drawdown end │ 466.603 USDT │ Profit at drawdown end │ 2008.385 USDT │
│ Drawdown start │ 2024-04-09 07:00:00 │ │ Drawdown start │ 2025-01-19 22:00:00 │
│ Drawdown end │ 2024-05-07 21:00:00 │ │ Drawdown end │ 2025-04-16 01:00:00 │
│ Market change │ 44.09% │ │ Market change │ 44.09% │
└───────────────────────────────┴─────────────────────────────────┘ └───────────────────────────────┴─────────────────────────────────┘
Backtested 2022-01-01 00:00:00 -> 2026-02-20 00:00:00 | Max open trades : 1 Backtested 2022-01-01 00:00:00 -> 2026-02-20 00:00:00 | Max open trades : 1
STRATEGY SUMMARY STRATEGY SUMMARY
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━
┃ Strategy ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃ Drawdown ┃ ┃ Strategy ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃ Drawdown ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩ ┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━
│ Empty │ 53 │ 1.76 │ 1312.665131.274 days, 1:16:00 │ 33 0 20 62.3 │ 116.751 USDT 7.37% │ │ Empty │ 92 │ 1.622474.507247.453 days, 23:07:00 │ 45 0 47 48.9 │ 359.078 USDT 10.66% │
└──────────┴────────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┴─────────────────────┘ └──────────┴────────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┴─────────────────────