Binance WebSocket’ini Dinleyerek Canlı Veri Çeken Python Kodu (2025 Rehberi)

Tarih:

Paylaş:

Binance WebSocket’ini Dinleyerek Canlı Veri Çeken Python Kodu (2025 Rehberi)

Öncelikle neden WebSocket kullandığımızı netleştirelim: REST ile periyodik “çek-al” yapmak yerine, WebSocket ile Binance’in akışına bağlanır ve veriyi anında işlersin. Ayrıca bu yaklaşım daha düşük gecikme, daha tutarlı veri ve daha az oran sınırı hatası sağlar. Dahası, aşağıdaki rehber ile doğru uç noktaları, ping/pong yönetimini ve yeniden bağlanma stratejisini kolayca uygularsın.

Kısa özet: Spot WebSocket tabanı wss://stream.binance.com:9443. Tekil akış için /ws/<streamName>, birleştirilmiş akış için /stream?streams=<s1>/<s2> kullan. Tüm sembolleri küçük harfle yaz. Binance bağlantıyı yaklaşık 24 saatte bir kapatır; bu yüzden istemcin otomatik olarak yeniden bağlanır.

Neden WebSocket?

  • Anında aksiyon al: Trade, kline (mum) ve miniTicker olayları milisaniye düzeyinde gelir; böylece işlemleri gecikmeden kaydedersin.
  • Kaynakları verimli kullan: REST’e göre daha az istek atarsın; ayrıca oran sınırlarını daha az zorlarsın.
  • Veriyi doğru yere akıt: CSV, SQLite, Parquet ya da mesaj kuyruklarına (Kafka/Kinesis) doğrudan yazarsın.

Mimari Özeti

Uç Noktalar ve Akış Adları (Spot)

  • Taban: wss://stream.binance.com:9443
  • Tekil akış: /ws/<streamName>
  • Birleştirilmiş akış: /stream?streams=<stream1>/<stream2>
  • Örnek akış adları: btcusdt@trade, ethusdt@kline_1m, bnbusdt@miniTicker
  • İpucu: Tüm akış adlarını küçük harfle yaz.

Ping/Pong ve Süreklilik

Sunucu düzenli aralıklarla PING gönderir; sen de gecikmeden PONG yanıtı verirsin. Ayrıca Binance bağlantıyı ~24 saat sonra kapatır; bu nedenle istemci otomatik olarak yeniden bağlanmayı yönetir. Böylece veri akışı kesintiye uğramadan devam eder.

Bağlantı ve Mesaj Sınırları

  • Mesaj oranı: Saniyede 5 mesaj sınırını aşma (subscribe/unsubscribe ve ping/pong dâhil).
  • Akış sınırı: Tek bağlantıda en fazla 1024 stream dinleyebilirsin; öte yandan pratikte akışları birden çok bağlantıya bölmek stabilite sağlar.
  • Deneme kotası: Aşırı bağlantı denemelerini azalt; aksi halde istemciyi geçici olarak engelleyebilirler.

Not: Futures uç noktaları farklıdır (ör. USDS-M için wss://fstream.binance.com). Buna ek olarak, kimlik gerektiren User Data Stream akışları farklı bir akış mantığı izler.

Kurulum

python -V   # 3.10+ öneririm
pip install websocket-client orjson

websocket-client düşük seviyeyi kontrol etmeni sağlar. Ayrıca orjson yüksek hızlı JSON ayrıştırır. İstersen standart json modülünü de kullanabilirsin.

Üretim-Hazır Python Örneği

Aşağıdaki örnek, BTCUSDT trade ve ETHUSDT 1 dakikalık kline akışlarını birleştirilmiş stream ile dinler. Ayrıca mesajları ayrıştırır, CSV’ye yazar, ping/pong yanıtını verir ve üstel geri çekilme (exponential backoff) ile otomatik yeniden bağlanır.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import csv
import json
import random
import signal
import time
from datetime import datetime, timezone
from typing import List

import orjson
import websocket  # pip install websocket-client

BASE_WS = "wss://stream.binance.com:9443"
RUN = True  # nazik kapanış bayrağı


def build_combined_stream_url(streams: List[str]) -> str:
    # Çoklu stream'i tek bağlantıda dinlemek için URL üret
    streams = [s.strip().lower() for s in streams if s.strip()]
    path = "/stream?streams=" + "/".join(streams)
    return BASE_WS + path


def utc_iso(ms: int) -> str:
    # Binance ms epoch -> ISO8601
    return datetime.fromtimestamp(ms / 1000, tz=timezone.utc).isoformat()


def on_open(ws):
    print("[WS] Açıldı:", ws.url)


def on_close(ws, code, reason):
    print(f"[WS] Kapandı code={code} reason={reason}")


def on_error(ws, err):
    print("[WS] Hata:", err)


def on_ping(ws, message):
    # Ping geldiğinde anında pong gönder
    try:
        ws.pong(message)
    except Exception as e:
        print("[WS] Pong gönderilemedi:", e)


def safe_json_loads(data):
    # Hızlı ayrıştır; gerekirse standart json'a düş
    try:
        return orjson.loads(data if isinstance(data, (bytes, bytearray)) else data.encode())
    except Exception:
        return json.loads(data if isinstance(data, str) else data.decode("utf-8", errors="ignore"))


def handle_message(raw, writer_trade, writer_kline):
    # Combined stream: {"stream":"...","data":{...}}
    obj = safe_json_loads(raw)
    payload = obj.get("data", obj)

    e = payload.get("e")  # event type

    if e == "trade":  # btcusdt@trade
        symbol = payload.get("s")
        price = payload.get("p")
        qty = payload.get("q")
        ts = payload.get("T") or payload.get("E")
        writer_trade.writerow([utc_iso(ts), symbol, price, qty])
        return

    if e == "kline":  # ethusdt@kline_1m
        k = payload.get("k", {})
        symbol = payload.get("s")
        interval = k.get("i")
        o = k.get("o"); h = k.get("h"); l = k.get("l"); c = k.get("c")
        start = k.get("t"); end = k.get("T"); closed = int(bool(k.get("x")))
        writer_kline.writerow([utc_iso(start), utc_iso(end), symbol, interval, o, h, l, c, closed])
        return

    # Gerekirse diğer event türlerini de işle (miniTicker vb.)


def run_forever(streams: List[str]):
    url = build_combined_stream_url(streams)

    with open("trades.csv", "a", newline="", encoding="utf-8") as f1, \
         open("klines_1m.csv", "a", newline="", encoding="utf-8") as f2:

        trade_writer = csv.writer(f1)
        kline_writer = csv.writer(f2)

        # Başlıkları ekle (dosya boşsa)
        if f1.tell() == 0:
            trade_writer.writerow(["time_utc", "symbol", "price", "qty"])
        if f2.tell() == 0:
            kline_writer.writerow(["start_utc", "end_utc", "symbol", "interval", "open", "high", "low", "close", "closed"])

        backoff = 1
        while RUN:
            ws = websocket.WebSocketApp(
                url,
                on_open=on_open,
                on_close=on_close,
                on_error=on_error,
                on_message=lambda _ws, msg: handle_message(msg, trade_writer, kline_writer),
                on_ping=on_ping,
            )
            try:
                # Sunucunun pinglerine on_ping ile yanıt ver
                ws.run_forever(ping_interval=0, reconnect=0)
            except Exception as e:
                print("[WS] İstisna:", e)

            if not RUN:
                break

            # Üstel geri çekilme + jitter
            wait = min(60, backoff) + random.uniform(0, 3)
            print(f"[WS] Yeniden bağlanıyorum... {wait:.1f}s")
            time.sleep(wait)
            backoff = min(backoff * 2, 60)


def _shutdown(signum, frame):
    global RUN
    RUN = False
    print(f"\n[SYS] Sinyal alındı ({signum}). Kapanıyorum...")


if __name__ == "__main__":
    # Nazik kapanış için sinyal yakala
    import signal
    for sig in (signal.SIGINT, signal.SIGTERM):
        signal.signal(sig, _shutdown)

    # Akışları tanımla
    streams = [
        "btcusdt@trade",
        "ethusdt@kline_1m",
        # "bnbusdt@miniTicker",
    ]
    run_forever(streams)

Nasıl Çalıştırırsın?

python binance_stream_listener.py
# trades.csv ve klines_1m.csv dosyaları oluşur ve yeni veriler eklendikçe büyür

Neden Bu Kod “Üretim-Hazır”?

  • Ping/Pong yönetimi: Sunucu pingi geldiğinde anında pong gönderirsin; böylece bağlantı aktif kalır.
  • Backoff’lu yeniden bağlanma: Ağ kesilse bile uygulama otomatik toparlar; dahası bekleme süresini kademeli artırır.
  • Birleştirilmiş stream: Tek sokette çoklu akış izlersin; ayrıca bant genişliğini daha verimli kullanırsın.
  • Kalıcı kayıt: CSV ile hızlı başlarsın; daha sonra SQLite/Parquet/Kafka’ya geçersin.

Ölçekleme ve En İyi Uygulamalar

  1. Öncelikle stream’leri grupla: 20–50 akışı tek bağlantıda topla; ardından daha fazlasını yeni bağlantılara böl.
  2. Mesaj oranını koru: Abonelik işlemlerini partiler hâlinde gönder; böylece 5 msg/sn sınırını aşmazsın.
  3. Saat senkronu kur: Sunucu saatini not et; öte yandan yerel saat ofsetini analizde hesaba kat.
  4. Dayanıklılığı artır: Prod ortamında kalıcı depoya yaz; ayrıca yeniden başlatmada kaldığın yerden devam etmek için ofset tablosu tut.
  5. Pazar farklarını unutma: Futures/Options için farklı uç noktaları kullan; buna ek olarak dokümana göre event şemalarını güncelle.

Sık Karşılaşılan Sorunlar

  • Bağlantı donuyor: Genelde geciken pong yanıtı sorun yaratır; böylece bağlantı kopar. Çözüm olarak otomatik reconnect uygula ve ağ gecikmesini düşür.
  • Sembol büyük harf: Akış adlarını her zaman küçük harfle yaz; aksi hâlde sunucu isteği reddeder.
  • Uzun süre sonra kopma: Binance bağlantıyı ~24 saatte bir kapatır; bu yüzden beklenen kopuşu kod zaten yönetir.
  • Subscribe flood: Abonelikleri peş peşe gönderirsen 5 msg/sn sınırını aşarsın; sonuç olarak IP geçici engel alabilir.

Genişletme Fikirleri

  • Gerçek zamanlı gösterge: WebSocket → asyncio → FastAPI/WebSocket ile veriyi tarayıcıya yayınla; böylece kullanıcı paneli canlı güncellenir.
  • Alarm motoru: Mum kapanınca (x==True) kural çalıştır; örneğin RSI veya MA crossover gibi sinyaller üret.
  • Tutarlılık denetimi: Periyodik olarak REST klines ile karşılaştır; ayrıca eksik mumları geri yükle.

Diğer Haberler

Square Enix işten çıkarmalar: Batı’da yeniden yapılandırma

Square Enix, ABD ve Avrupa'daki yapılandırma çalışmaları çerçevesinde ek işten çıkarmalar gerçekleştireceğini duyurdu. Bu süreçten etkilenen alanların neredeyse tamamı, şirketin Batı ülkelerindeki operasyonlarını kapsıyor.

Starlink müşteri sayısı 8 milyon oldu, yeni anlaşmalar!

SpaceX’in internet hizmeti Starlink, müşteri sayısını 8 milyona ulaştırdı. Yeni spektrum lisansları satın alan şirket, ayrıca British Airways’in sahibi ile işbirliği yaptı.

Vostochny uzay üssü elektrik faturalarını ödeyemedi

Rusya'nın önemli projelerinden biri olan Vostochny uzay üssü, yıllardır süren sorunlar yaşıyor. Son olarak, elektrik şirketi, borçlar yüzünden iptal edilen ödemeler nedeniyle uzay üssünün elektriğini kesti.

Google AI askeri üs Christmas Adası’na kurulacak

Google, Avustralya'nın Christmas Adası'nda gizli bir AI askeri üssü inşa etmeyi planlıyor. Bu proje, stratejik bir konumda bulunması nedeniyle askeri yeteneklerin artırılmasını amaçlıyor.