Алгоритмдік Трейдингтегі Ордер Түрлері: Chasing бар Лимиттен Виртуалды Ордерлерге дейін
Жаңадан бастаған адам биржа терминалын ашқанда, ол екі батырманы көреді: "Сатып алу" және "Сату". Алго-трейдер өз кодын ашқанда, ол жиырма жеті ордер түрін, үш абстракция деңгейін және ноутбукты жауып, базарда қияр сатқысы келтіретін бір топ шектік жағдайларды көреді. Бірақ, өкінішке орай, қияр сізге 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 ақылдырақ: ол әдеттегі сауда көлемі профилін ескереді. Егер күндізгі көлемнің 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 limit: ордер баптауға болатын агрессивтілікпен қозғалатын бағаны қуалайды
Енді нағыз қызық басталады. Стандартты лимиттік ордер — пассивті нысан: ол ордер кітабында отырып күтеді. Баға қозғалса — ордер орындалмай қалады. Алго-трейдер үшін бұл көбіне қолайсыз: кіру сигналы іске қосылды, бірақ нарық 0,1%-ға қозғалғандықтан позиция құрылмады.
Chasing limit order — бұл лимиттік ордердің айналасындағы бағдарламалық орауыш, ол:
- Ағымдағы ең жақсы бағада (немесе шағын offset-пен) лимиттік ордер қояды
- Бағаны WebSocket арқылы бақылайды
- Егер баға ордерден алшақтаса — оны тоқтатып, ағымдағы бағаға жақынырақ қайта қояды
- Ордер орындалғанша немесе рұқсат етілген ауытқудан асып кеткенше қайталайды
Негізгі Параметрлер
- chase_interval_ms — ордерді қаншалықты жиі тексеру және қайта қою. 100мс — агрессивті, 1000мс — босаң.
- max_chase_distance — ордер тоқтатылғанға дейінгі бастапқы бағадан максималды ауытқу. Қашып бара жатқан нарықты қуалаудан қорғаныс.
- aggression_level — лимиттік ордерді нарықтық бағаға қаншалықты жақын қою керек.
0— ең жақсы bid/ask-та (пассивті),1— спредті кесіп өту (агрессивті, іс жүзінде 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 — қуатты құрал, бірақ оны шығын генераторына айналдыру оңай:
- Cancel/replace спамы. Әрбір тоқтату мен қайта қою API-ге жүктеме болып табылады. Биржалар сұраныстарды шектейді (rate limit), ал агрессивті chasing API кілтіңіздің бұғатталуына әкелуі мүмкін.
- Кері таңдау (adverse selection). Егер баға сізден қашып жатса — нарық сіз білмейтін нәрсені білуі мүмкін. Мұндай жағдайда бағаны қуалау шыңында сатып алуды білдіреді.
- Maker-ден Taker-ге ауысу. Жоғары агрессивтілікпен сіз іс жүзінде taker комиссияларын төлейсіз, бірақ кешігумен (тоқтату + жаңа ордер). Кейде жай ғана market ордер қою оңайырақ.
4. Уақытқа Негізделген Ордерлер: Миллисекундтық Дәлдік
Ордерді "X бағада" емес, "T уақытта" орындау қажет жағдайлар бар. Оғаш естіледі ме? Шын мәнінде бұл толық стратегиялар класы.
Пайдалану жағдайлары
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. Виртуалды/Синтетикалық Ордерлер: Жүйеңіздегі Көрінбейтіндер
Виртуалды ордерлер: іске қосылғыш іске қосылғанға дейін тек бот жадында өмір сүреді
Бұл, мүмкін, алго-трейдер қаруының ең бағаланбаған құралы. Виртуалды ордер (синтетикалық ордер деп те аталады) — тек сіздің жүйеңізде ғана өмір сүретін ордер. Ол іске қосылу шарты орындалғанға дейін (әдетте — баға белгілі бір деңгейге жеткенге дейін) биржаға жіберілмейді.
Бұл Қалай Жұмыс Істейді
- Сіздің алгоритміңіз шешеді: "BTC-ды 40 000 долларға сатып алғым келеді"
- Биржаға лимиттік ордер жіберудің орнына, ол жадта виртуалды ордер жасайды
- WebSocket баға ағынына жазылады
- 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
);
}
}
Виртуалды Ордерлердің Осал Тұстары
-
Кідіріс алшақтығы. Сіз бағаны көрген сәт пен нақты ордер биржаға жеткен сәт арасында уақыт өтеді. Тұрақсыз нарықта баға сол 20-100мс ішінде ұшып кетуі мүмкін. Шешім: сәл агрессивті лимиттік ордер жіберу (буфермен).
-
Өткізіп алынған орындалулар. Егер баға сіздің деңгейіңізді бір тикте (flash crash) "тесіп өтіп" қайтадан оралса — сіз уақытында әрекет ете алмауыңыз мүмкін. Кітапта отырған қарапайым лимиттік ордер орындалған болар еді; виртуалды ордер — жоқ.
-
Күй басқару. Виртуалды ордерлер жадта өмір сүреді. Процесс құласа — ордерлер жоғалады. Шешім: қайта іске қосқанда қалпына келтірумен тұрақты сақтау (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). Мәні бойынша, бір ғана шақыруда мәміленің толық өмірлік циклі:
- Кіру: сатып алуға лимиттік ордер
- Take-profit: сатуға лимиттік ордер (жоғарыда)
- 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 | Жоқ | Динамикалық | Иә | Өте сирек | Жоғары (бағдарламалық болса) |
Қорытынды: Стратегияның Құрылыс Блогі Ретіндегі Ордер
Ордер түрлері жай ғана "интерфейстегі батырмалар" емес. Олар кез келген сауда жүйесінің орындау қабаты құрылатын іргелі примитивтер. "Стратегия бэктестте пайдалы" мен "стратегия өндірісте пайдалы" арасындағы айырмашылық көбіне дәл осында — ордерлерді биржаға дәл қалай жіберетініңізде жатыр.
Бірнеше практикалық қорытынды:
- Стандартты ордерлерден бастаңыз, нюанстарды түсінгеніңізге көз жеткізіңіз (stop-limit пен stop-market, IOC пен FOK). Көптеген қателер дәл осында болады.
- Виртуалды ордерлер grid боттар үшін міндетті. Егер сіз 50-ден астам ордер қойсаңыз — оларды бәрін биржаға жібермеңіз.
- Chasing орындалу жылдамдығы бағадан маңыздырақ болғанда қажет. Бірақ әрдайым max_chase_distance орнатыңыз — әйтпесе өте алысқа жылжып кетуіңіз мүмкін.
- Уақытқа негізделген орындау — тар мамандандырылған, бірақ funding арбитражы мен оқиғаға негізделген стратегиялар үшін қуатты.
- Жеке ордерлерді басқару қабаты кез келген байсалды алготрейдинг жүйесі үшін сөзсіз қажет. Биржаның табиғи ордер түрлері жеткіліксіз.
Егер сіз сауда жүйесін құрып жатсаңыз және тереңірек барғыңыз келсе — ордер кітабындағы кезектегі позиция, 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) — озық ордер түрлері бар кәсіби платформа
Authors
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.