fix: LabelGenerator _classify_bar — simulation LONG/SHORT indépendante
Bug : quand le SL LONG était touché, la fonction retournait 0 (NEUTRAL) immédiatement sans évaluer les conditions SHORT. Résultat : 0 labels SHORT sur 12230 barres, modèle inutilisable pour signaux SHORT. Fix : deux boucles indépendantes (LONG et SHORT) qui évaluent chacune leur propre TP/SL. Si les deux gagnent, priorité au premier résolu. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -140,30 +140,59 @@ class LabelGenerator:
|
||||
sl_short: float,
|
||||
) -> int:
|
||||
"""
|
||||
Parcourt les barres futures bar par bar et retourne le label.
|
||||
Vérifie HIGH pour TP LONG et LOW pour SL LONG (et inversement pour SHORT).
|
||||
Simule LONG et SHORT de façon indépendante sur les barres futures.
|
||||
|
||||
LONG et SHORT sont deux trades hypothétiques distincts : le SL du LONG
|
||||
(prix baisse) ne signifie pas que le SL du SHORT (prix monte) est touché.
|
||||
Les deux simulations sont donc parcourues séparément pour éviter de
|
||||
manquer les signaux SHORT quand le prix descend.
|
||||
|
||||
Retourne le label du trade gagnant qui se résout en premier :
|
||||
1 (LONG), -1 (SHORT) ou 0 (NEUTRAL).
|
||||
"""
|
||||
for _, bar in future.iterrows():
|
||||
# LONG : TP atteint ?
|
||||
if bar['high'] >= tp_long and bar['low'] > sl_long:
|
||||
return 1
|
||||
# LONG : SL atteint en premier ?
|
||||
if bar['low'] <= sl_long:
|
||||
# Vérifie si TP atteint le même bar (candle ambiguë)
|
||||
if bar['high'] >= tp_long:
|
||||
return 0 # Ambigu → neutre
|
||||
return 0 # SL touché → pas de LONG
|
||||
# --- Simulation LONG indépendante ---
|
||||
long_win_idx = None
|
||||
long_lose_idx = None
|
||||
for idx, (_, bar) in enumerate(future.iterrows()):
|
||||
tp_hit = bar['high'] >= tp_long
|
||||
sl_hit = bar['low'] <= sl_long
|
||||
if tp_hit and sl_hit:
|
||||
long_lose_idx = idx # Barre ambiguë → perte
|
||||
break
|
||||
if tp_hit:
|
||||
long_win_idx = idx
|
||||
break
|
||||
if sl_hit:
|
||||
long_lose_idx = idx
|
||||
break
|
||||
|
||||
# SHORT : TP atteint ?
|
||||
if bar['low'] <= tp_short and bar['high'] < sl_short:
|
||||
return -1
|
||||
# SHORT : SL atteint en premier ?
|
||||
if bar['high'] >= sl_short:
|
||||
if bar['low'] <= tp_short:
|
||||
return 0
|
||||
return 0
|
||||
# --- Simulation SHORT indépendante ---
|
||||
short_win_idx = None
|
||||
short_lose_idx = None
|
||||
for idx, (_, bar) in enumerate(future.iterrows()):
|
||||
tp_hit = bar['low'] <= tp_short
|
||||
sl_hit = bar['high'] >= sl_short
|
||||
if tp_hit and sl_hit:
|
||||
short_lose_idx = idx # Barre ambiguë → perte
|
||||
break
|
||||
if tp_hit:
|
||||
short_win_idx = idx
|
||||
break
|
||||
if sl_hit:
|
||||
short_lose_idx = idx
|
||||
break
|
||||
|
||||
return 0 # Ni TP ni SL atteint dans l'horizon
|
||||
long_won = long_win_idx is not None
|
||||
short_won = short_win_idx is not None
|
||||
|
||||
if long_won and not short_won:
|
||||
return 1
|
||||
if short_won and not long_won:
|
||||
return -1
|
||||
if long_won and short_won:
|
||||
# Les deux trades seraient gagnants : prendre celui qui se résout en premier
|
||||
return 1 if long_win_idx <= short_win_idx else -1
|
||||
return 0 # Aucun TP atteint dans l'horizon
|
||||
|
||||
@staticmethod
|
||||
def _log_distribution(labels: pd.Series) -> None:
|
||||
|
||||
Reference in New Issue
Block a user