Files
trader-bot/backend/app/core/strategy/base.py
tika adbc41102e fix: aligner les candles du chart avec la période du backtest
Bug: les markers BUY/SELL du chart utilisaient les timestamps des trades
du backtest mais les candles étaient fetchées séparément (500 candles récentes),
causant un désalignement visuel.

- Backend: /backtest retourne désormais les candles exactes du DataFrame analysé
- Frontend: Backtest.tsx utilise result.candles directement (suppression du
  fetchCandles séparé)
- Ajout: sérialisation reason/OB/LL sur les trades, overlays OB/LL bornés
  dans le temps, trade reasons expandables, filtre HTF, badge tendance HTF

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 01:23:42 +01:00

81 lines
2.5 KiB
Python

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Optional
import pandas as pd
@dataclass
class OrderBlockZone:
"""Zone Order Block à surveiller."""
id: str
direction: str # "bullish" | "bearish"
top: float # Haut de la zone
bottom: float # Bas de la zone
origin_time: pd.Timestamp
mitigated: bool = False # True si le prix a traversé la zone
@dataclass
class LiquidityLevel:
"""Niveau de liquidité (Equal H/L)."""
id: str
direction: str # "high" | "low"
price: float
origin_time: pd.Timestamp
swept: bool = False # True si le prix a dépassé ce niveau
@dataclass
class TradeReason:
"""Explication structurée de pourquoi un signal a été généré."""
summary: str # "EQH sweep at 1.08542 → Bullish OB [1.082 - 1.0835]"
swept_level_price: Optional[float] = None
swept_level_direction: Optional[str] = None # "high" | "low"
ob_direction: Optional[str] = None # "bullish" | "bearish"
ob_top: Optional[float] = None
ob_bottom: Optional[float] = None
ob_origin_time: Optional[str] = None
filters_applied: list[str] = field(default_factory=list)
@dataclass
class TradeSignal:
"""Signal de trading généré par la stratégie."""
direction: str # "buy" | "sell"
entry_price: float
stop_loss: float
take_profit: float
signal_type: str # description du setup
time: pd.Timestamp
order_block: Optional[OrderBlockZone] = None
liquidity_level: Optional[LiquidityLevel] = None
reason: Optional[TradeReason] = None
@dataclass
class AnalysisResult:
"""Résultat complet de l'analyse de la stratégie."""
order_blocks: list[OrderBlockZone] = field(default_factory=list)
liquidity_levels: list[LiquidityLevel] = field(default_factory=list)
signals: list[TradeSignal] = field(default_factory=list)
class AbstractStrategy(ABC):
"""Interface commune pour toutes les stratégies."""
@abstractmethod
def analyze(self, df: pd.DataFrame) -> AnalysisResult:
"""
Analyse un DataFrame de candles et retourne les zones,
niveaux de liquidité et signaux d'entrée.
df doit avoir les colonnes : time, open, high, low, close, volume
"""
...
@abstractmethod
def get_params(self) -> dict:
"""Retourne les paramètres configurables de la stratégie."""
...