← Maqolalarga qaytish
March 23, 2026
5 daqiqa o'qish

Algoritmik Treydingda Order Turlari: Chasing bilan Limitdan Virtual Orderlargacha

Algoritmik Treydingda Order Turlari: Chasing bilan Limitdan Virtual Orderlargacha
#orders
#algotrading
#limit
#chasing
#virtual-orders
#grid-bot
#market-making
📖
Part 2 of 6 · Collection
Order Book & Market Microstructure

Yangi boshlovchi birja terminalini ochganda, ikkita tugmani ko'radi: "Sotib olish" va "Sotish". Algo-treyder o'z kodini ochganda esa, yigirma yettita order turini, uchta abstraksiya darajasini va noutbukni yopib, bozorda bodring sotgisi keladigan bir dasta chekka holatlarni ko'radi. Ammo bodringlar, afsuski, sizga 3:59 UTC da funding stavkasi arbitraji o'tkazishga imkon bermaydi — shuning uchun mavzuga o'tamiz.

Ushbu maqolada biz oddiy birja orderlaridan tortib, faqat sizning tizimingiz ichida mavjud bo'lgan va hech qachon order kitobida ko'rinmaydigan sintetik virtual konstruksiyalargacha bo'lgan butun yo'lni bosib o'tamiz. TypeScript, Python, biroz og'riq va bir oz ma'rifat kutmoqda.


1. Standart Birja Orderlari: O'tkazib Yuborib Bo'lmaydigan Asos

Standart orderlar Standart order turlarining tasnifi: marketdan icebergga qadar

Murakkab narsa qurishdan oldin, asosiy qurilish bloklarini to'g'ri tushunganimizga ishonch hosil qilishimiz kerak. Qancha odam stop-limit va stop-marketni chalkashtirib yuborishi va keyin nega o'z stopi "ishlamaganini" ajablanishi hайratlanarli (spoyler: u ishlagan, lekin limit order sirpanish (slippage) tufayli bajarilmagan).

Market order

Eng oddiy va shu bilan birga eng xavfli tur. Siz birjaga aytasiz: "hozir, mavjud bo'lgan har qanday narxda sotib ol/sot." Birja order kitobidan likvidlikni eng yaxshi narxdan boshlab oladi. Agar eng yaxshi darajadagi hajm yetarli bo'lmasa — u yanada pastroqqa siljiydi.

Qachon ishlatish kerak: shoshilinch pozitsiyadan chiqish, tezlik narxdan muhimroq bo'lgan signalni bajarish.

Xavflar: yupqa bozorda 100 BTC uchun market order narxni bir necha foizga siljitishi mumkin. Ta'sirni hisobga olmasdan market orderlarni modellashtiruvchi backtestlar sof xayoldir.

Limit order

Siz aniq narxni ko'rsatasiz. Order order kitobiga kiradi va kimdir sizning narxingizga rozi bo'lguncha kutadi. Agar limit-bid orderning narxi joriy bozordan yuqori bo'lsa — u darhol bajariladi (market order kabi, lekin kafolatlangan maksimal narx bilan).

Muhim jihat: limit order bajarilishini kafolatlamaydi. Narx sizning darajangizga yetib, orqaga qaytishi mumkin, sizni navbatda qoldirib (navbat pozitsiyasi haqidagi maqolamizda batafsilroq).

Stop-market va Stop-limit

Aynan shu yerda chalkashlik boshlanadi. Ikkala tur ham trigger narxi (stop price) yetganda faollashadigan "uxlab yotgan" orderlar hisoblanadi. Ammo:

  • Stop-market: ishga tushganda market orderga aylanadi. Bajarilishni kafolatlaydi, lekin narxni emas.
  • Stop-limit: ishga tushganda limit orderga aylanadi. Narxni kafolatlaydi (ko'rsatilganidan yomonroq bo'lmaydi), lekin bajarilishni emas.

O'zgaruvchan kripto bozorida stop-limit "o'tkazib yuborishi" mumkin — narx stopni yorib o'tdi, limit order joylashtirildi, lekin bozor allaqachon uchib o'tdi. Sizda bajarilmagan limit order va o'sib borayotgan zarar qoladi. Aynan shuning uchun stop-loss uchun ko'proq stop-market ishlatiladi.

Trailing stop

Narxni belgilangan masofada "kuzatib boruvchi" stop. Narx ko'tariladi — stop ham yuqoriga siljiydi. Narx tushadi — stop joyida qoladi. Trend bo'yicha strategiyalarda foydani himoya qilish uchun foydali.

Birja qo'llab-quvvatlashi: hamma birjalar ham tabiiy trailing stopni qo'llab-quvvatlamaydi. Algo-treyderlar ko'pincha ularni dasturiy tarzda amalga oshiradi — bu parametrlar ustidan ko'proq nazorat beradi (callback rate, faollashtirish narxi, qadam o'lchami).

Iceberg order

Umumiy hajmning faqat bir qismi order kitobida ko'rinadigan order. Siz 1000 BTC sotib olmoqchisiz, lekin kitobda faqat 10 tasini ko'rsatasiz. Birinchi 10 tasi bajarilganda — keyingi 10 tasi paydo bo'ladi.

Nima uchun: haqiqiy niyatlaringizni bozordan yashirish uchun. Kitobdagi katta order hammaga "kimdir katta miqdorda sotib olmoqchi/sotmoqchi" degan signal beradi. Javobga HFT algoritmlari front-running qila boshlaydi va narx sizdan uzoqlashadi.

Eslatma: ko'plab kripto birjalarida iceberg orderlar yo qo'llab-quvvatlanmaydi, yoki bir xil hajmlar naqshi orqali oson aniqlanadi. Ilg'or algoritmlar ko'rinadigan qism hajmini tasodifiylashtiradi.

Time-in-force parametrlari: GTC, GTD, IOC, FOK

Bular alohida order turlari emas, balki time-in-force parametrlari — order qancha vaqt yashaydi:

Parametr To'liq nomi Xatti-harakati
GTC Good Till Cancelled Bekor qilinguncha yashaydi. Standart default
GTD Good Till Date Belgilangan sana/vaqtgacha yashaydi
IOC Immediate or Cancel Darhol bajariladi (to'liq yoki qisman), qolgani bekor qilinadi
FOK Fill or Kill Faqat to'liq va darhol bajariladi. Iloji bo'lmasa — butunlay bekor qilinadi

IOC va FOK farqi: farq muhim. IOC qisman bajarilishi mumkin — siz 100 BTC sotib olmoqchi edingiz, 3 tasini sotib oldingiz, qolgani bekor qilindi. FOK esa yo hammasi, yo hech narsa.

Post-only (Faqat Maker)

Order kitobiga maker sifatida kiritilishi kafolatlangan va hech qachon taker sifatida bajarilmaydigan order. Agar joylashtirish paytida narx darhol bajarilishga olib kelsa — birja uni rad etadi (yoki narxni tuzatadi, birjaga qarab).

Nima uchun: maker komissiyalari odatda taker komissiyalaridan past (Binanceda — VIP darajalar uchun 0,02% va 0,04%). Kuniga minglab order joylashtiradigan market meyker uchun komissiya farqi foyda va zarar orasidagi farqdir.


2. TWAP va VWAP: Institutsiyalar Order Kitobida Filni Qanday Yashiradi

Хеdж-fond 50 million dollarlik pozitsiya sotib olmoqchi bo'lganda, u bitta market order joylashtirmaydi. U bajarish algoritmlaridan foydalanadi — katta orderni ko'plab kichikroq qismlarga bo'lib, ularni vaqt davomida bajaradigan va bozorga ta'sirni minimallashtiradigan algoritmlar.

TWAP (Time-Weighted Average Price)

G'oya juda oddiy: umumiy hajmni teng qismlarga bo'lish va teng vaqt oralig'ida bajarish.

import asyncio
from datetime import datetime, timedelta

class TWAPExecutor:
    """
    TWAP executor: splits a large order into equal parts
    and executes them at equal time intervals.
    """
    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] slice {i+1}/{self.num_slices}: "
                      f"filled {order['filled']} @ {order['average']}")
            except Exception as e:
                print(f"[TWAP] slice {i+1} failed: {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] done: {self.executed_qty}/{self.total_qty} "
              f"avg price: {avg_price:.2f}")

VWAP (Volume-Weighted Average Price)

VWAP aqlliroq: u odatiy savdo hajmi profilini hisobga oladi. Agar kunlik hajmning 30% odatda 9:00 dan 10:00 gacha savdo qilinsa, VWAP order hajmining 30% ini o'sha oynada bajaradi. Maqsad — o'rtacha bajarilish narxini bozor VWAP-iga imkon qadar yaqinlashtirish.

class VWAPExecutor:
    """
    VWAP executor: distributes volume proportionally
    to the historical volume profile.
    """
    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] period {i+1}: weight={weight:.2%}, "
                  f"filled={order['filled']} @ {order['average']}")

            await asyncio.sleep(interval_seconds)

TWAP va VWAP farqi: TWAP soddaroq va bashorat qilish osonroq. VWAP yaxshiroq o'rtacha narx beradi, lekin ishonchli hajm profilini talab qiladi. Hajmlar wash-trade qilinishi mumkin bo'lgan kripto bozorida VWAP profilini ehtiyotkorlik bilan qurish kerak.


3. Chasing bilan Limit: Orderingiz Narxni Quvishni Bilganda

Chasing limit orderlar Chasing limit: order sozlanadigan tajovuzkorlik bilan harakatlanuvchi narxni quvadi

Endi ish qiziqarli bo'la boshlaydi. Standart limit order passiv obyekt: u order kitobida o'tirib kutadi. Narx harakatlansa — order bajarilmay qoladi. Algo-treyder uchun bu ko'pincha maqbul emas: kirish signali ishga tushdi, lekin bozor 0,1% harakatlangani sababli pozitsiya qurilmadi.

Chasing limit order — bu limit order atrofidagi dasturiy o'ram bo'lib, u:

  1. Joriy eng yaxshi narxda (yoki kichik offset bilan) limit order joylashtiradi
  2. Narxni WebSocket orqali kuzatib boradi
  3. Agar narx orderdan uzoqlashsa — uni bekor qilib, joriy narxga yaqinroq qayta joylashtiradi
  4. Order bajarilguncha yoki ruxsat etilgan chetlanishdan oshguncha takrorlaydi

Asosiy Parametrlar

  • chase_interval_ms — orderni qanchalik tez-tez tekshirish va qayta joylashtirish. 100ms — tajovuzkor, 1000ms — bo'shashgan.
  • max_chase_distance — order bekor qilinishidan oldin dastlabki narxdan maksimal chetlanish. Qochib ketayotgan bozorni quvishdan himoya.
  • aggression_level — limit orderni bozor narxiga qanchalik yaqin joylashtirish kerak. 0 — eng yaxshi bid/askda (passiv), 1 — spredni kesib o'tish (tajovuzkor, aslida taker).
  • chase_on_partial — order qisman bajarilganda quvishni davom ettirish kerakmi.

TypeScript Implementatsiyasi

interface ChasingOrderParams {
  symbol: string;
  side: "buy" | "sell";
  totalQty: number;
  /** 0 = passive (at best bid/ask), 1 = cross spread */
  aggression: number;
  /** max price deviation from initial price */
  maxChaseDistance: number;
  /** how often to re-evaluate, ms */
  chaseIntervalMs: number;
  /** stop chasing after this many ms */
  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 instance
    private params: ChasingOrderParams
  ) {}

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

    while (this.filledQty < this.params.totalQty) {
      // Timeout
      if (Date.now() - this.startTime > this.params.timeoutMs) {
        console.log("[CHASE] timeout reached, cancelling");
        await this.cancelCurrent();
        break;
      }

      // Get current order book
      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;

      // Calculate target price
      let targetPrice: number;
      if (this.params.side === "buy") {
        targetPrice = bestBid + spread * this.params.aggression;
      } else {
        targetPrice = bestAsk - spread * this.params.aggression;
      }

      // Remember the initial price
      if (this.initialPrice === null) {
        this.initialPrice = targetPrice;
      }

      // Check max chase distance
      const deviation = Math.abs(targetPrice - this.initialPrice);
      if (deviation > this.params.maxChaseDistance) {
        console.log(
          `[CHASE] max deviation exceeded: ${deviation.toFixed(4)} > ` +
          `${this.params.maxChaseDistance}`
        );
        await this.cancelCurrent();
        break;
      }

      // Check current order
      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;
        }

        // Update filledQty for partial fills
        if (order.filled > 0) {
          const newFilled = order.filled - (
            fills.reduce((s, f) => s + f.qty, 0) - this.filledQty
          );
          // Order is in place — do we need to reprice?
        }

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

        if (priceDiff > tickSize) {
          // Price moved — reprice
          console.log(
            `[CHASE] repricing: ${currentPrice} -> ` +
            `${targetPrice.toFixed(4)}`
          );
          await this.cancelCurrent();
        } else {
          // Order is at the right price — wait
          await this.sleep(this.params.chaseIntervalMs);
          continue;
        }
      }

      // Place new order
      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] placed ${this.params.side} ${remainingQty} ` +
        `@ ${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 { /* order already filled or cancelled */ }
      this.currentOrderId = null;
    }
  }

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

Chasing Zarar Keltiradigan Holatlar

Chasing kuchli vosita, lekin uni zarar generatoriga aylantirish oson:

  1. Cancel/replace spami. Har bir bekor qilish va qayta joylashtirish API uchun yuk hisoblanadi. Birjalar so'rovlarni cheklaydi (rate limit), va tajovuzkor chasing API kalitingiz bloklanishiga olib kelishi mumkin.
  2. Noqulay tanlov (adverse selection). Agar narx sizdan qochayotgan bo'lsa — bozor siz bilmagan narsani bilishi mumkin. Bunday holatda narxni quvish tepada sotib olishni anglatadi.
  3. Maker'dan Taker'ga o'tish. Yuqori tajovuzkorlik bilan siz aslida taker komissiyalarini to'laysiz, lekin kechikish bilan (bekor qilish + yangi order). Ba'zan shunchaki market order joylashtirish osonroq.

4. Vaqtga Asoslangan Orderlar: Millisekund Aniqligi

Order "X narxda" emas, balki "T vaqtda" bajarilishi kerak bo'lgan holatlar mavjud. G'alati eshitiladimi? Aslida bu butun bir strategiyalar sinfi.

Foydalanish holatlari

Funding stavkasi arbitraji. Perpetual fyucherslarda funding har 8 soatda to'lanadi (00:00, 08:00, 16:00 UTC Binanceda). Agar funding stavkasi = +0,1% bo'lsa, hisob-kitob paytida short pozitsiyada bo'lishingiz kerak. Strategiya: hisob-kitobdan bir necha soniya oldin short ochish, fundingni yig'ish, pozitsiyani yopish. Vaqt aniqligi hal qiluvchi — bir soniya kechikish o'tkazib yuborilgan funding degani.

Sessiya ochilishi/yopilishi. An'anaviy bozorlarda va ba'zi kripto derivativlarda qat'iy sessiyalar mavjud. Ochilish auksioni (NYSE, CME) — bu likvidlik cho'qqisiga chiqqan payt. Auksiondan 100ms oldin order joylashtirish afzallik hisoblanadi.

Yangiliklarga asoslangan bajarish. Inflyatsiya ma'lumotlari rejalashtirilgan vaqtda e'lon qilinadi. Algoritm sonni yangiliklar oqimidan tahlil qiladi va 50ms ichida order joylashtiradi. Bu yerda vaqtga asoslangan bajarish voqealarga asoslangan mantiq bilan birlashtiriladi.

Implementatsiya

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

  /**
   * Schedule execution at a precise time.
   * Uses a busy-wait loop for maximum precision.
   */
  async executeAt(targetTime: Date): Promise<any> {
    const targetMs = targetTime.getTime();

    // Phase 1: coarse wait (sleep)
    const coarseWait = targetMs - Date.now() - 500; // wake up 500ms early
    if (coarseWait > 0) {
      console.log(
        `[TIME-ORDER] sleeping for ${(coarseWait / 1000).toFixed(1)}s`
      );
      await new Promise((r) => setTimeout(r, coarseWait));
    }

    // Phase 2: precise wait (busy-wait)
    while (Date.now() < targetMs) {
      // spin — burns CPU, but achieves ~1ms precision
    }

    // Phase 3: execution
    const sendTime = Date.now();
    const order = await this.exchange.createOrder(
      this.symbol,
      this.orderType,
      this.side,
      this.qty,
      this.limitPrice
    );

    console.log(
      `[TIME-ORDER] executed at ${new Date(sendTime).toISOString()}, ` +
      `target was ${targetTime.toISOString()}, ` +
      `delta: ${sendTime - targetMs}ms`
    );

    return order;
  }
}

// Example: place an order exactly at 00:00:00 UTC (funding settlement)
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);

Muhim eslatma: vaqtga asoslangan orderning aniqligi sizning kodingiz bilan emas, balki birjaga tarmoq kechikishi bilan cheklanadi. Agar API'ga ping 50ms bo'lsa, mukammal busy-wait ham 50ms delta beradi. Jiddiy HFT uchun co-location ishlatiladi — server jismonan birjaning matching engine yonida joylashadi.


5. Virtual/Sintetik Orderlar: Tizimingizdagi Ko'rinmaslar

Grid botlar uchun virtual orderlar Virtual orderlar: orderlar trigger ishga tushguncha faqat bot xotirasida mavjud

Bu ehtimol algo-treyder arsenalidagi eng kam baholangan vosita. Virtual order (sintetik order deb ham ataladi) — bu faqat sizning tizimingizda mavjud bo'lgan order. U trigger sharti bajarilguncha (odatda — narx muayyan darajaga yetguncha) birjaga yuborilmaydi.

Bu Qanday Ishlaydi

  1. Sizning algoritmingiz qaror qiladi: "BTC ni 40 000 dollarga sotib olmoqchiman"
  2. Birjaga limit order yuborish o'rniga, xotirada virtual order yaratiladi
  3. WebSocket narx oqimiga obuna bo'ladi
  4. Bid/ask 40 000 dollarga yetganda — birjaga haqiqiy market yoki limit order yuboriladi

Nima Uchun Virtual Orderlar Muhim

Ma'lumot sizib chiqmaydi. Sizning orderingiz order kitobida ko'rinmaydi. Hech kim — boshqa treyderlar ham, HFT algoritmlari ham, hatto birjaning o'zi ham — bajarilish paytigacha sizning niyatlaringiz haqida bilmaydi. Bu kuchlar muvozanatini tubdan o'zgartiradi.

Front-runningdan himoya. Kripto birjalarda, ayniqsa kam shaffof bo'lganlarida, katta limit orderlar haqidagi ma'lumot front-running uchun ishlatilishi mumkinligi haqida asosli shubhalar mavjud (bu haqda tadqiqotlar ham bor). Virtual orderlar bu xavfni bartaraf etadi.

Grid botlar. Klassik grid bot turli narx darajalarida 50-200 ta order to'ridan iborat setka joylashtiradi. Agar siz ularning barchasini birjaga yuborsangiz — bu kitobda 200 ta order bo'ladi, ular: (a) hamma uchun ko'rinadi, (b) birjadagi order limitini ishlatib qo'yadi (odatda hisob uchun 200-300 ta ochiq order), (c) narx keskin harakatlansa, ularning barchasi bajarilib, sizda ulkan pozitsiya paydo bo'ladi. Virtual orderlar barcha uchta muammoni hal qiladi.

Tushayotgan pichoqlarni ushlash. Strategiya: joriy narxdan -5%, -10%, -15% pastda virtual sotib olish orderlarini joylashtirish. Bozor tushsa — orderlar asta-sekin ishga tushadi. Tushmasa — hech narsani xavf ostiga qo'ymaysiz va birja order slotlarini ishlatmaysiz.

TypeScript Implementatsiyasi

interface VirtualOrder {
  id: string;
  symbol: string;
  side: "buy" | "sell";
  triggerPrice: number;
  qty: number;
  /** Order type sent to the exchange upon triggering */
  executionType: "market" | "limit";
  /** For limit: offset from trigger price */
  limitOffset?: number;
  status: "pending" | "triggered" | "filled" | "failed";
}

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

  constructor(private exchange: any) {}

  /**
   * Create a virtual order. Nothing is sent to the exchange.
   */
  addOrder(params: Omit<VirtualOrder, "id" | "status">): string {
    const id = `virt_${++this.orderCounter}`;
    this.orders.set(id, { ...params, id, status: "pending" });
    console.log(
      `[VIRTUAL] created ${params.side} ${params.qty} ` +
      `${params.symbol} @ trigger ${params.triggerPrice}`
    );
    return id;
  }

  /**
   * Called on every price tick (from WebSocket).
   */
  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} triggered! 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} filled: ${realOrder.filled} ` +
          `@ ${realOrder.average ?? realOrder.price}`
        );
      } catch (err) {
        order.status = "failed";
        console.error(`[VIRTUAL] ${id} execution failed:`, err);
      }
    }
  }

  /**
   * Get all active virtual orders.
   */
  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;
  }
}

// --- Example: Grid bot with virtual orders ---

async function gridBot(exchange: any) {
  const manager = new VirtualOrderManager(exchange);
  const currentPrice = 42000;
  const gridStep = 200;      // grid step
  const gridLevels = 20;     // levels in each direction
  const qtyPerLevel = 0.01;  // BTC per level

  // Create virtual grid
  for (let i = 1; i <= gridLevels; i++) {
    // Buy orders below current price
    manager.addOrder({
      symbol: "BTC/USDT",
      side: "buy",
      triggerPrice: currentPrice - gridStep * i,
      qty: qtyPerLevel,
      executionType: "limit",
      limitOffset: 1,  // limit price = trigger + 1 USDT
    });

    // Sell orders above current price
    manager.addOrder({
      symbol: "BTC/USDT",
      side: "sell",
      triggerPrice: currentPrice + gridStep * i,
      qty: qtyPerLevel,
      executionType: "limit",
      limitOffset: 1,
    });
  }

  console.log(
    `[GRID] created ${gridLevels * 2} virtual orders, ` +
    `0 on exchange`
  );

  // WebSocket subscription (pseudocode for ccxt.pro)
  while (true) {
    const ticker = await exchange.watchTicker("BTC/USDT");
    await manager.onPriceUpdate(
      "BTC/USDT", ticker.bid, ticker.ask
    );
  }
}

Virtual Orderlarning Zaif Tomonlari

  1. Kechikish bo'shlig'i. Siz narxni ko'rgan payt bilan haqiqiy order birjaga yetib borgan payt orasida vaqt o'tadi. O'zgaruvchan bozorda narx o'sha 20-100ms ichida uchib ketishi mumkin. Yechim: biroz tajovuzkor limit order yuborish (bufer bilan).

  2. O'tkazib yuborilgan bajarilishlar. Agar narx sizning darajangizni bitta tickda "teshib o'tsa" (flash crash) va orqaga qaytsa — siz vaqtida javob bera olmasligingiz mumkin. Kitobda o'tirgan oddiy limit order bajarilgan bo'lardi; virtual order esa yo'q.

  3. Holatni boshqarish. Virtual orderlar xotirada yashaydi. Jarayon qulasa — orderlar yo'qoladi. Yechim: qayta ishga tushirilganda tiklanadigan doimiy saqlash (Redis, SQLite, fayl).


6. Shartli/Aqlli Orderlar: Order Kombinatorikasi

Bitta order yetarli bo'lmaganda, treyderlar ularni shartli konstruksiyalarga birlashtiradi. Ba'zilari birjalarda tabiiy qo'llab-quvvatlanadi, boshqalari dasturiy tarzda amalga oshiriladi.

OCO (One Cancels Other)

Ikki order bog'langan: agar biri bajarilsa — ikkinchisi avtomatik ravishda bekor qilinadi. Klassik misol: siz long pozitsiyadasiz va ham take-profit, ham stop-loss o'rnatmoqchisiz. Qaysi biri birinchi bo'lib ishga tushsa — ikkinchisi bekor qilinishi kerak.

class OCOHandler:
    """
    OCO: when one order fills, the other is cancelled.
    """
    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):
        """Checks statuses and cancels the paired order."""
        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] take-profit filled, cancelling stop-loss")
                    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] stop-loss filled, cancelling take-profit")
                    await self.exchange.cancel_order(
                        self.order_a_id, self.symbol
                    )
                    break

            await asyncio.sleep(0.5)

Bracket order

Uch komponentli konstruksiya: birlamchi kirish orderi + chiqish uchun OCO (take-profit + stop-loss). Aslida, bitta chaqiruvda to'liq savdo hayot sikli:

  1. Kirish: limit sotib olish orderi
  2. Take-profit: limit sotish orderi (yuqorida)
  3. Stop-loss: stop-market sotish orderi (pastda)

Kirish bajarilganda, TP va SL avtomatik ravishda joylashtiriladi. Ulardan biri bajarilganda — ikkinchisi bekor qilinadi.

If-Then Mantiq

Eng moslashuvchan variant — ixtiyoriy shartlar bilan order zanjirlari:


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},
            },
        ]
    }
]

Bunday konstruksiyalar hech qanday birja tomonidan tabiiy ravishda qo'llab-quvvatlanmaydi — faqat dasturiy amalga oshirish orqali. Bu algotrading tizimlari muqarrar ravishda o'zining order boshqaruv qatlamini rivojlantirishining sabablaridan biridir.


7. Market Meykerlar Ixtisoslashtirilgan Order Turlaridan Qanday Foydalanadi

Market making — o'z olamiga ega bo'lgan soha, va orderlar to'plami ham unga mos keladi. Market meykerning vazifasi — spreddan foyda ko'rib, doimiy ravishda bid va ask kotirovkalarini berish, shu bilan birga adverse selection'ni (xabardor treyder siz bilan qarama-qarshi savdo qilgan holatni) minimallashtirish.

Post-only — Majburiy Talab

Market meyker uchun post-only tanlov emas — bu talab. Agar orderingiz tasodifan taker sifatida bajarilsa — maker rebatini olish o'rniga siz taker komissiyasini to'laysiz. Kuniga minglab orderlar bo'yicha bu falokatli.

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}  # CRITICAL for market makers
    )
    ask = await exchange.create_order(
        symbol, "limit", "sell", qty, ask_price,
        {"postOnly": True}
    )
    return bid, ask

Hidden orderlar

Ba'zi birjalarda (Kraken, Bitfinex) yashirin orderlar mavjud — ular order kitobida ko'rinmaydi, lekin birjada bor va matchingda ishtirok etadi. Kelishuv: siz maker sifatida ham taker komissiyalarini to'laysiz, lekin anonimlikka ega bo'lasiz.

Market meyker uchun bu — inventarni boshqarish vositasi: agar katta pozitsiya to'planib qolgan bo'lsa, uni bozorga niyatingizni oshkor qilmasdan yopish uchun yashirin order joylashtirishingiz mumkin.

Pegged orderlar

Eng yaxshi bid/askka bog'langan order. Masalan, Coinbase Advanced Trade'da siz eng yaxshi bidni avtomatik kuzatib boradigan va har doim navbat boshida turadigan order joylashtira olasiz. Bu birja darajasidagi tabiiy chasing order — ammo bu hamma joyda mavjud emas.

Ommaviy order boshqaruvi

Professional market meykerlar bitta HTTP so'rovida bir vaqtning o'zida o'nlab orderlarni bekor qilish va joylashtirish uchun batch API'lardan foydalanadi. Binanceda bu batchOrders, Bybitda esa — place-batch-order. Bu kechikish va rate limit bosimini kamaytiradi.


8. Order Turlari Taqqoslash Jadvali

Order Turi Bajarilish Kafolati Narx Kafolati Kitobda Ko'rinadi Birjalarda Tabiiy Amalga Oshirish Murakkabligi
Market Ha Yo'q Yo'q (darhol) Ha Yo'q
Limit Yo'q Ha Ha Ha Yo'q
Stop-market Ha (trigerdan keyin) Yo'q Yo'q Ha Yo'q
Stop-limit Yo'q Ha Yo'q (trigergacha) Ha Yo'q
Trailing stop Ha (trigerdan keyin) Yo'q Yo'q Qisman Past
Iceberg Yo'q Ha Qisman Qisman O'rta
Post-only Yo'q Ha Ha Ha Yo'q
TWAP Yo'q (bo'laklarga bog'liq) Yo'q Qisman Yo'q O'rta
VWAP Yo'q Yo'q Qisman Yo'q Yuqori
Chasing limit Limitdan yuqori Qisman Ha (joriy order) Yo'q O'rta
Vaqtga asoslangan Turga bog'liq Turga bog'liq Yo'q (T vaqtgacha) Yo'q Past
Virtual/Sintetik Limitdan past Turga bog'liq Yo'q Yo'q O'rta
OCO Ha (ikkitadan biri) Qisman Ha (ikkalasi) Qisman O'rta
Bracket Ha Qisman Ha Kam uchraydi Yuqori
Hidden Yo'q Ha Yo'q Kam uchraydi Yo'q
Pegged Yo'q Dinamik Ha Juda kam uchraydi Yuqori (dasturiy bo'lsa)

Xulosa: Strategiyaning Qurilish Bloki Sifatida Order

Order turlari shunchaki "interfeysdagi tugmalar" emas. Ular har qanday savdo tizimining bajarish qatlami qurilгan fundamental primitivlardir. "Strategiya backtestda foydali" va "strategiya ishlab chiqarishda foydali" o'rtasidagi farq ko'pincha aynan shu yerda — orderlarni birjaga qanday yuborishingizda yotadi.

Bir necha amaliy xulosalar:

  1. Standart orderlardan boshlang, nuanslarni tushunganingizga ishonch hosil qiling (stop-limit va stop-market, IOC va FOK). Ko'pchilik xatolar aynan shu yerda sodir bo'ladi.
  2. Virtual orderlar grid botlar uchun majburiy. Agar siz 50 dan ortiq order joylashtirsangiz — ularning barchasini birjaga yubormang.
  3. Chasing bajarilish darajasi narxdan muhimroq bo'lganda kerak. Lekin har doim max_chase_distance ni belgilang — aks holda juda uzoqqa siljib ketishingiz mumkin.
  4. Vaqtga asoslangan bajarish — nisha, ammo funding arbi va voqealarga asoslangan strategiyalar uchun kuchli vosita.
  5. Maxsus order boshqaruv qatlami har qanday jiddiy algotrading tizimi uchun muqarrar. Birjaning tabiiy order turlari yetarli emas.

Agar siz savdo tizimi qurayotgan bo'lsangiz va chuqurroq borishni istasangiz — order kitobidagi navbat pozitsiyasi, CCXT'dagi WebSocket usullari va funding stavkasi arbitraji haqidagi maqolalarimizga qarang.


Havolalar va Manbalar

blog.disclaimer

Authors

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

Bozordan bir qadam oldinda bo'ling

Sun'iy intellekt savdo tahlillari, bozor tahlili va platforma yangiliklari uchun bizning xabarnomaga obuna bo'ling.

Biz sizning maxfiyligingizni hurmat qilamiz. Istalgan vaqtda obunadan chiqishingiz mumkin.