Retour à l'accueil

Automatisation de la recherche de zones d'offre et de demande sur Bybit

Le système automatise la recherche de zones offre/demande sur Bybit via des blocs d'ordre et de rejet avec filtres ATR. Confirmation d'entrée par pinbar sur TF 5m avec envoi de graphiques vers Telegram. Décomposition complète du code pour développeurs middle/senior.

Python-bot : zones demande/offre Bybit + Telegram
Advertisement 728x90

Scanner Automatisé des Zones d'Offre et de Demande avec Alertes Telegram pour Bybit

Un système basé sur Python analyse toutes les paires USDT sur Bybit, identifie les zones d'offre et de demande en utilisant les concepts de Smart Money, suit les retests de prix avec formation de pinbar, et envoie instantanément des signaux de trading sur Telegram avec annotations graphiques. Le traitement de centaines d'actifs prend quelques minutes au lieu d'heures d'analyse manuelle.

La logique suit une chaîne : détection de zone → retest de prix → réaction du price action → génération de signal. Les zones sont filtrées par ATR, les cassures et les chevauchements pour exclure les niveaux non pertinents.

Théorie des Zones d'Offre et de Demande

Les zones de liquidité sont des zones clés où les positions s'accumulent et où un momentum ultérieur se produit. Les zones de demande se forment là où le prix a fortement augmenté, les zones d'offre là où il a fortement chuté. Un signal se déclenche lorsque le prix revient dans une zone avec confirmation par pinbar (une bougie avec une longue mèche).

Google AdInline article slot

Critères de validité d'une zone :

  • Impulsion vers la zone > 2 ATR
  • Impulsion hors de la zone > 2 ATR
  • Taille de la zone 1–6 ATR
  • Pas de cassure après la formation
MAX_ZONE_ATR = 7
MIN_ZONE_ATR = 1
LOOKBACK_PRE = 8
LOOKAHEAD_POST = 8
MIN_PRE_MOVE_ATR = 2
MIN_POST_MOVE_ATR = 2
MIN_ZONE_SIZE_ATR = 1.0
MAX_ZONE_SIZE_ATR = 6.0

Les paramètres ajustent la sensibilité : timeframe de 4H pour les zones, période ATR de 100 pour l'évaluation de la volatilité, scan toutes les 300 secondes.

Intégration avec l'API Bybit

Le système charge les listes de symboles et les bougies historiques :

Google AdInline article slot
def get_symbols():
    data = client.get_instruments_info(category="linear")
    symbols = []
    for item in data["result"]["list"]:
        if item["quoteCoin"] == "USDT":
            symbols.append(item["symbol"])
    return symbols

def get_klines(symbol, interval, limit):
    data = client.get_kline(
        category="linear",
        symbol=symbol,
        interval=interval,
        limit=limit
    )
    klines = data["result"]["list"]
    klines.reverse()  # from oldest to newest
    return klines

Seules les paires USDT sont filtrées. Les données sont traitées dans un DataFrame pandas avec ATR calculé.

Détection des Blocs d'Ordres

Les blocs d'ordres sont des structures fondamentales pour les zones. Bloc d'ordre de demande : une bougie baissière suivie d'une impulsion haussière au-dessus du précédent plus haut.

def detect_order_blocks(df):
    for i in range(1, len(df)):
        o1 = df.open.iloc[i-1]
        c1 = df.close.iloc[i-1]
        h1 = df.high.iloc[i-1]
        l1 = df.low.iloc[i-1]
        o2 = df.open.iloc[i]
        c2 = df.close.iloc[i]
        atr = df.atr.iloc[i]

        # DEMAND OB
        if c1 < o1 and c2 > o2 and c2 > h1:
            impulse = c2 - l1
            if impulse > atr * 1.5:
                zones.append({
                    "type": "demand",
                    "kind": "orderblock",
                    "low": l1,
                    "high": o1,
                    "start_bar": i-1
                })

De même pour l'offre. L'impulsion est filtrée >1.5 ATR pour exclure les mouvements en range.

Google AdInline article slot

Blocs de Rejet et Zones Avancées

Les blocs de rejet sont détectés par les proportions de bougie : mèche inférieure >55% de la plage, corps <35%.

def detect_rejection_blocks(df):
    for i in range(2, len(df)-1):
        o = df.open.iloc[i]
        c = df.close.iloc[i]
        h = df.high.iloc[i]
        l = df.low.iloc[i]
        atr = df.atr.iloc[i]
        body = abs(c - o)
        full = h - l
        upper_wick = h - max(o,c)
        lower_wick = min(o,c) - l
        body_ratio = body / full
        lower_ratio = lower_wick / full

        # DEMAND rejection
        if lower_ratio > 0.55 and body_ratio < 0.35:
            zones.append({
                "type": "demand",
                "kind": "rejection",
                "low": l,
                "high": min(o,c),
                "start_bar": i
            })

Un filtre avancé vérifie les impulsions avant/après la zone par rapport à l'ATR.

Fonction d'invalidation :

def is_zone_broken(df, zone):
    start_idx = zone['start_bar'] + 1
    slice_df = df.iloc[start_idx:]
    if zone['type'] == 'supply':
        break_level = slice_df['high'].max() if INVALIDATION_METHOD == "wick" else slice_df['close'].max()
        return break_level > zone['high']
    else:
        break_level = slice_df['low'].min() if INVALIDATION_METHOD == "wick" else slice_df['close'].min()
        return break_level < zone['low']

Les zones qui se chevauchent sont supprimées en triant par fraîcheur et en excluant les chevauchements.

Sélection des Zones les Plus Proches et Déclenchement Pinbar

Deux zones les plus proches du prix actuel sont sélectionnées :

def get_nearest_zones(price, zones, n=2):
    def zone_distance(z):
        if price < z["low"]:
            return z["low"] - price
        elif price > z["high"]:
            return price - z["high"]
        return 0
    return sorted(zones, key=zone_distance)[:n]

Pinbar sur le timeframe 5m :

def is_bullish_pinbar(candle):
    o, h, l, c = float(candle[1]), float(candle[2]), float(candle[3]), float(candle[4])
    body = abs(c - o)
    total_range = h - l
    if body > 0.3 * total_range or c <= o or lower_wick < body * 2 or upper_wick > body * 0.5:
        return False
    return True

Génération et Envoi des Signaux

Vérification du signal d'achat :

def check_long_signal(symbol, klines_5m, zones):
    last = klines_5m[-2]  # closed candle
    price = float(last[4])
    if not is_bullish_pinbar(last):
        return None
    for zone in zones:
        if price_in_zone(price, zone):
            key = f"{symbol}_{last[0]}_long"
            if key in sent_signals:
                return None
            sent_signals[key] = True
            return zone
    return None

Le signal est visualisé sur un graphique avec annotations de zone et envoyé à Telegram via l'API bot.

Points Clés

  • Le système utilise le 4H pour les zones et le 5m pour les déclencheurs, filtrant le bruit des timeframes inférieurs.
  • La normalisation ATR adapte les zones à la volatilité de l'actif sans être liée au BTC.
  • Protection contre les doublons via sent_signals et invalidation des zones cassées.
  • Traitement de toutes les paires USDT de Bybit en quelques minutes avec focus sur les zones les plus proches.
  • Price action (pinbar) comme déclencheur final après confirmation structurelle.

— Editorial Team

Advertisement 728x90

Lire ensuite