sgcWebSockets + Binance ile Delphi'de Gerçek Zamanlı Bir Ticaret Botu Oluşturun

· Özellikler

Ne İnşa Ediyoruz

Bu eğitimin sonunda, Binance'ten canlı işlem ve emir defteri verilerini akıtan, basit bir breakout stratejisi çalıştıran, REST API aracılığıyla gerçek emirler veren ve risk kontrollerini (maksimum pozisyon büyüklüğü, günlük zarar limiti, kill switch) uygulayan çalışan bir Delphi VCL uygulamanız olacak. Aynı altyapı, yalnızca kimlik bilgisi ve sembol eşlemesi değişerek sgcWebSockets tarafından desteklenen herhangi bir borsada çalışır: Coinbase, Kraken, OKX, Bybit, Bitfinex.

Bu, referans sgcTrader örneğimizde kullanılan mimarinin aynısıdır. Tam kullanıcı arayüzü, grafik oluşturma ve çoklu borsa yönlendirmesiyle daha büyük bir başlangıç noktası istiyorsanız, onu edinin. Aşağıdaki adım adım anlatım, yaklaşık 300 satır kodda perde arkasında neler olduğunu gösterir.

Başlamadan önce iki ön koşul. Önce, bir Binance API anahtarı edinin (Account > API Management). Geliştirme için, yalnızca "Enable Reading" ve "Enable Spot Trading" iznine sahip bir anahtar oluşturun ve IP'nizi beyaz listeye alın. Asla koda para çekme özelliği etkin bir anahtar koymayın. İkinci olarak, her şeyi önce Binance'in test ağında (testnet) yapın (testnet.binance.vision). Uç noktalar, mesaj formatları ve imza algoritması üretimle aynıdır, ancak fonlar sahtedir. "Stratejimin doğru olduğundan eminim" yüzünden, tam olarak önce test ağında test etmediğimiz sayıda gerçek para kaybettik.

Tek Bir Diyagramda Mimari

Üç iş parçacığı, iki bileşen, bir risk bekçisi:

Bileşen Rol İş Parçacığı
TsgcWSAPI_Binance WebSocket akışı: işlemler, derinlik, klineler, kullanıcı verileri G/Ç çalışanı
TsgcHTTP_API_Binance REST: emir verme, iptal, hesap anlık görüntüsü Ticaret çalışanı
Strateji kuyruğu Ayrıştırma: piyasa olayları → kararlar → emirler Strateji çalışanı
Risk kapısı Her emri engelle / küçült / izin ver Ticaret çalışanında satır içi

Adım 1: Piyasa Verilerini Akıtın

Forma bir TsgcWSAPI_Binance bırakın. Zaten Binance birleşik akış protokolünü konuşur; yalnızca istediğiniz kanallara abone olursunuz.

uses
  sgcWSAPI_Binance;

procedure TForm1.FormCreate(Sender: TObject);
begin
  oBinance := TsgcWSAPI_Binance.Create(Self);
  oBinance.WatchDog.Enabled  := True;
  oBinance.WatchDog.Interval := 5;
  oBinance.HeartBeat.Enabled := True;

  oBinance.OnBinanceMessage := DoStream;
  oBinance.OnDisconnect     := DoDisconnect;

  // Subscribe to 1-minute klines and aggregated trades for BTCUSDT
  oBinance.Streams.Add('btcusdt@kline_1m');
  oBinance.Streams.Add('btcusdt@aggTrade');

  oBinance.Active := True;
end;

procedure TForm1.DoStream(Sender: TObject; const aStream, aData: string);
begin
  // Fire-and-forget: push to the strategy queue
  oStrategyQueue.Push(TMarketEvent.Create(aStream, aData));
end;

İşte tüm piyasa verisi alım katmanı bu kadar. Bağlantı kopmalarında yeniden bağlanma, ölü bağlantıları tespit etmek için heartbeat ve strateji kuyruğuna bloklamayan bir gönderim.

Bileşenin, aksi takdirde kendiniz yazmanız gereken bir şeyi yapması: Binance birleşik akış URL'si /stream?streams=name1/name2/name3 şeklindedir ve bağlantıyı koparmadan akış eklemek veya kaldırmak istiyorsanız, aynı soket üzerinden bir JSON-RPC subscribe/unsubscribe mesajı göndermeniz gerekir. TsgcWSAPI_Binance, JSON-RPC el sıkışmasını sizin için yöneten SubscribeStream ve UnsubscribeStream metotlarını sunar. Kullanıcı arayüzünde yeni bir ticker seçtiğinde kullanışlıdır; yeniden bağlanma yok, kayıp mesaj yok.

Ayrıca: Binance, IP başına ve akış başına sınırlar uygular. Her USDT çiftinde tam derinlik için mesaj hızı sınırına hızla ulaşırsınız. Yalnızca gerçekten ihtiyacınız olana abone olun ve geniş bir piyasa görünümüne ihtiyacınız olduğunda sembol başına akışlar yerine toplu akışları (!miniTicker@arr) tercih edin.

Adım 2: Minimal Bir Strateji

Strateji kendi iş parçacığında çalışır. 1 dakikalık kline akışından son N kapanışın kayan bir penceresini tutar ve fiyat 20 periyotluk bir yükseğin üzerine çıktığında uzun (long) pozisyon alır. Yalnızca örnekleme amaçlıdır; lütfen bunu gerçek paranın önüne koymayın.

procedure TStrategyThread.Execute;
var
  oEvent : TMarketEvent;
  oJSON  : TsgcJSONObject;
  vClose : Double;
  vHigh  : Double;
begin
  while not Terminated do
  begin
    if not oStrategyQueue.Pop(oEvent, 100) then Continue;
    try
      oJSON := TsgcJSONObject.Parse(oEvent.Data);
      try
        if oEvent.Stream.EndsWith('@kline_1m') then
        begin
          vClose := oJSON.O['k'].F['c'];
          FCloses.Append(vClose);
          if FCloses.Count >= 21 then
          begin
            vHigh := FCloses.Max(20);                  // prior 20-bar high
            if (FPosition = 0) and (vClose > vHigh) then
              oOrderQueue.Push(TIntent.New(siBuy, 'BTCUSDT', 0.001))
            else if (FPosition > 0) and (vClose < FCloses.MA(20)) then
              oOrderQueue.Push(TIntent.New(siSell, 'BTCUSDT', FPosition));
          end;
        end;
      finally
        oJSON.Free;
      end;
    finally
      oEvent.Free;
    end;
  end;
end;

Adım 3: Risk Kapısı

Bir stratejinin borsayla doğrudan konuşmasına asla izin vermeyin. Her niyeti, sınırlarınızı bilen bir kapıdan geçirin.

function TRiskGate.Validate(const aIntent: TIntent;
  out aReason: string): Boolean;
begin
  Result := False;

  if FKillSwitch then
    Exit(False);

  if Abs(FDailyPnL) > FConfig.MaxDailyLoss then
  begin
    aReason := 'Daily loss limit hit';
    Exit;
  end;

  if (aIntent.Side = siBuy)
     and (FPositionUSD + aIntent.Qty * FLastPrice > FConfig.MaxPositionUSD) then
  begin
    aReason := 'Max position size';
    Exit;
  end;

  Result := True;
end;

Adım 4: Emri REST Aracılığıyla Verin

Emir çalışanı, doğrulanmış niyetleri çeker, isteği imzalar ve Binance'e gönderir.

procedure TTraderThread.Execute;
var
  oIntent  : TIntent;
  vReason  : string;
  oResponse: TsgcBinanceClass_Response_NewOrder;
begin
  while not Terminated do
  begin
    if not oOrderQueue.Pop(oIntent, 100) then Continue;
    try
      if not FRisk.Validate(oIntent, vReason) then
      begin
        Log(Format('REJECT %s %s qty=%.6f reason=%s',
          [SideName(oIntent.Side), oIntent.Symbol, oIntent.Qty, vReason]));
        Continue;
      end;

      oResponse := oHttp.NewOrder(
        oIntent.Symbol,
        IfThen(oIntent.Side = siBuy, 'BUY', 'SELL'),
        'MARKET',
        oIntent.Qty,
        0  // price ignored for MARKET
      );
      try
        Log(Format('FILL  %s qty=%.6f price=%.2f id=%d',
          [oIntent.Symbol, oResponse.ExecutedQty,
           oResponse.AvgPrice, oResponse.OrderId]));
        FRisk.OnFill(oIntent.Side, oResponse.ExecutedQty, oResponse.AvgPrice);
      finally
        oResponse.Free;
      end;
    finally
      oIntent.Free;
    end;
  end;
end;

Adım 4b: REST Kimlik Doğrulama ve İmzalama

TsgcHTTP_API_Binance bileşeni, API gizli anahtarını (secret) kullanarak istekleri sizin için imzalar. Perde arkasında kanonik sorgu dizesini oluşturur, gizli anahtarınızla bir HMAC-SHA256 hesaplar ve onu signature parametresi olarak ekler. Anahtarı ve gizli anahtarı başlangıçta bir kez sağlarsınız.

oHttp := TsgcHTTP_API_Binance.Create(Self);
oHttp.BinanceOptions.ApiKey    := FConfig.ApiKey;
oHttp.BinanceOptions.ApiSecret := FConfig.ApiSecret;
oHttp.BinanceOptions.RecvWindow := 5000;   // ms tolerance for signed requests
// Test connectivity and confirm your IP whitelist
ShowMessage('Server time: ' + IntToStr(oHttp.GetServerTime));

Test ağına karşı çalıştırmak istiyorsanız, BinanceOptions.Testnet := True olarak ayarlayın; bileşen hem REST temel URL'sini hem de WebSocket ana bilgisayarını otomatik olarak değiştirir. Test ağına karşı derleyip test edin, tek bir bayrağı çevirin, üretime dağıtın. Binance API belgeleri iki ortam arasında bunun dışında aynıdır.

Adım 5: Kullanıcı Veri Akışı

Aynı WebSocket bileşeni ayrıca özel kullanıcı veri akışınıza da abone olur: hesap güncellemeleri, emir olayları, pozisyon değişiklikleri. Botunuzun dışında gerçekleşen gerçekleşmeleri (web arayüzünden manuel iptal, tasfiye vb.) bu şekilde mutabakata bağlarsınız.

oBinance.AuthOptions.ApiKey    := FConfig.ApiKey;
oBinance.AuthOptions.ApiSecret := FConfig.ApiSecret;
oBinance.Streams.Add('!userData');

procedure TForm1.DoStream(Sender: TObject; const aStream, aData: string);
var
  oJSON: TsgcJSONObject;
begin
  if aStream = '!userData' then
  begin
    oJSON := TsgcJSONObject.Parse(aData);
    try
      if oJSON.S['e'] = 'executionReport' then
        FRisk.ReconcileExternalFill(oJSON);
    finally
      oJSON.Free;
    end;
  end;
end;

Geriye Dönük Test (Backtesting) Hakkında Bir Not

Yukarıdakilerin hiçbiri "bu strateji gerçekten kârlı mı?" sorusunu yanıtlamaz. Geriye dönük testin amacı budur: ileriye dönük performansını tahmin etmek için aynı stratejiyi geçmiş verilere karşı yeniden oynatmak. Yukarıdaki mimari bunu neredeyse ücretsiz hale getirir: strateji iş parçacığı, piyasa olaylarının canlı bir WebSocket'ten mi yoksa bir CSV okuyucudan mı geldiğini umursamaz. Diskten klineleri okuyup aynı kuyruğa besleyen sentetik bir olay kaynağı oluşturun; strateji kodunuz yıllarca süren geçmiş verilere karşı değişmeden çalışır.

Kaçınılması gereken iki tuzak. İleriye bakma yanlılığı (look-ahead bias): stratejinin, işlediği zaman damgasında mevcut olmayacak hiçbir veri noktasına bakmasına izin vermeyin. Ve hayatta kalma yanlılığı (survivorship bias): bugüne kadar hayatta kalan "başarılı" sembollerin seçilmiş listesinde değil, o zaman var olan sembol evreninde eğitin ve test edin. Her ikisi de üretimde, tüm kodlama hatalarının toplamından daha fazla stratejiyi öldürmüştür.

Operasyonel Kontrol Listesi

Konu Nerede ele alınır
Wi-Fi kopmasında yeniden bağlanma WatchDog.Enabled := True
Ölü bağlantı tespiti HeartBeat.Enabled := True
Zaman senkronizasyonu (Binance kaymış imzaları reddeder) İşletim sisteminde NTP, ayrıca sunucu zamanı uç noktasına günlük bir çağrı
Emir idempotensliği Her emirde newClientOrderId kullanın
İstek sınırları Üst bilgileri izleyin; sınırın %90'ı içindeyken geri çekilin
Kill switch Tek bir boolean, kullanıcı arayüzünden veya bir watchdog sürecinden çevrilir
Denetim günlüğü Her niyet, her gerçekleşme, her reddetme, yalnızca ekleme (append-only)

Binance'in Ötesinde

TsgcWSAPI_Binance'i TsgcWSAPI_Coinbase, TsgcWSAPI_Kraken veya diğer 20+ borsa bileşeninden herhangi biriyle değiştirin. Strateji, risk kapısı ve emir çalışanı değişmez; yalnızca kimlik bilgisi kurulumu ve sembol adlandırması değişir. Kutudan çıktığı haliyle grafikler, pozisyon yönetimi ve emir yönlendirme kullanıcı arayüzüne sahip üretim sınıfı bir çoklu borsa ticaret aracı için sgcTrader örneğine bakın.

Gerçek çoklu borsa sistemleri, burada gördüğünüzün üzerine bir katman daha ekler: bir sembol normalleştirici. Binance ona BTCUSDT, Coinbase BTC-USD, Kraken XBT/USD der. Kanonik bir ad ve borsa başına takma adlarla dahili bir sembol modeli oluşturun ve API sınırında çevirin. Önceden beş dakikalık iş, sonrasında sonsuz sayıda önlenmiş hata.

Çoklu borsa işlemleri için eklenecek diğer şey, başlangıçta bir saat sapması (clock-skew) kontrolüdür. Binance, Coinbase ve diğerleri, zaman damgası sunucularından 1000 ms'den fazla sapan imzalı istekleri reddeder. NTP genellikle sizi bunun çok içinde tutar, ancak yanlış yapılandırılmış bir VPS bir saatte saniyeler kadar kayabilir. Başlangıçta sunucu zamanı uç noktasını sorgulayın, sapmayı günlüğe kaydedin, >500 ms ise ticareti reddedin.

Bunun İçin Neden Delphi?

"Neden Python'da yazmıyorsunuz?" bariz sorudur. Üretimden üç yanıt. İlk olarak, JIT ısınması ve GIL, CPython'ı düşük gecikmeli olay döngüleri için zayıf bir seçim haline getirir; Delphi'de 0,8 ms medyan gecikmeye ulaşan aynı strateji, ciddi bir çaba olmadan CPython'da 6 ms sürer. İkinci olarak, dağıtım hikayesi daha basittir: imzalı tek bir exe'ye karşı, yarısı kurulum sırasında bir C derleyicisi gerektiren yüzlerce wheel içeren bir virtualenv. Üçüncü olarak, mevcut arka ofis Delphi'dedir. Bu sınıfları (hesap defteri, K&Z hesaplayıcı, günlük, denetim günlüğü) başka bir dilde yeniden uygulamak yerine yeni botta yeniden kullanmak, bütün bir mutabakat hatası kategorisini ortadan kaldırır.

Saf araştırma ve not defteri tarzı geriye dönük testler için Python kolayca kazanır; pandas, statsmodels, vectorbt ve arkadaşlarının ekosistemi rakipsizdir. Çoğu ekip için işe yarayan ayrım: araştırma Python'da, üretim Delphi'de. Strateji mantığını küçük bir durum makinesi olarak dışa aktarın, bir kez taşıyın, savaşta test edilmiş bir Delphi çalışma zamanında çalıştırın. İki yarının sonuçları paylaşmak için bir dili paylaşması gerekmez.

Sırada Ne Okumalı

Bunu bir VPS'te 7/24 çalıştırmayı planlıyorsanız, sırada Performans Ayarlama bölümünü okuyun. En yaygın tuzaklardan kaçınmak için 10 Yaygın Hata bölümüne bakın. Ve sgcWebSockets'i henüz kurmadıysanız, Başlarken merkezi sizi beş dakikada canlı hale getirir.

Sorumluluk reddi: bu yazıdaki strateji eğitim amaçlıdır. Kripto para ticareti önemli riskler içerir. Test edilmemiş kodu gerçek sermayeyle dağıtmayın.