← Makalelere geri dön
March 23, 2026
5 dakikalık okuma

Algoritmik Ticarette Emir Türleri: Takipli Limit Emirden Sanal Emirlere

Algoritmik Ticarette Emir Türleri: Takipli Limit Emirden Sanal Emirlere
#emirler
#algotrading
#limit
#takip
#sanal-emirler
#grid-bot
#piyasa-yapıcılık

Yeni başlayan biri borsa terminalini açtığında iki düğme görür: "Al" ve "Sat." Bir algo trader kendi kod tabanını açtığında yirmi yedi emir türü, üç soyutlama katmanı ve dizüstü bilgisayarı kapatıp pazarda salatalık satmak isteğini doğuran bir yığın uç durum görür. Ama salatalık satmak, ne yazık ki, 3:59 UTC'de fonlama oranı arbitrajı yapmanıza izin vermiyor — o zaman hadi dalalım.

Bu makalede temel borsa emirlerinden başlayarak yalnızca sisteminiz içinde var olan ve emir defterinde hiç görünmeyen sentetik sanal yapılara kadar tüm yolculuğu ele alacağız. TypeScript, Python, biraz acı ve biraz aydınlanma bekleniyor.


1. Standart Borsa Emirleri: Atlanamayacak Temel

Standart emirler Standart emir türlerinin sınıflandırması: piyasa emrinden buzdağı emrine

Karmaşık bir şey inşa etmeden önce temel yapı taşlarını gerçekten anladığımızdan emin olmamız gerekiyor. Pek çok kişinin stop-limit ile stop-market'ı karıştırıp ardından stop'larının "neden tetiklenmediğini" merak etmesi şaşırtıcı (ipucu: tetiklendi, ancak limit emir kayma nedeniyle dolmadı).

Piyasa emri

En basit ve aynı zamanda en tehlikeli tür. Borsaya şunu söylüyorsunuz: "Şu anda, mevcut herhangi bir fiyattan al/sat." Borsa, en iyi fiyattan başlayarak emir defterinden likidite çekiyor. En iyi seviyedeki hacim yetmezse — daha ileriye kayıyor.

Ne zaman kullanılır: acil pozisyon çıkışı, hızın fiyattan daha önemli olduğu sinyallerin yürütülmesi.

Tuzaklar: ince bir piyasada 100 BTC'lik piyasa emri fiyatı birkaç yüzde hareket ettirebilir. Piyasa emirlerini etki hesaba katmadan modelleyen geriye dönük testler salt hayaldir.

Limit emri

Tam bir fiyat belirtiyorsunuz. Emir, emir defterine giriyor ve biri sizin fiyatınızı kabul edene kadar bekliyor. Limit alış emrinin fiyatı mevcut piyasanın üzerindeyse — hemen doluyor (piyasa emri gibi, ancak garantili bir maksimum fiyatla).

Önemli nokta: limit emri yürütmeyi garanti etmez. Fiyat seviyenize ulaşıp geri dönebilir ve sizi kuyrukta bırakabilir (kuyruk pozisyonu hakkındaki makalemizde daha fazla bilgi bulabilirsiniz).

Stop-market ve Stop-limit

Karışıklık burada başlıyor. Her iki tür de tetikleme fiyatına (stop fiyatı) ulaşıldığında etkinleşen "uyku" emirlerdir. Ancak:

  • Stop-market: tetiklendiğinde piyasa emrine dönüşür. Yürütmeyi garanti eder, ancak fiyatı değil.
  • Stop-limit: tetiklendiğinde limit emire dönüşür. Fiyatı garanti eder (belirtilenden daha kötü olmaz), ancak yürütmeyi değil.

Değişken kripto piyasasında stop-limit "ıskalanabilir" — fiyat stop'u geçti, limit emri yerleştirildi, ancak piyasa zaten uçup gitti. Geriye doldurulmamış bir limit emri ve büyüyen bir kayıpla kaldınız. Stop-limit yerine stop-market'ın stop-loss için daha yaygın kullanılmasının tam nedeni budur.

İzleyen stop

Belirlenen bir mesafede fiyatı "takip eden" bir stop. Fiyat yükseliyor — stop yukarı hareket ediyor. Fiyat düşüyor — stop yerinde kalıyor. Trend takip stratejilerinde kârları korumak için yararlıdır.

Borsa desteği: tüm borsalar yerel izleyen stopları desteklemiyor. Algo traderlar bunları sıklıkla programatik olarak uygular — bu, parametreler üzerinde daha fazla kontrol sağlar (geri çekilme oranı, aktivasyon fiyatı, adım boyutu).

Buzdağı emri

Toplam hacmin yalnızca bir kısmının emir defterinde göründüğü bir emir. 1.000 BTC satın almak istiyorsunuz, ancak defterde yalnızca 10 gösteriyorsunuz. İlk 10 dolduğunda — sonraki 10 görünüyor.

Neden: gerçek niyetlerinizi piyasadan gizlemek için. Defterdeki büyük bir emir herkese "biri büyük miktarda almak/satmak istiyor" sinyalini verir. Buna yanıt olarak HFT algoritmaları ön-çalıştırmaya başlar ve fiyat sizden uzaklaşır.

Uyarı: pek çok kripto borsasında buzdağı emirleri ya desteklenmiyor ya da özdeş hacim örüntüleriyle kolayca tespit ediliyor. Gelişmiş algoritmalar görünür kısım boyutunu rastgele seçiyor.

Zaman-geçerlilik parametreleri: GTC, GTD, IOC, FOK

Bunlar ayrı emir türleri değil, zaman-geçerlilik parametreleridir — bir emrin ne kadar süre yaşadığını belirtir:

Parametre Tam Adı Davranış
GTC Good Till Cancelled (İptal Edilene Kadar) İptal edilene kadar yaşar. Varsayılan standart
GTD Good Till Date (Tarihe Kadar) Belirtilen tarih/saate kadar yaşar
IOC Immediate or Cancel (Hemen veya İptal) Hemen yürütür (tamamen veya kısmen), kalan iptal edilir
FOK Fill or Kill (Doldur veya Öldür) Yalnızca tam ve anında yürütür. Mümkün değilse — tamamen iptal edilir

IOC ile FOK farkı: kritiktir. IOC kısmen dolabilir — 100 BTC almak istediniz, 3 aldınız, geri kalan iptal edildi. FOK ya 100'ün tamamı ya da hiçbir şey.

Post-only (Yalnızca Yapıcı)

Emir defterine yapıcı olarak girmeyi kesinlikle garanti eden ve asla alıcı olarak yürütülmeyen bir emir. Yerleştirme anında fiyat anında yürütmeye neden olacaksa — borsa onu reddeder (veya fiyatı ayarlar, borsaya bağlı olarak).

Neden: yapıcı ücretleri genellikle alıcı ücretlerinden düşüktür (Binance'da VIP kademeleri için %0,02'ye karşı %0,04). Günde binlerce emir veren bir piyasa yapıcı için ücret farkı kâr ile zarar arasındaki fark anlamına gelir.


2. TWAP ve VWAP: Kurumlar Emir Defterinde Fili Nasıl Saklar

Bir hedge fon 50 milyon dolarlık pozisyon almak istediğinde tek bir piyasa emri vermez. Büyük bir emri pek çok küçük emre bölen ve piyasa etkisini minimize ederek bunları zaman içinde yürüten yürütme algoritmalarını kullanır.

TWAP (Zamana Göre Ağırlıklı Ortalama Fiyat)

Fikir son derece basit: toplam hacmi eşit parçalara bölün ve eşit zaman aralıklarında yürütün.

import asyncio
from datetime import datetime, timedelta

class TWAPExecutor:
    """
    TWAP yürütücü: büyük bir emri eşit parçalara böler
    ve eşit zaman aralıklarında yürütür.
    """
    def __init__(self, exchange, symbol: str, side: str,
                 total_qty: float, duration_minutes: int, num_slices: int):
        self.exchange = exchange
        self.symbol = symbol
        self.side = side
        self.total_qty = total_qty
        self.slice_qty = total_qty / num_slices
        self.interval = (duration_minutes * 60) / num_slices
        self.num_slices = num_slices
        self.executed_qty = 0.0
        self.fills: list[dict] = []

    async def execute(self):
        for i in range(self.num_slices):
            remaining = self.total_qty - self.executed_qty
            qty = min(self.slice_qty, remaining)
            if qty <= 0:
                break

            try:
                order = await self.exchange.create_order(
                    symbol=self.symbol,
                    type="market",
                    side=self.side,
                    amount=qty,
                )
                self.executed_qty += float(order["filled"])
                self.fills.append(order)
                print(f"[TWAP] dilim {i+1}/{self.num_slices}: "
                      f"dolduruldu {order['filled']} @ {order['average']}")
            except Exception as e:
                print(f"[TWAP] dilim {i+1} başarısız: {e}")

            if i < self.num_slices - 1:
                await asyncio.sleep(self.interval)

        avg_price = (
            sum(f["cost"] for f in self.fills) /
            sum(f["filled"] for f in self.fills)
        ) if self.fills else 0
        print(f"[TWAP] tamamlandı: {self.executed_qty}/{self.total_qty} "
              f"ortalama fiyat: {avg_price:.2f}")

VWAP (Hacme Göre Ağırlıklı Ortalama Fiyat)

VWAP daha akıllıdır: tipik işlem hacmi profilini dikkate alır. Günlük hacmin %30'u genellikle 9:00 ile 10:00 arasında işlem görüyorsa, VWAP o zaman diliminde emrin %30'unu yürütür. Amaç, ortalama yürütme fiyatını piyasa VWAP'ına olabildiğince yakın tutmaktır.

class VWAPExecutor:
    """
    VWAP yürütücü: hacmi tarihsel hacim profiline
    orantılı olarak dağıtır.
    """
    def __init__(self, exchange, symbol: str, side: str,
                 total_qty: float, volume_profile: list[float]):
        self.exchange = exchange
        self.symbol = symbol
        self.side = side
        self.total_qty = total_qty
        total_weight = sum(volume_profile)
        self.weights = [w / total_weight for w in volume_profile]

    async def execute(self, interval_seconds: float = 60.0):
        executed = 0.0
        for i, weight in enumerate(self.weights):
            qty = self.total_qty * weight
            remaining = self.total_qty - executed
            qty = min(qty, remaining)

            if qty <= 0:
                break

            order = await self.exchange.create_order(
                symbol=self.symbol,
                type="market",
                side=self.side,
                amount=qty,
            )
            executed += float(order["filled"])
            print(f"[VWAP] dönem {i+1}: ağırlık={weight:.2%}, "
                  f"dolduruldu={order['filled']} @ {order['average']}")

            await asyncio.sleep(interval_seconds)

TWAP ile VWAP farkı: TWAP daha basit ve öngörülebilirdir. VWAP daha iyi bir ortalama fiyat sunar, ancak güvenilir bir hacim profili gerektirir. Hacimlerin yapay şişirilebileceği kripto piyasasında VWAP profili dikkatli oluşturulmalıdır.


3. Takipli Limit: Emiriniz Fiyatı Kovalamayı Bildiğinde

Takipli limit emirler Takipli limit: emir, yapılandırılabilir agresiflikle hareket eden fiyatı kovalıyor

Şimdi işler gerçekten ilginçleşiyor. Standart bir limit emri pasif bir varlıktır: emir defterinde oturur ve bekler. Fiyat hareket ettiyse — emir doldurulmamış kalır. Algo trader için bu genellikle kabul edilemez: giriş sinyali ateşlendi, ancak piyasa %0,1 hareket ettiği için pozisyon oluşturulmadı.

Takipli limit emri, bir limit etrafında programatik bir sarmalayıcıdır:

  1. Mevcut en iyi fiyata (veya küçük bir ofsetle) limit emri yerleştirir
  2. WebSocket aracılığıyla fiyatı izler
  3. Fiyat emirden uzaklaşırsa — iptal edip mevcut fiyata daha yakın yeniden yerleştirir
  4. Emir dolana veya izin verilen sapma aşılana kadar tekrar eder

Temel Parametreler

  • chase_interval_ms — emri ne sıklıkla kontrol edip değiştireceğiniz. 100ms — agresif, 1000ms — gevşek.
  • max_chase_distance — emrin iptal edilmesinden önceki başlangıç fiyatından maksimum sapma. Kaçan piyasayı kovalamaya karşı koruma.
  • aggression_level — limit emrini piyasa fiyatına ne kadar yakın yerleştireceğiniz. 0 — en iyi alış/satışta (pasif), 1 — spreadi geçiyor (agresif, fiilen alıcı).
  • chase_on_partial — emir kısmen dolduysa kovalamaya devam edilip edilmeyeceği.

TypeScript Uygulaması

interface ChasingOrderParams {
  symbol: string;
  side: "buy" | "sell";
  totalQty: number;
  /** 0 = pasif (en iyi alış/satışta), 1 = spreadi geç */
  aggression: number;
  /** başlangıç fiyatından maksimum fiyat sapması */
  maxChaseDistance: number;
  /** yeniden değerlendirme sıklığı, ms */
  chaseIntervalMs: number;
  /** bu ms sonra kovalamayı durdur */
  timeoutMs: number;
}

class ChasingLimitOrder {
  private currentOrderId: string | null = null;
  private filledQty = 0;
  private initialPrice: number | null = null;
  private startTime = Date.now();

  constructor(
    private exchange: any, // ccxt exchange örneği
    private params: ChasingOrderParams
  ) {}

  async execute(): Promise<{ filledQty: number; avgPrice: number }> {
    const fills: Array<{ qty: number; price: number }> = [];

    while (this.filledQty < this.params.totalQty) {
      // Zaman aşımı
      if (Date.now() - this.startTime > this.params.timeoutMs) {
        console.log("[CHASE] zaman aşımına ulaşıldı, iptal ediliyor");
        await this.cancelCurrent();
        break;
      }

      // Mevcut emir defterini al
      const book = await this.exchange.fetchOrderBook(
        this.params.symbol, 5
      );
      const bestBid = book.bids[0][0];
      const bestAsk = book.asks[0][0];
      const spread = bestAsk - bestBid;

      // Hedef fiyatı hesapla
      let targetPrice: number;
      if (this.params.side === "buy") {
        targetPrice = bestBid + spread * this.params.aggression;
      } else {
        targetPrice = bestAsk - spread * this.params.aggression;
      }

      // Başlangıç fiyatını hatırla
      if (this.initialPrice === null) {
        this.initialPrice = targetPrice;
      }

      // Maksimum kovalam mesafesini kontrol et
      const deviation = Math.abs(targetPrice - this.initialPrice);
      if (deviation > this.params.maxChaseDistance) {
        console.log(
          `[CHASE] maksimum sapma aşıldı: ${deviation.toFixed(4)} > ` +
          `${this.params.maxChaseDistance}`
        );
        await this.cancelCurrent();
        break;
      }

      // Mevcut emri kontrol et
      if (this.currentOrderId) {
        const order = await this.exchange.fetchOrder(
          this.currentOrderId, this.params.symbol
        );

        if (order.status === "closed") {
          fills.push({ qty: order.filled, price: order.average });
          this.filledQty += order.filled;
          this.currentOrderId = null;
          continue;
        }

        // Kısmi dolgular için filledQty güncelle
        if (order.filled > 0) {
          const newFilled = order.filled - (
            fills.reduce((s, f) => s + f.qty, 0) - this.filledQty
          );
          // Emir yerinde — yeniden fiyatlandırmaya gerek var mı?
        }

        const currentPrice = parseFloat(order.price);
        const priceDiff = Math.abs(currentPrice - targetPrice);
        const tickSize = spread * 0.1 || 0.01;

        if (priceDiff > tickSize) {
          // Fiyat hareket etti — yeniden fiyatlandır
          console.log(
            `[CHASE] yeniden fiyatlandırılıyor: ${currentPrice} -> ` +
            `${targetPrice.toFixed(4)}`
          );
          await this.cancelCurrent();
        } else {
          // Emir doğru fiyatta — bekle
          await this.sleep(this.params.chaseIntervalMs);
          continue;
        }
      }

      // Yeni emir ver
      const remainingQty = this.params.totalQty - this.filledQty;
      const order = await this.exchange.createLimitOrder(
        this.params.symbol,
        this.params.side,
        remainingQty,
        targetPrice
      );
      this.currentOrderId = order.id;
      console.log(
        `[CHASE] ${this.params.side} ${remainingQty} verildi ` +
        `@ ${targetPrice.toFixed(4)}`
      );

      await this.sleep(this.params.chaseIntervalMs);
    }

    const totalCost = fills.reduce((s, f) => s + f.qty * f.price, 0);
    const avgPrice = this.filledQty > 0 ? totalCost / this.filledQty : 0;
    return { filledQty: this.filledQty, avgPrice };
  }

  private async cancelCurrent(): Promise<void> {
    if (this.currentOrderId) {
      try {
        await this.exchange.cancelOrder(
          this.currentOrderId, this.params.symbol
        );
      } catch { /* emir zaten doldu veya iptal edildi */ }
      this.currentOrderId = null;
    }
  }

  private sleep(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }
}

Takibin Zararlı Olduğu Durumlar

Takip güçlü bir araçtır, ancak kolayca kayıp üreticisine dönüşebilir:

  1. İptal/değiştirme spam'i. Her iptal ve değiştirme API üzerinde bir yüktür. Borsalar istekleri hız sınırlar ve agresif takip API anahtarınızın yasaklanmasına yol açabilir.
  2. Ters seçim. Fiyat sizden kaçıyorsa — piyasa sizin bilmediğiniz bir şey biliyor olabilir. Bu durumda fiyatı kovalamak tepede almak demektir.
  3. Yapıcıdan Alıcıya geçiş. Yüksek agresiflikle fiilen alıcı ücretleri ödüyorsunuz, ancak gecikmeyle (iptal + yeni emir). Bazen sadece piyasa emri vermek daha basittir.

4. Zamana Dayalı Emirler: Milisaniye Hassasiyeti

Bir emri "X fiyatında" değil "T zamanında" yürütmeniz gereken durumlar vardır. Garip mi geliyor? Bu aslında başlı başına bir strateji sınıfıdır.

Kullanım senaryoları

Fonlama oranı arbitrajı. Sürekli vadeli işlemlerde fonlama her 8 saatte bir ödenir (Binance'da 00:00, 08:00, 16:00 UTC). Fonlama oranı = +%0,1 ise uzlaşma anında kısa pozisyonda olmanız gerekir. Strateji: uzlaşmadan birkaç saniye önce kısa aç, fondlamayı topla, pozisyonu kapat. Zamanlama kritiktir — bir saniyelik gecikme kaçırılmış fonlama demektir.

Seans açılış/kapanışları. Geleneksel piyasalarda ve bazı kripto türevlerinde sabit seanslar vardır. Açılış müzayedesi (NYSE, CME) likiditanin zirveye ulaştığı andır. Müzayededen 100ms önce emir vermek bir avantajdır.

Habere dayalı yürütme. Enflasyon verileri planlanmış bir zamanda açıklanıyor. Algoritma sayıyı haber akışından ayrıştırıyor ve 50ms içinde emir veriyor. Burada zamana dayalı yürütme olaya dayalı mantıkla birleşiyor.

Uygulama

class TimeBasedOrder {
  constructor(
    private exchange: any,
    private symbol: string,
    private side: "buy" | "sell",
    private qty: number,
    private orderType: "market" | "limit",
    private limitPrice?: number
  ) {}

  /**
   * Tam bir zamanda yürütmeyi planla.
   * Maksimum hassasiyet için meşgul-bekleme döngüsü kullanır.
   */
  async executeAt(targetTime: Date): Promise<any> {
    const targetMs = targetTime.getTime();

    // Aşama 1: kaba bekleme (uyku)
    const coarseWait = targetMs - Date.now() - 500; // 500ms önce uyan
    if (coarseWait > 0) {
      console.log(
        `[TIME-ORDER] ${(coarseWait / 1000).toFixed(1)}s uyuyor`
      );
      await new Promise((r) => setTimeout(r, coarseWait));
    }

    // Aşama 2: hassas bekleme (meşgul-bekleme)
    while (Date.now() < targetMs) {
      // döngü — CPU yakar, ancak ~1ms hassasiyet sağlar
    }

    // Aşama 3: yürütme
    const sendTime = Date.now();
    const order = await this.exchange.createOrder(
      this.symbol,
      this.orderType,
      this.side,
      this.qty,
      this.limitPrice
    );

    console.log(
      `[TIME-ORDER] ${new Date(sendTime).toISOString()} tarihinde yürütüldü, ` +
      `hedef ${targetTime.toISOString()} idi, ` +
      `delta: ${sendTime - targetMs}ms`
    );

    return order;
  }
}

// Örnek: tam 00:00:00 UTC'de emir ver (fonlama uzlaşması)
const executor = new TimeBasedOrder(exchange, "BTC/USDT", "sell", 0.1, "market");
const target = new Date("2026-03-24T00:00:00.000Z");
await executor.executeAt(target);

Önemli uyarı: zamana dayalı emrin hassasiyeti kodunuzla değil, borsaya olan ağ gecikmesiyle sınırlıdır. API'ye ping'iniz 50ms ise mükemmel bir meşgul-bekleme bile 50ms delta üretecektir. Ciddi HFT için ortak yerleşim kullanılır — sunucu, borsanın eşleştirme motorunun fiziksel olarak yanında durur.


5. Sanal/Sentetik Emirler: Sisteminizdeki Görünmezler

Grid botlar için sanal emirler Sanal emirler: emirler tetikleyici ateşlenene kadar yalnızca botun belleğinde yaşar

Bu, algo trader'ın cephaneliğindeki en az takdir edilen araç olabilir. Sanal emir (sentetik emir olarak da bilinir), yalnızca sisteminizde var olan bir emirdir. Bir tetikleme koşulu karşılanana kadar borsaya gönderilmez (genellikle — fiyat belirli bir seviyeye ulaşır).

Nasıl Çalışır

  1. Algoritmanız karar verir: "40.000 dolara BTC almak istiyorum"
  2. Borsaya limit emri göndermek yerine bellekte sanal bir emir oluşturur
  3. WebSocket fiyat akışına abone olur
  4. Alış/satış 40.000 dolara ulaştığında — borsaya gerçek bir piyasa veya limit emri gönderir

Sanal Emirler Neden Önemli

Bilgi sızıntısı yok. Emiriniz emir defterinde görünmez. Hiç kimse — diğer traderlar, HFT algoritmaları, hatta borsanın kendisi bile — yürütme anına kadar niyetlerinizden haberdar değil. Bu, güç dengesini temelden değiştiriyor.

Ön-çalıştırmaya karşı koruma. Kripto borsalarında, özellikle daha az şeffaf olanlarda, büyük limit emirler hakkındaki bilgilerin ön-çalıştırma için kullanılabileceğine dair makul şüpheler var (bu konuda araştırmalar bile var). Sanal emirler bu riski ortadan kaldırıyor.

Grid botlar. Klasik bir grid bot, farklı fiyat seviyelerine 50-200 emir verir. Hepsini borsaya gönderirseniz — defterde 200 emir olur: (a) herkese görünür, (b) borsadaki emir limitini kullanır (genellikle hesap başına 200-300 açık emir), (c) fiyat ani hareket ederse hepsi dolar ve büyük bir pozisyonla kalırsınız. Sanal emirler bu üç sorunu da çözüyor.

Düşen bıçakları yakalamak. Strateji: mevcut fiyatın -%5, -%10, -%15 altındaki seviyelere sanal alış emirleri verin. Piyasa düşerse — emirler kademeli olarak tetiklenir. Düşmezse — hiçbir risk almaz ve borsa emir yuvalarını kullanmazsınız.

TypeScript Uygulaması

interface VirtualOrder {
  id: string;
  symbol: string;
  side: "buy" | "sell";
  triggerPrice: number;
  qty: number;
  /** Tetiklendiğinde borsaya gönderilen emir türü */
  executionType: "market" | "limit";
  /** Limit için: tetikleme fiyatından ofset */
  limitOffset?: number;
  status: "pending" | "triggered" | "filled" | "failed";
}

class VirtualOrderManager {
  private orders: Map<string, VirtualOrder> = new Map();
  private orderCounter = 0;

  constructor(private exchange: any) {}

  /**
   * Sanal emir oluştur. Borsaya hiçbir şey gönderilmez.
   */
  addOrder(params: Omit<VirtualOrder, "id" | "status">): string {
    const id = `virt_${++this.orderCounter}`;
    this.orders.set(id, { ...params, id, status: "pending" });
    console.log(
      `[VIRTUAL] ${params.side} ${params.qty} oluşturuldu ` +
      `${params.symbol} @ tetikleyici ${params.triggerPrice}`
    );
    return id;
  }

  /**
   * Her fiyat tickinde çağrılır (WebSocket'ten).
   */
  async onPriceUpdate(
    symbol: string, bestBid: number, bestAsk: number
  ): Promise<void> {
    for (const [id, order] of this.orders) {
      if (order.symbol !== symbol || order.status !== "pending") continue;

      const triggered =
        (order.side === "buy" && bestAsk <= order.triggerPrice) ||
        (order.side === "sell" && bestBid >= order.triggerPrice);

      if (!triggered) continue;

      order.status = "triggered";
      console.log(
        `[VIRTUAL] ${id} tetiklendi! bid=${bestBid} ask=${bestAsk}`
      );

      try {
        let realOrder: any;

        if (order.executionType === "market") {
          realOrder = await this.exchange.createMarketOrder(
            order.symbol, order.side, order.qty
          );
        } else {
          const limitPrice = order.side === "buy"
            ? order.triggerPrice + (order.limitOffset ?? 0)
            : order.triggerPrice - (order.limitOffset ?? 0);
          realOrder = await this.exchange.createLimitOrder(
            order.symbol, order.side, order.qty, limitPrice
          );
        }

        order.status = "filled";
        console.log(
          `[VIRTUAL] ${id} dolduruldu: ${realOrder.filled} ` +
          `@ ${realOrder.average ?? realOrder.price}`
        );
      } catch (err) {
        order.status = "failed";
        console.error(`[VIRTUAL] ${id} yürütme başarısız:`, err);
      }
    }
  }

  /**
   * Tüm aktif sanal emirleri al.
   */
  getPendingOrders(): VirtualOrder[] {
    return [...this.orders.values()].filter(
      (o) => o.status === "pending"
    );
  }

  cancelOrder(id: string): boolean {
    const order = this.orders.get(id);
    if (order && order.status === "pending") {
      this.orders.delete(id);
      return true;
    }
    return false;
  }
}

// --- Örnek: Sanal emirlerle Grid bot ---

async function gridBot(exchange: any) {
  const manager = new VirtualOrderManager(exchange);
  const currentPrice = 42000;
  const gridStep = 200;      // grid adımı
  const gridLevels = 20;     // her yönde seviye sayısı
  const qtyPerLevel = 0.01;  // seviye başına BTC

  // Sanal grid oluştur
  for (let i = 1; i <= gridLevels; i++) {
    // Mevcut fiyatın altında alış emirleri
    manager.addOrder({
      symbol: "BTC/USDT",
      side: "buy",
      triggerPrice: currentPrice - gridStep * i,
      qty: qtyPerLevel,
      executionType: "limit",
      limitOffset: 1,  // limit fiyat = tetikleyici + 1 USDT
    });

    // Mevcut fiyatın üzerinde satış emirleri
    manager.addOrder({
      symbol: "BTC/USDT",
      side: "sell",
      triggerPrice: currentPrice + gridStep * i,
      qty: qtyPerLevel,
      executionType: "limit",
      limitOffset: 1,
    });
  }

  console.log(
    `[GRID] ${gridLevels * 2} sanal emir oluşturuldu, ` +
    `borsada 0`
  );

  // WebSocket aboneliği (ccxt.pro için sözde kod)
  while (true) {
    const ticker = await exchange.watchTicker("BTC/USDT");
    await manager.onPriceUpdate(
      "BTC/USDT", ticker.bid, ticker.ask
    );
  }
}

Sanal Emirlerin Tuzakları

  1. Gecikme boşluğu. Fiyatı gördüğünüz an ile gerçek emrin borsaya ulaştığı an arasında zaman geçer. Değişken bir piyasada fiyat o 20-100ms'de kaçıp gidebilir. Çözüm: biraz agresif bir limit emri gönderin (tampon ile).

  2. Kaçırılan dolgular. Fiyat seviyenizi tek bir tickte "deldiyse" (flash crash) ve geri döndüyse — zamanında tepki veremeyebilirsiniz. Defterde bekleyen normal bir limit emri dolardı; sanal bir emir — dolmayacak.

  3. Durum yönetimi. Sanal emirler bellekte yaşar. Süreç çökerse — emirler kaybolur. Çözüm: yeniden başlatmada kurtarma ile kalıcı depolama (Redis, SQLite, dosya).


6. Koşullu/Akıllı Emirler: Emir Kombinatorikleri

Tek bir emir yetmediğinde, traderlar bunları koşullu yapılara birleştirir. Bazıları borsalarda yerel olarak desteklenir, diğerleri programatik olarak uygulanır.

OCO (Biri İptal Eder Diğerini)

İki emir birbirine bağlıdır: biri yürütülürse — diğeri otomatik olarak iptal edilir. Klasik örnek: uzun pozisyondasınız ve hem kâr al hem de zarar durdur ayarlamak istiyorsunuz. Hangisi önce tetiklenirse — diğeri iptal edilmelidir.

class OCOHandler:
    """
    OCO: bir emir dolduğunda diğeri iptal edilir.
    """
    def __init__(self, exchange, symbol: str):
        self.exchange = exchange
        self.symbol = symbol
        self.order_a_id: str | None = None
        self.order_b_id: str | None = None

    async def place(
        self,
        take_profit_price: float,
        stop_loss_price: float,
        qty: float,
    ):
        tp = await self.exchange.create_limit_sell_order(
            self.symbol, qty, take_profit_price
        )
        self.order_a_id = tp["id"]

        sl = await self.exchange.create_order(
            self.symbol, "stop", "sell", qty,
            None, {"stopPrice": stop_loss_price}
        )
        self.order_b_id = sl["id"]

        print(f"[OCO] TP @ {take_profit_price}, SL @ {stop_loss_price}")

    async def monitor(self):
        """Durumları kontrol eder ve eşleşen emri iptal eder."""
        while True:
            if self.order_a_id:
                a = await self.exchange.fetch_order(
                    self.order_a_id, self.symbol
                )
                if a["status"] == "closed":
                    print("[OCO] kâr al doldu, zarar durdur iptal ediliyor")
                    await self.exchange.cancel_order(
                        self.order_b_id, self.symbol
                    )
                    break

            if self.order_b_id:
                b = await self.exchange.fetch_order(
                    self.order_b_id, self.symbol
                )
                if b["status"] == "closed":
                    print("[OCO] zarar durdur doldu, kâr al iptal ediliyor")
                    await self.exchange.cancel_order(
                        self.order_a_id, self.symbol
                    )
                    break

            await asyncio.sleep(0.5)

Bracket emri

Üç bileşenli yapı: birincil giriş emri + çıkış için OCO (kâr al + zarar durdur). Özünde, tek bir çağrıda tam bir işlem yaşam döngüsü:

  1. Giriş: limit alış emri
  2. Kâr al: limit satış emri (üstte)
  3. Zarar durdur: stop-market satış emri (altta)

Giriş dolduğunda, TP ve SL otomatik olarak yerleştirilir. Herhangi biri dolduğunda — diğeri iptal edilir.

If-Then Mantığı

En esnek seçenek — keyfi koşullarla emir zincirleri:


rules = [
    {
        "condition": {"symbol": "BTC/USDT", "price_above": 50000},
        "action": {"type": "market_buy", "symbol": "ETH/USDT", "qty": 10},
        "then": [
            {
                "condition": {"symbol": "ETH/USDT", "price_above": 4000},
                "action": {"type": "market_sell", "symbol": "ETH/USDT", "qty": 10},
            },
            {
                "condition": {"symbol": "ETH/USDT", "price_below": 3500},
                "action": {"type": "market_sell", "symbol": "ETH/USDT", "qty": 10},
            },
        ]
    }
]

Bu tür yapılar hiçbir borsada yerel olarak desteklenmiyor — yalnızca programatik uygulama. Bu, algotrading sistemlerinin kaçınılmaz olarak kendi emir yönetim katmanlarını büyütmesinin nedenlerinden biri.


7. Piyasa Yapıcılar Özel Emir Türlerini Nasıl Kullanır

Piyasa yapıcılık kendi evrenini oluşturur ve emir araç seti de buna uygun. Piyasa yapıcının işi, sürekli olarak alış ve satış teklifleri sunmak, spreadden kazanırken ters seçimi (bilgili bir trader'ın size karşı işlem yapması durumu) minimize etmektir.

Post-only Zorunluluk Olarak

Piyasa yapıcı için post-only bir seçenek değil — bir zorunluluktur. Emiriniz kazara alıcı olarak yürütülürse — yapıcı geri ödemesi almak yerine alıcı ücreti ödersiniz. Günde binlerce emir boyunca bu feci sonuçlar doğurur.

async def quote(exchange, symbol, mid_price, half_spread, qty):
    bid_price = mid_price - half_spread
    ask_price = mid_price + half_spread

    bid = await exchange.create_order(
        symbol, "limit", "buy", qty, bid_price,
        {"postOnly": True}  # Piyasa yapıcılar için KRİTİK
    )
    ask = await exchange.create_order(
        symbol, "limit", "sell", qty, ask_price,
        {"postOnly": True}
    )
    return bid, ask

Gizli emirler

Bazı borsalarda (Kraken, Bitfinex) gizli emirler mevcuttur — emir defterinde görünmezler, ancak borsadadırlar ve eşleştirmeye katılırlar. Ödün: yapıcı olsanız bile alıcı ücreti ödersiniz, ancak anonimlik kazanırsınız.

Piyasa yapıcı için bu bir envanter yönetim aracıdır: büyük bir pozisyon birikirse, piyasaya niyetinizi açıklamadan onu boşaltmak için gizli bir emir verebilirsiniz.

Sabitlenmiş emirler

En iyi alış/satışa sabitlenmiş bir emir. Örneğin Coinbase Advanced Trade'de en iyi alışı otomatik takip eden ve her zaman kuyruğun önünde duran bir emir verebilirsiniz. Bu, borsa düzeyinde yerel bir takip emridir — ancak evrensel olarak mevcut değil.

Toplu emir yönetimi

Profesyonel piyasa yapıcılar, tek bir HTTP isteğinde onlarca emri aynı anda iptal edip vermek için toplu API'leri kullanır. Binance'da bu batchOrders, Bybit'te — place-batch-order. Bu, gecikmeyi ve hız sınırı baskısını azaltır.


8. Emir Türü Karşılaştırma Tablosu

Emir Türü Yürütme Garantisi Fiyat Garantisi Defterde Görünür Borsalarda Yerel Uygulama Karmaşıklığı
Piyasa Evet Hayır Hayır (anında) Evet Yok
Limit Hayır Evet Evet Evet Yok
Stop-market Evet (tetiklemeden sonra) Hayır Hayır Evet Yok
Stop-limit Hayır Evet Hayır (tetikleyene kadar) Evet Yok
İzleyen stop Evet (tetiklemeden sonra) Hayır Hayır Kısmi Düşük
Buzdağı Hayır Evet Kısmi Kısmi Orta
Post-only Hayır Evet Evet Evet Yok
TWAP Hayır (dilimlere bağlı) Hayır Kısmi Hayır Orta
VWAP Hayır Hayır Kısmi Hayır Yüksek
Takipli limit Limitten yüksek Kısmi Evet (mevcut emir) Hayır Orta
Zamana dayalı Türe bağlı Türe bağlı Hayır (T zamanına kadar) Hayır Düşük
Sanal/Sentetik Limitten düşük Türe bağlı Hayır Hayır Orta
OCO Evet (ikiden biri) Kısmi Evet (ikisi de) Kısmi Orta
Bracket Evet Kısmi Evet Nadir Yüksek
Gizli Hayır Evet Hayır Nadir Yok
Sabitlenmiş Hayır Dinamik Evet Çok nadir Yüksek (programatikse)

Sonuç: Emir, Strateji Yapı Taşı Olarak

Emir türleri yalnızca "bir arayüzdeki düğmeler" değil. Bunlar, herhangi bir ticaret sisteminin yürütme katmanının inşa edildiği temel ilkellerdir. "Strateji geriye dönük testte kârlı" ile "strateji üretimde kârlı" arasındaki fark çoğunlukla tam burada yatar — emirleri borsaya tam olarak nasıl gönderdiğinizde.

Birkaç pratik çıkarım:

  1. Standart emirlerle başlayın, nüansları anladığınızdan emin olun (stop-limit ile stop-market, IOC ile FOK). Çoğu hata burada oluyor.
  2. Sanal emirler grid botlar için zorunluluktur. 50'den fazla emir veriyorsanız — hepsini borsaya göndermeyin.
  3. Takip, doldurma oranı fiyattan daha önemli olduğunda gereklidir. Ancak her zaman max_chase_distance belirleyin — aksi takdirde çok uzaklara sürüklenebilirsiniz.
  4. Zamana dayalı yürütme, fonlama arbitrajı ve olaya dayalı stratejiler için niş ama güçlüdür.
  5. Özel emir yönetim katmanı, herhangi bir ciddi algotrading sistemi için kaçınılmazdır. Borsada yerel emir türleri yetmez.

Bir ticaret sistemi kuruyorsanız ve daha derine inmek istiyorsanız — emir defterinde kuyruk pozisyonu, CCXT'de WebSocket yöntemleri ve fonlama oranı arbitrajı hakkındaki makalelerimize göz atın.


Kaynaklar ve Referanslar

Sorumluluk Reddi: Bu makalede sağlanan bilgiler yalnızca eğitim ve bilgilendirme amaçlıdır ve finansal, yatırım veya ticaret tavsiyesi niteliği taşımaz. Kripto para ticareti önemli bir kayıp riski içerir.

Yazarlar

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

Piyasanın Önünde Olun

Özel yapay zeka ticaret içgörüleri, piyasa analizi ve platform güncellemeleri için bültenimize abone olun.

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.