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,
|
sl_short: float,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""
|
"""
|
||||||
Parcourt les barres futures bar par bar et retourne le label.
|
Simule LONG et SHORT de façon indépendante sur les barres futures.
|
||||||
Vérifie HIGH pour TP LONG et LOW pour SL LONG (et inversement pour SHORT).
|
|
||||||
|
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():
|
# --- Simulation LONG indépendante ---
|
||||||
# LONG : TP atteint ?
|
long_win_idx = None
|
||||||
if bar['high'] >= tp_long and bar['low'] > sl_long:
|
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
|
||||||
|
|
||||||
|
# --- 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
|
||||||
|
|
||||||
|
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
|
return 1
|
||||||
# LONG : SL atteint en premier ?
|
if short_won and not long_won:
|
||||||
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
|
|
||||||
|
|
||||||
# SHORT : TP atteint ?
|
|
||||||
if bar['low'] <= tp_short and bar['high'] < sl_short:
|
|
||||||
return -1
|
return -1
|
||||||
# SHORT : SL atteint en premier ?
|
if long_won and short_won:
|
||||||
if bar['high'] >= sl_short:
|
# Les deux trades seraient gagnants : prendre celui qui se résout en premier
|
||||||
if bar['low'] <= tp_short:
|
return 1 if long_win_idx <= short_win_idx else -1
|
||||||
return 0
|
return 0 # Aucun TP atteint dans l'horizon
|
||||||
return 0
|
|
||||||
|
|
||||||
return 0 # Ni TP ni SL atteint dans l'horizon
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _log_distribution(labels: pd.Series) -> None:
|
def _log_distribution(labels: pd.Series) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user