Zurück zur Startseite

Automatisierung der Suche nach Supply-Demand-Zonen auf Bybit

Das System automatisiert die Suche nach Supply/Demand-Zonen auf Bybit durch Order- und Rejection-Blöcke mit ATR-Filtern. Einstiegsbestätigung durch Pinbar auf 5m-TF mit Versand von Charts an Telegram. Vollständige Code-Analyse für Middle-/Senior-Developer.

Python-Bot: Demand/Supply-Zonen Bybit + Telegram
Advertisement 728x90

Automatisierter Supply/Demand-Zonen-Scanner mit Telegram-Benachrichtigungen für Bybit

Ein Python-basiertes System scannt alle USDT-Paare auf Bybit, identifiziert Supply- und Demand-Zonen mithilfe von Smart-Money-Konzepten, verfolgt Preisrücktests mit Pinbar-Formation und sendet sofort Handelsignale mit Chart-Markierungen an Telegram. Die Verarbeitung von Hunderten von Assets dauert Minuten statt Stunden manueller Analyse.

Die Logik folgt einer Kette: Zonenerkennung → Preisrücktest → Price-Action-Reaktion → Signalgenerierung. Zonen werden nach ATR, Ausbrüchen und Überlappungen gefiltert, um irrelevante Levels auszuschließen.

Theorie der Supply- und Demand-Zonen

Liquiditätszonen sind Schlüsselbereiche, in denen sich Positionen ansammeln und anschließender Schwung entsteht. Demand-Zonen bilden sich dort, wo der Preis aggressiv gestiegen ist, Supply-Zonen dort, wo er scharf gefallen ist. Ein Signal wird ausgelöst, wenn der Preis mit Pinbar-Bestätigung (eine Kerze mit langem Docht) in eine Zone zurückkehrt.

Google AdInline article slot

Kriterien für die Zonengültigkeit:

  • Impuls in die Zone > 2 ATR
  • Impuls aus der Zone > 2 ATR
  • Zonengröße 1–6 ATR
  • Kein Ausbruch nach der 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

Parameter passen die Empfindlichkeit an: 4H-Zeitrahmen für Zonen, ATR-Periode 100 für Volatilitätsbewertung, Scannen alle 300 Sekunden.

Integration mit der Bybit-API

Das System lädt Symbollisten und historische Kerzen:

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()  # von ältester zu neuester
    return klines

Nur USDT-Paare werden gefiltert. Daten werden in einem pandas DataFrame mit berechnetem ATR verarbeitet.

Order-Block-Erkennung

Order-Blöcke sind grundlegende Strukturen für Zonen. Demand-OB: eine bärische Kerze, gefolgt von einem bullischen Impuls über dem vorherigen Hoch.

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
                })

Ähnlich für Supply. Impuls wird auf >1,5 ATR gefiltert, um range-bound Bewegungen auszuschließen.

Google AdInline article slot

Rejection-Blöcke und erweiterte Zonen

Rejection-Blöcke werden durch Kerzenproportionen erkannt: unterer Docht >55% der Range, Körper <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
            })

Ein erweitertes Filter prüft Impulse vor/nach der Zone relativ zum ATR.

Ungültigkeitsfunktion:

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']

Überlappende Zonen werden durch Sortierung nach Frische und Ausschluss von Überlappungen entfernt.

Auswahl der nächstgelegenen Zonen und Pinbar-Trigger

Zwei Zonen, die dem aktuellen Preis am nächsten liegen, werden ausgewählt:

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 auf 5m-Zeitrahmen:

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

Signalgenerierung und -versand

Long-Signalprüfung:

def check_long_signal(symbol, klines_5m, zones):
    last = klines_5m[-2]  # geschlossene Kerze
    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

Das Signal wird auf einem Chart mit Zonenmarkierung visualisiert und über die Bot-API an Telegram gesendet.

Wichtige Punkte

  • Das System verwendet 4H für Zonen und 5m für Trigger, um Rauschen von niedrigeren Zeitrahmen zu filtern.
  • ATR-Normalisierung passt Zonen an die Volatilität des Assets an, ohne an BTC gebunden zu sein.
  • Duplikatschutz über sent_signals und Ungültigkeit gebrochener Zonen.
  • Verarbeitung aller Bybit-USDT-Paare in Minuten mit Fokus auf nächstgelegene Zonen.
  • Price Action (Pinbar) als finaler Trigger nach struktureller Bestätigung.

— Editorial Team

Advertisement 728x90

Weiterlesen