← Макалаларга кайтуу
March 23, 2026
5 мүн окуу

Алгоритмдик Трейдингдеги Ордер Түрлөрү: Chasing менен Лимиттен Виртуалдык Ордерлерге чейин

Алгоритмдик Трейдингдеги Ордер Түрлөрү: Chasing менен Лимиттен Виртуалдык Ордерлерге чейин
#orders
#algotrading
#limit
#chasing
#virtual-orders
#grid-bot
#market-making
📖
Part 2 of 6 · Collection
Order Book & Market Microstructure

Жаңы баштаган адам биржа терминалын ачканда, ал эки баскычты көрөт: "Сатып алуу" жана "Сатуу". Алго-трейдер өз кодун ачканда, ал жыйырма жети ордер түрүн, үч абстракция деңгээлин жана ноутбукту жаап, базарда бадыраң сатуу дегендин артынан жүргүзгүсү келтирген бир топ четки учурларды көрөт. Бирок, өкүнүчтүү болсо да, бадыраңдар силерге 3:59 UTC-де funding rate арбитражын жүргүзүүгө мүмкүнчүлүк беришпейт — андыктан түз эле маселеге өтөлү.

Бул макалада биз негизги биржа ордерлеринен баштап, жалгыз гана сиздин системаңызда жашаган жана эч качан ордер китебинде пайда болбогон синтетикалык виртуалдык түзүлүштөргө чейинки бүткүл жолду басып өтөбүз. TypeScript, Python, бир аз оору жана бир аз агартуу күтүлүүдө.


1. Стандарттуу Биржа Ордерлери: Өткөрүп Жиберип Болбой турган Негиз

Стандарттуу ордерлер Стандарттуу ордер түрлөрүнүн классификациясы: маркеттен айсбергге чейин

Татаал нерсе куруунун алдында, негизги куруу блокторун туура түшүнгөнүбүзгө көз жеткиребиз керек. Канча адам stop-limit менен stop-market-ти чаташтырып, кийин эмне үчүн өз стобу "иштебей калганына" таң калаары таң калыштуу (спойлер: ал иштеп кеткен, бирок лимиттик ордер slippage айынан аткарылган эмес).

Market ордер

Эң жөнөкөй жана ошол эле учурда эң коркунучтуу түрү. Сиз биржага: "азыр, кандай гана жеткиликтүү баада болбосун сатып ал/сат" дейсиз. Биржа ордер китебинен эң жакшы баадан баштап ликвиддүүлүктү алат. Эң жакшы деңгээлдеги көлөм жетишсиз болсо — ал андан ары жылат.

Качан колдонуу керек: позициядан шашылыш чыгуу, ылдамдык баадан маанилүүрөөк болгон сигналды аткаруу.

Тузактар: сейрек нарыкта 100 BTC үчүн market ордер бааны бир нече пайызга жылдырышы мүмкүн. Таасирди эске албай market ордерлерди моделдештирген бэктесттер — таза кыял.

Limit ордер

Сиз так бааны көрсөтөсүз. Ордер ордер китебине түшөт жана бирөө сиздин бааңызга макул болгонго чейин күтөт. Эгер лимиттик сатып алуу ордеринин баасы учурдагы нарыктан жогору болсо — ал дароо аткарылат (market ордер сыяктуу, бирок кепилденген максималдуу баа менен).

Негизги жагы: лимиттик ордер аткарылууну кепилдебейт. Баа сиздин деңгээлиңизге жетип, тескери бурулушу мүмкүн, сизди кезекте калтырып (кезектеги позиция жөнүндөгү макалабызда толугураак).

Stop-market жана Stop-limit

Так ушул жерден чаташуу башталат. Эки түрү тең иштөө баасына (stop price) жеткенде активдешкен "уктап жаткан" ордерлер. Бирок:

  • Stop-market: иштеп кеткенде market ордерге айланат. Аткарылууну кепилдейт, бирок бааны эмес.
  • Stop-limit: иштеп кеткенде лимиттик ордерге айланат. Бааны кепилдейт (көрсөтүлгөндөн жаманыраак эмес), бирок аткарылууну эмес.

Туруксуз крипто нарыгында stop-limit "өтүп кетиши" мүмкүн — баа стопту бузуп өттү, лимиттик ордер коюлду, бирок нарык мурунтан эле учуп өттү. Сизде аткарылбаган лимиттик ордер жана өсүп бара жаткан чыгым калат. Так ушул себептен stop-loss үчүн stop-market көбүрөөк колдонулат.

Trailing stop

Бааны белгиленген аралыкта "кубалаган" стоп. Баа көтөрүлөт — стоп да жогору жылат. Баа түшөт — стоп ордунда калат. Тренддик стратегияларда пайданы коргоо үчүн пайдалуу.

Биржа колдоосу: бардык биржалар да табигый trailing stop-ду колдобойт. Алго-трейдерлер аны көбүнчө программалык түрдө ишке ашырышат — бул параметрлерге (callback rate, активдештирүү баасы, кадам өлчөмү) көбүрөөк көзөмөл берет.

Iceberg ордер

Жалпы көлөмдүн бир бөлүгү гана ордер китебинде көрүнгөн ордер. Сиз 1000 BTC сатып алгыңыз келет, бирок китепте 10ун гана көрсөтөсүз. Биринчи 10у аткарылганда — кийинки 10у пайда болот.

Эмне үчүн: нарыктан чыныгы ниеттериңизди жашыруу үчүн. Китептеги чоң ордер баарына "бирөө чоң көлөмдө сатып алгысы/саткысы келет" деген сигнал берет. Жооп катары HFT алгоритмдери front-running жасай башташат, ал эми баа сизден алыстайт.

Эскертүү: көптөгөн крипто биржаларда айсберг ордерлер же колдоого алынбайт, же бирдей көлөмдөрдүн үлгүсү аркылуу оңой аныкталат. Өнүккөн алгоритмдер көрүнгөн бөлүктүн өлчөмүн кокустандырышат.

Time-in-force параметрлери: GTC, GTD, IOC, FOK

Булар өзүнчө ордер түрлөрү эмес, тескерисинче time-in-force параметрлери — ордер канча убакыт жашайт:

Параметр Толук аталышы Жүрүм-туруму
GTC Good Till Cancelled Токтотулгуча жашайт. Стандарттуу default
GTD Good Till Date Көрсөтүлгөн күн/убакытка чейин жашайт
IOC Immediate or Cancel Дароо аткарылат (толук же жарым-жартылай), калганы жокко чыгарылат
FOK Fill or Kill Гана толук жана дароо аткарылат. Мүмкүн болбосо — толугу менен жокко чыгарылат

IOC жана FOK айырмасы: айырма маанилүү. IOC жарым-жартылай аткарылышы мүмкүн — сиз 100 BTC сатып алгыңыз келди, 3үн сатып алдыңыз, калганы жокко чыгарылды. FOK болсо же толугу менен, же такыр эле жок.

Post-only (жалгыз Maker)

Ордер китебине maker катары кирүүсү кепилденген жана эч качан taker катары аткарылбаган ордер. Эгер коюу учурунда баа дароо аткарылууга алып келсе — биржа аны четке кагат (же биржага жараша бааны тууралайт).

Эмне үчүн: maker комиссиялары адатта taker комиссияларынан төмөн (Binance-де — VIP деңгээлдер үчүн 0,02% жана 0,04%). Күнүнө миңдеген ордер койгон маркет-мейкер үчүн комиссиянын айырмасы — пайда менен чыгымдын ортосундагы айырма.


2. TWAP жана VWAP: Институттар Ордер Китебинде Пилди Кантип Жашырышат

Хедж-фонд 50 миллион долларлык позиция сатып алгысы келгенде, ал бир гана market ордер коёт эмес. Ал аткаруу алгоритмдерин колдонот — чоң ордерди көптөгөн кичине бөлүктөргө бөлүп, аларды убакыт бою аткарган, нарыкка таасирди азайткан алгоритмдер.

TWAP (Time-Weighted Average Price)

Идея абдан жөнөкөй: жалпы көлөмдү тең бөлүктөргө бөлүп, тең убакыт аралыктарында аткаруу.

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 акылдуураак: ал típik соода көлөмүнүн профилин эске алат. Эгер күндүзгү көлөмдүн 30%ы адатта саат 9:00дан 10:00го чейин соодаланса, VWAP ордердин 30%ын так ошол терезеде аткарат. Максат — орточо аткаруу баасын нарыктык VWAP-ка мүмкүн болушунча жакындатуу.

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 менен VWAP-тын айырмасы: TWAP жөнөкөйрөөк жана божомолдонгонураак. VWAP жакшыраак орточо баа берет, бирок ишенимдүү көлөм профилин талап кылат. Көлөмдөр wash-trade жасалышы мүмкүн болгон крипто нарыгында VWAP профилин этияттык менен куруу керек.


3. Chasing менен Limit: Ордериңиз Бааны Кубалоону Билгенде

Chasing лимиттик ордерлер Chasing limit: ордер тууралоого боло турган агрессивдүүлүк менен кыймылдаган бааны кубалайт

Эми иштер чындап эле кызыктуу боло баштайт. Стандарттуу лимиттик ордер — пассивдүү нерсе: ал ордер китебинде отуруп күтөт. Баа кыймылдаса — ордер аткарылбай калат. Алго-трейдер үчүн бул көбүнчө кабыл алынгыс: кирүү сигналы иштеп кетти, бирок нарык 0,1%га жылгандыктан позиция курулган жок.

Chasing limit order — бул лимиттик ордердин айланасындагы программалык оролуш, ал:

  1. Учурдагы эң жакшы баада (же кичине offset менен) лимиттик ордер коёт
  2. Бааны WebSocket аркылуу байкайт
  3. Эгер баа ордерден алыстаса — аны токтотуп, учурдагы баага жакыныраак кайра коёт
  4. Ордер аткарылганча же уруксат берилген четтөөдөн ашканга чейин кайталайт

Негизги Параметрлер

  • chase_interval_ms — ордерди канчалык көп текшерип, кайра коюу керек. 100мс — агрессивдүү, 1000мс — бошоңдоо.
  • max_chase_distance — ордер токтотулганга чейинки баштапкы баадан максималдуу четтөө. Качып бара жаткан нарыкты кубалоодон коргоо.
  • aggression_level — лимиттик ордерди нарыктык баага канчалык жакын коюу керек. 0 — эң жакшы bid/ask-та (пассивдүү), 1 — спрeдди кесип өтүү (агрессивдүү, иш жүзүндө taker).
  • chase_on_partial — ордер жарым-жартылай аткарылса, кубалоону улантуу керекпи.

TypeScript Ишке Ашыруусу

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 Зыян Келтире турган Учурлар

Chasing — күчтүү курал, бирок аны чыгым генераторуна айландыруу оңой:

  1. Cancel/replace спамы. Ар бир жокко чыгаруу жана кайра коюу API үчүн жүктөм болуп саналат. Биржалар сурамдарды чектейт (rate limit), ал эми агрессивдүү chasing API ачкычыңыздын бөгөттөлүшүнө алып келиши мүмкүн.
  2. Терс тандоо (adverse selection). Эгер баа сизден качып жатса — нарык сиз билбеген нерсени билиши мүмкүн. Мындай кырдаалда бааны кубалоо чокуда сатып алууну билдирет.
  3. Maker-ден Taker-ге өтүү. Жогорку агрессивдүүлүк менен сиз иш жүзүндө taker комиссияларын төлөйсүз, бирок кечигүү менен (жокко чыгаруу + жаңы ордер). Кээде жөн эле market ордер коюу оңоюраак.

4. Убакытка Негизделген Ордерлер: Миллисекунддук Тактык

Ордерди "X баада" эмес, "T убактысында" аткаруу зарыл болгон учурлар бар. Кызык угулаby? Чынында бул толук стратегиялар классы.

Колдонуу учурлары

Funding rate арбитражы. Түбөлүк фьючерстерде funding ар 8 саат сайын төлөнөт (Binance-де 00:00, 08:00, 16:00 UTC). Эгер funding ставкасы = +0,1% болсо, эсептешүү учурунда short позицияда болуу керек. Стратегия: эсептешүүдөн бир нече секунд мурун short ачуу, funding жыйноо, позицияны жабуу. Убакыттын тактыгы чечүүчү — бир секунд кечигүү өткөрүп жиберилген funding дегенди билдирет.

Сессиялардын ачылышы/жабылышы. Салттуу нарыктарда жана айрым крипто туундуларда туруктуу сессиялар бар. Ачылуу аукциону (NYSE, CME) — ликвиддүүлүктүн чокусуна жеткен учур. Аукциондон 100мс мурун ордер коюу — артыкчылык.

Жаңылыктарга негизделген аткаруу. Инфляция маалыматтары пландаштырылган убакытта жарыяланат. Алгоритм санды жаңылыктар лентасынан талдап, 50мс ичинде ордер коёт. Бул жерде убакытка негизделген аткаруу окуяга негизделген логика менен айкалышат.

Ишке ашыруу

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

Маанилүү эскертүү: убакытка негизделген ордердин тактыгы сиздин кодуңуз менен эмес, биржага чейинки тармак кечигүүсү (latency) менен чектелет. Эгер API-ге пинг убагыңыз 50мс болсо, кемчиликсиз busy-wait деле 50мс дельта берет. Олуттуу HFT үчүн co-location колдонулат — сервер физикалык жактан биржанын matching engine-инин жанында жайгашат.


5. Виртуалдык/Синтетикалык Ордерлер: Системаңыздагы Көрүнбөстөр

Grid боттор үчүн виртуалдык ордерлер Виртуалдык ордерлер: триггер иштегенге чейин алар жалгыз гана боттун эсинде жашайт

Бул, балким, алго-трейдердин куралынын арасындагы эң баалуулугу азыраак баалаган каражат. Виртуалдык ордер (синтетикалык ордер деп да аталат) — жалгыз гана сиздин системаңызда жашаган ордер. Ал триггер шарты аткарылганга чейин (адатта — баа белгилүү бир деңгээлге жеткенге чейин) биржага жиберилбейт.

Бул Кантип Иштейт

  1. Сиздин алгоритмиңиз чечим кабыл алат: "BTC-ды 40 000 долларга сатып алгым келет"
  2. Биржага лимиттик ордер жиберүүнүн ордуна, ал эсте виртуалдык ордер түзөт
  3. WebSocket баа агымына жазылат
  4. Bid/ask 40 000 долларга жеткенде — биржага чыныгы market же лимиттик ордер жиберилет

Виртуалдык Ордерлер Эмне Үчүн Маанилүү

Маалымат сызылып чыкпайт. Сиздин ордериңиз ордер китебинде көрүнбөйт. Эч ким — башка трейдерлер да, HFT алгоритмдери да, атүгүл биржанын өзү да — аткарылуу учуруна чейин сиздин ниеттериңиз жөнүндө билбейт. Бул күчтөрдүн тең салмактуулугун түп-тамырынан өзгөртөт.

Front-running-дан коргоо. Крипто биржаларда, өзгөчө азыраак ачык болгондорунда, чоң лимиттик ордерлер жөнүндөгү маалыматтын front-running үчүн колдонулушу мүмкүн деген негиздүү шектөө бар (бул жөнүндө изилдөөлөр да бар). Виртуалдык ордерлер бул тобокелди жоюшат.

Grid боттор. Классикалык grid бот ар кандай баа деңгээлдеринде 50-200 ордерден турган торду жайгаштырат. Эгер сиз аларды баарын биржага жиберсеңиз — бул китепте: (а) баарына көрүнгөн, (б) биржадагы ордер лимитин колдонгон (адатта аккаунт үчүн 200-300 ачык ордер), (в) баа катуу кыймылдаса, алардын баары аткарылып, сизде эбегейсиз позиция калат дегенди билдирген 200 ордер. Виртуалдык ордерлер бул үч көйгөйдү тең чечет.

Кулап жаткан бычактарды кармоо. Стратегия: учурдагы баадан -5%, -10%, -15% төмөн виртуалдык сатып алуу ордерлерин коюу. Нарык кулап баштаса — ордерлер бирден-бирден иштеп кетет. Кулабаса — сиз эч нерсеге тобокелдик кылбайсыз жана биржанын ордер слотторун колдонбойсуз.

TypeScript Ишке Ашыруусу

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

Виртуалдык Ордерлердин Начар Жактары

  1. Кечигүү боштугу. Сиз бааны көргөн учур менен чыныгы ордер биржага жеткен учур ортосунда убакыт өтөт. Туруксуз нарыкта баа так ошол 20-100мс ичинде учуп кетиши мүмкүн. Чечим: бир аз агрессивдүү лимиттик ордер жиберүү (буфер менен).

  2. Өткөрүп жиберилген аткаруулар. Эгер баа сиздин деңгээлиңизди бир тикте (flash crash) "тешип өтүп" кайра кайтып келсе — сиз убагында аракет кыла албашыңыз мүмкүн. Китепте отурган кадимки лимиттик ордер аткарылмак; виртуалдык — жок.

  3. Абалды башкаруу. Виртуалдык ордерлер эсте жашайт. Процесс кулап калса — ордерлер жоголот. Чечим: кайра иштеткенде калыбына келтирүү менен туруктуу сактоо (Redis, SQLite, файл).


6. Шарттуу/Акылдуу Ордерлер: Ордер Комбинаторикасы

Бир ордер жетишсиз болгондо, трейдерлер аларды шарттуу түзүлүштөргө бириктиришет. Айрымдары биржаларда табигый түрдө колдоого алынат, башкалары программалык түрдө ишке ашырылат.

OCO (One Cancels Other)

Эки ордер байланышкан: эгер бирөө аткарылса — экинчиси автоматтык түрдө жокко чыгарылат. Классикалык мисал: сиз long позицияда турасыз жана take-profit менен stop-loss экөөнү тең орнотууну каалайсыз. Кайсынысы биринчи иштеп кетсе — экинчиси жокко чыгарылышы керек.

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

Үч компоненттен турган түзүлүш: кирүү үчүн негизги ордер + чыгуу үчүн OCO (take-profit + stop-loss). Мааниси боюнча, бир гана чакырууда мамиленин толук өмүрлүк цикли:

  1. Кирүү: сатып алууга лимиттик ордер
  2. Take-profit: сатууга лимиттик ордер (жогоруда)
  3. Stop-loss: сатууга stop-market ордер (төмөндө)

Кирүү аткарылганда, TP менен SL автоматтык түрдө коюлат. Алардын бирөө аткарылганда — экинчиси жокко чыгарылат.

If-Then Логикасы

Эң ийкемдүү вариант — каалаган шарттар менен ордер чынжырлары:


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

Мындай түзүлүштөр эч бир биржада табигый түрдө колдоого алынбайт — жалгыз гана программалык ишке ашыруу аркылуу. Бул алготрейдинг системаларынын сөзсүз түрдө өз ордерлерди башкаруу катмарын өнүктүрүшүнүн себептеринин бири.


7. Маркет-Мейкерлер Адистештирилген Ордер Түрлөрүн Кантип Колдонушат

Market making — өзүнчө ааламы бар тармак, жана ордер каражаттарынын жыйындысы да ошого туура келет. Маркет-мейкердин ишинин мазмуну — спредден пайда алуу менен bid жана ask-ты үзгүлтүксүз белгилөө, ошону менен катар adverse selection-ду (маалыматтуу трейдер сизге каршы соода жасаган абалды) азайтуу.

Post-only — Милдеттүү Талап

Маркет-мейкер үчүн post-only — тандоо эмес, талап. Эгер сиздин ордериңиз кокустан taker катары аткарылса — maker rebate алуунун ордуна сиз taker комиссиясын төлөйсүз. Күнүнө миңдеген ордер боюнча бул кырсык.

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 ордерлер

Айрым биржаларда (Kraken, Bitfinex) жашыруун ордерлер жеткиликтүү — алар ордер китебинде көрүнбөйт, бирок биржада бар жана matching-ге катышат. Мамиле: сиз maker катары да taker комиссияларын төлөйсүз, бирок анонимдүүлүккө ээ болосуз.

Маркет-мейкер үчүн бул — товардык запасты (inventory) башкаруу каражаты: эгер чоң позиция топтолуп калса, аны нарыкка ниетиңизди ачыкка чыгарбай тарамдоо үчүн жашыруун ордер коюуга болот.

Pegged ордерлер

Эң жакшы bid/ask-ка байланган ордер. Мисалы, Coinbase Advanced Trade-те сиз эң жакшы bid-ды автоматтык түрдө байкап туруучу жана дайыма кезектин башында турган ордер коё аласыз. Бул — биржа деңгээлиндеги табигый chasing ордер, бирок бул баары жеринде бирдей жеткиликтүү эмес.

Жалпы ордер башкаруу

Кесипкөй маркет-мейкерлер бир HTTP сурамында бир нече ондогон ордерлерди бир мезгилде жокко чыгаруу жана коюу үчүн batch API-лерди колдонушат. Binance-де бул batchOrders, Bybit-те — place-batch-order. Бул кечигүү жана rate limit басымын азайтат.


8. Ордер Түрлөрүнүн Салыштыруу Кестеси

Ордер Түрү Аткаруу Кепилдиги Баа Кепилдиги Китепте Көрүнөт Биржаларда Табигый Ишке Ашыруу Татаалдыгы
Market Ооба Жок Жок (дароо) Ооба Жок
Limit Жок Ооба Ооба Ооба Жок
Stop-market Ооба (иштеп кеткенден кийин) Жок Жок Ооба Жок
Stop-limit Жок Ооба Жок (иштеп кеткенге чейин) Ооба Жок
Trailing stop Ооба (иштеп кеткенден кийин) Жок Жок Жарым-жартылай Төмөн
Iceberg Жок Ооба Жарым-жартылай Жарым-жартылай Орточо
Post-only Жок Ооба Ооба Ооба Жок
TWAP Жок (бөлүктөргө көз каранды) Жок Жарым-жартылай Жок Орточо
VWAP Жок Жок Жарым-жартылай Жок Жогору
Chasing limit Limit-ден жогору Жарым-жартылай Ооба (учурдагы ордер) Жок Орточо
Убакытка негизделген Түргө көз каранды Түргө көз каранды Жок (T убакытка чейин) Жок Төмөн
Виртуалдык/Синтетикалык Limit-ден төмөн Түргө көз каранды Жок Жок Орточо
OCO Ооба (экөөнүн бирөө) Жарым-жартылай Ооба (экөө тең) Жарым-жартылай Орточо
Bracket Ооба Жарым-жартылай Ооба Сейрек Жогору
Hidden Жок Ооба Жок Сейрек Жок
Pegged Жок Динамикалык Ооба Абдан сейрек Жогору (программалык болсо)

Жыйынтык: Стратегиянын Куруу Блогу Катары Ордер

Ордер түрлөрү жөн гана "интерфейстеги баскычтар" эмес. Алар кандай гана соода системасынын аткаруу катмары курулган негизги примитивдер. "Стратегия бэктестте пайдалуу" менен "стратегия өндүрүштө пайдалуу" ортосундагы айырма көбүнчө так ушул жерде — ордерлерди биржага так кантип жиберериңизде жатат.

Бир нече практикалык жыйынтык:

  1. Стандарттуу ордерлерден баштаңыз, нюанстарды түшүнгөнүңүзгө көз жеткириңиз (stop-limit жана stop-market, IOC жана FOK). Көпчүлүк каталар так ушул жерде болот.
  2. Виртуалдык ордерлер grid боттор үчүн милдеттүү. Эгер сиз 50дөн ашык ордер коюп жатсаңыз — аларды баарын биржага жибербеңиз.
  3. Chasing аткаруу деңгээли баадан маанилүүрөөк болгондо керек. Бирок дайыма max_chase_distance коюңуз — болбосо өтө алыска жылып кетишиңиз мүмкүн.
  4. Убакытка негизделген аткаруу — тар адистештирилген, бирок funding арбитражы жана окуяга негизделген стратегиялар үчүн күчтүү.
  5. Жеке ордерлерди башкаруу катмары ар кандай олуттуу алготрейдинг системасы үчүн сөзсүз керек. Биржанын табигый ордер түрлөрү жетишсиз.

Эгер сиз соода системасын куруп жатсаңыз жана тереңирээк баргыңыз келсе — ордер китебиндеги кезектеги позиция, CCXT-теги WebSocket методдору жана funding rate арбитражы жөнүндөгү макалаларыбызды караңыз.


Шилтемелер жана Булактар

  • CCXT Library — крипто биржалар менен иштөө үчүн бириктирилген китепкана, 100+ биржаны колдойт
  • Binance API Documentation — Binance ордер түрлөрүнүн документтери
  • Bybit API v5 — Bybit документтери, анын ичинде batch ордерлер
  • Moallemi, C. & Yuan, K. (2017). The Value of Queue Position in a Limit Order Book. Columbia Business School Research Paper
  • Cartea, A., Jaimungal, S., & Penalva, J. (2015). Algorithmic and High-Frequency Trading. Cambridge University Press
  • Avellaneda, M. & Stoikov, S. (2008) — High-frequency trading in a limit order book. Quantitative Finance
  • Erik Rigtorp — Order Queue Position Estimation — кезектеги позицияны баалоо боюнча материалдар
  • Trading Technologies (TT) — өнүккөн ордер түрлөрү бар кесипкөй платформа
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

Рынктан бир кадам алдыда болуңуз

AI соода аналитикасы, рынок талдоолору жана платформа жаңылыктары үчүн биздин жаңылыктар бюллетенине жазылыңыз.

Биз сиздин купуялыгыңызды урматтайбыз. Каалаган убакта жазылымдан чыга аласыз.