एल्गोरिदमिक ट्रेडिंग में ऑर्डर प्रकार: चेजिंग वाले लिमिट से लेकर वर्चुअल ऑर्डर तक
जब कोई शुरुआती व्यक्ति एक्सचेंज टर्मिनल खोलता है, तो उसे दो बटन दिखते हैं: "खरीदें" और "बेचें"। जब एक algo trader अपना कोडबेस खोलता है, तो उसे सत्ताईस ऑर्डर प्रकार, एब्स्ट्रैक्शन के तीन स्तर, और edge cases का एक ढेर दिखता है जो उसे लैपटॉप बंद करके किसान बाजार में खीरे बेचने का मन कर देता है। लेकिन खीरे, दुर्भाग्य से, आपको 3:59 UTC पर funding rate arbitrage चलाने नहीं देंगे — तो चलिए इसमें गहराई से उतरते हैं।
इस लेख में, हम बुनियादी एक्सचेंज ऑर्डर से लेकर सिंथेटिक वर्चुअल संरचनाओं तक की पूरी यात्रा करेंगे, जो केवल आपके सिस्टम के भीतर मौजूद होती हैं और कभी भी ऑर्डर बुक में दिखाई नहीं देतीं। TypeScript, Python, थोड़ा दर्द, और थोड़ा ज्ञान की उम्मीद रखें।
1. मानक एक्सचेंज ऑर्डर: वह आधार जिसे आप छोड़ नहीं सकते
मानक ऑर्डर प्रकारों का वर्गीकरण: मार्केट से आइसबर्ग तक
कुछ भी जटिल बनाने से पहले, हमें यह सुनिश्चित करना होगा कि हम बुनियादी बिल्डिंग ब्लॉक्स को सही ढंग से समझते हैं। यह आश्चर्यजनक है कि कितने लोग stop-limit और stop-market को भ्रमित करते हैं, फिर सोचते हैं कि उनका stop "ट्रिगर क्यों नहीं हुआ" (स्पॉइलर: वह ट्रिगर हुआ, लेकिन slippage के कारण लिमिट ऑर्डर fill नहीं हुआ)।
Market order
सबसे सरल और साथ ही सबसे खतरनाक प्रकार। आप एक्सचेंज को बताते हैं: "अभी खरीदें/बेचें, किसी भी उपलब्ध कीमत पर।" एक्सचेंज सबसे अच्छी कीमत से शुरू करके ऑर्डर बुक से लिक्विडिटी लेता है। अगर सबसे अच्छे स्तर पर वॉल्यूम पर्याप्त नहीं है — तो यह आगे slip करता है।
कब उपयोग करें: आपातकालीन पोजीशन एग्जिट, ऐसा सिग्नल execute करना जहां कीमत से ज्यादा गति मायने रखती है।
खतरे: एक पतले बाजार में, 100 BTC के लिए market order कीमत को कई प्रतिशत तक हिला सकता है। बैकटेस्ट जो impact को ध्यान में रखे बिना market orders को मॉडल करते हैं, वे शुद्ध कल्पना हैं।
Limit order
आप एक सटीक कीमत निर्दिष्ट करते हैं। ऑर्डर ऑर्डर बुक में प्रवेश करता है और तब तक इंतजार करता है जब तक कोई आपकी कीमत से सहमत नहीं होता। अगर लिमिट bid order की कीमत मौजूदा बाजार से ऊपर है — तो यह तुरंत fill हो जाता है (market order की तरह, लेकिन गारंटीड अधिकतम कीमत के साथ)।
मुख्य बिंदु: लिमिट order execution की गारंटी नहीं देता। कीमत आपके स्तर तक पहुंचकर वापस पलट सकती है, जिससे आप कतार में बैठे रह जाते हैं (queue position पर हमारे लेख में इसके बारे में अधिक)।
Stop-market और Stop-limit
यहीं से भ्रम शुरू होता है। दोनों प्रकार "सोए हुए" ऑर्डर हैं जो trigger price (stop price) तक पहुंचने पर सक्रिय होते हैं। लेकिन:
- Stop-market: ट्रिगर होने पर, market order में बदल जाता है। execution की गारंटी देता है, लेकिन कीमत की नहीं।
- Stop-limit: ट्रिगर होने पर, limit order में बदल जाता है। कीमत की गारंटी देता है (निर्दिष्ट से बदतर नहीं), लेकिन execution की नहीं।
अस्थिर क्रिप्टो बाजार में, एक stop-limit "चूक" सकता है — कीमत stop को पार कर गई, limit order रखा गया, लेकिन बाजार पहले ही आगे निकल चुका है। आपके पास एक अनफिल्ड limit order और बढ़ता हुआ नुकसान रह जाता है। यही कारण है कि stop-loss के लिए stop-market का अधिक उपयोग किया जाता है।
Trailing stop
एक stop जो एक निश्चित दूरी पर कीमत का "पीछा" करता है। कीमत ऊपर जाती है — stop ऊपर चला जाता है। कीमत नीचे जाती है — stop अपनी जगह पर रहता है। trend-following रणनीतियों में मुनाफे की रक्षा के लिए उपयोगी।
एक्सचेंज समर्थन: सभी एक्सचेंज native trailing stops को सपोर्ट नहीं करते। Algo trader अक्सर इन्हें प्रोग्रामेटिक रूप से implement करते हैं — इससे parameters (callback rate, activation price, step size) पर अधिक नियंत्रण मिलता है।
Iceberg order
एक ऐसा ऑर्डर जिसमें कुल वॉल्यूम का केवल एक अंश ही ऑर्डर बुक में दिखाई देता है। आप 1,000 BTC खरीदना चाहते हैं, लेकिन बुक में केवल 10 दिखाते हैं। जब पहले 10 fill हो जाते हैं — अगले 10 दिखाई देते हैं।
क्यों: बाजार से अपने वास्तविक इरादों को छिपाने के लिए। बुक में एक बड़ा ऑर्डर सभी को यह संकेत देता है कि "कोई बड़ा खरीदना/बेचना चाहता है।" जवाब में, HFT एल्गोरिदम front-running शुरू कर देते हैं, और कीमत आपसे दूर चली जाती है।
चेतावनी: कई क्रिप्टो एक्सचेंजों पर, iceberg orders या तो अनसपोर्टेड हैं या समान वॉल्यूम के पैटर्न से आसानी से पहचाने जाते हैं। उन्नत एल्गोरिदम दृश्यमान हिस्से के आकार को randomize करते हैं।
Time-in-force पैरामीटर: GTC, GTD, IOC, FOK
ये अलग ऑर्डर प्रकार नहीं हैं बल्कि time-in-force पैरामीटर हैं — एक ऑर्डर कितने समय तक जीवित रहता है:
| पैरामीटर | पूरा नाम | व्यवहार |
|---|---|---|
| GTC | Good Till Cancelled | कैंसिल होने तक जीवित रहता है। मानक default |
| GTD | Good Till Date | निर्दिष्ट तारीख/समय तक जीवित रहता है |
| IOC | Immediate or Cancel | तुरंत execute होता है (पूर्ण या आंशिक रूप से), शेष cancel हो जाता है |
| FOK | Fill or Kill | केवल पूर्ण और तुरंत execute होता है। असंभव होने पर — पूरी तरह cancel हो जाता है |
IOC बनाम FOK: अंतर महत्वपूर्ण है। IOC आंशिक रूप से fill हो सकता है — आप 100 BTC खरीदना चाहते थे, 3 खरीदे, बाकी cancel हो गया। FOK या तो 100 है या कुछ नहीं।
Post-only (केवल Maker)
एक ऐसा ऑर्डर जिसकी गारंटी है कि यह maker के रूप में ऑर्डर बुक में प्रवेश करेगा और कभी भी taker के रूप में execute नहीं होगा। अगर रखने के समय कीमत तत्काल execution का कारण बनती है — एक्सचेंज इसे अस्वीकार कर देता है (या कीमत को समायोजित करता है, एक्सचेंज के आधार पर)।
क्यों: maker fees आमतौर पर taker fees से कम होती हैं (Binance पर — VIP स्तरों के लिए 0.02% बनाम 0.04%)। एक दिन में हजारों ऑर्डर रखने वाले market maker के लिए, fee का अंतर लाभ और हानि के बीच का अंतर है।
2. TWAP और VWAP: संस्थान ऑर्डर बुक में हाथी कैसे छिपाते हैं
जब एक hedge fund $50M की पोजीशन खरीदना चाहता है, तो वह एक भी market order नहीं रखता। यह execution algorithms का उपयोग करता है — ऐसे algorithms जो एक बड़े ऑर्डर को कई छोटे ऑर्डर में विभाजित करते हैं और समय के साथ उन्हें execute करते हैं, market impact को कम करते हुए।
TWAP (Time-Weighted Average Price)
विचार बहुत सरल है: कुल वॉल्यूम को बराबर भागों में विभाजित करें और बराबर समय अंतराल पर execute करें।
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% को उस विंडो के दौरान execute करेगा। लक्ष्य औसत execution price को market 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 बेहतर औसत कीमत देता है लेकिन एक विश्वसनीय वॉल्यूम प्रोफाइल की आवश्यकता होती है। क्रिप्टो बाजार में, जहां volumes wash-traded हो सकते हैं, VWAP प्रोफाइल को सावधानी से बनाने की जरूरत है।
3. चेजिंग वाला Limit: जब आपका ऑर्डर कीमत का पीछा करना जानता है
Chasing limit: ऑर्डर configurable आक्रामकता के साथ चलती कीमत का पीछा करता है
अब चीजें वास्तव में दिलचस्प हो जाती हैं। एक standard limit order एक निष्क्रिय entity है: यह ऑर्डर बुक में बैठा इंतजार करता है। अगर कीमत हिलती है — ऑर्डर unfilled रह जाता है। एक algo trader के लिए, यह अक्सर अस्वीकार्य होता है: entry signal फायर हुआ, लेकिन position नहीं बनी क्योंकि बाजार 0.1% हिल गया।
Chasing limit order एक programmatic wrapper है एक limit order के चारों ओर जो:
- मौजूदा सबसे अच्छी कीमत पर (या एक छोटे offset के साथ) एक limit order रखता है
- WebSocket के जरिए कीमत को मॉनिटर करता है
- अगर कीमत ऑर्डर से दूर जाती है — तो cancel करके मौजूदा कीमत के करीब फिर से रखता है
- तब तक दोहराता है जब तक ऑर्डर fill नहीं हो जाता या अनुमत deviation से अधिक नहीं हो जाता
मुख्य पैरामीटर
- chase_interval_ms — ऑर्डर की कितनी बार जांच और replace करनी है। 100ms — आक्रामक, 1000ms — relaxed।
- max_chase_distance — ऑर्डर cancel होने से पहले प्रारंभिक कीमत से अधिकतम विचलन। भागते हुए बाजार का पीछा करने से सुरक्षा।
- aggression_level — limit order को बाजार कीमत के कितने करीब रखना है।
0— सबसे अच्छे bid/ask पर (passive),1— spread को cross करना (आक्रामक, प्रभावी रूप से एक taker)। - chase_on_partial — अगर ऑर्डर आंशिक रूप से fill हो जाए तो chasing जारी रखनी है या नहीं।
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 एक शक्तिशाली उपकरण है, लेकिन इसे नुकसान generator में बदलना आसान है:
- Cancel/replace spam. हर cancel और replace API पर एक load है। एक्सचेंज requests को rate-limit करते हैं, और आक्रामक chasing आपकी API key को ban करवा सकती है।
- Adverse selection. अगर कीमत आपसे दूर भाग रही है — तो बाजार को कुछ पता हो सकता है जो आपको नहीं पता। इस स्थिति में कीमत का पीछा करने का मतलब है ऊपर खरीदना।
- Maker से Taker में बदलाव। उच्च आक्रामकता के साथ आप प्रभावी रूप से taker fees चुका रहे हैं, लेकिन देरी के साथ (cancel + नया ऑर्डर)। कभी-कभी बस एक market order रखना आसान होता है।
4. समय-आधारित ऑर्डर: मिलीसेकंड सटीकता
ऐसी स्थितियां हैं जहां आपको एक ऑर्डर "कीमत X पर" नहीं बल्कि "समय T पर" execute करने की आवश्यकता होती है। अजीब लगता है? यह वास्तव में रणनीतियों की एक पूरी class है।
उपयोग के मामले
Funding rate arbitrage. Perpetual futures पर, funding हर 8 घंटे में भुगतान किया जाता है (00:00, 08:00, 16:00 UTC Binance पर)। अगर funding rate = +0.1% है, तो आपको settlement के समय short होना चाहिए। रणनीति: settlement से कुछ सेकंड पहले short खोलें, funding collect करें, position बंद करें। समय critical है — एक सेकंड की देरी का मतलब है missed funding।
Session खुलना/बंद होना। पारंपरिक बाजारों और कुछ क्रिप्टो derivatives पर, निश्चित sessions होते हैं। opening auction (NYSE, CME) वह क्षण है जब liquidity अपने चरम पर होती है। auction से 100ms पहले एक ऑर्डर रखना एक edge है।
समाचार-आधारित execution. Inflation data एक निर्धारित समय पर जारी किया जाता है। एल्गोरिदम एक news feed से संख्या parse करता है और 50ms के भीतर एक ऑर्डर रखता है। यहां, समय-आधारित execution को event-driven logic के साथ जोड़ा जाता है।
कार्यान्वयन
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);
महत्वपूर्ण चेतावनी: समय-आधारित ऑर्डर की सटीकता आपके कोड से नहीं बल्कि एक्सचेंज तक network latency से सीमित होती है। अगर API के लिए आपका ping 50ms है, तो एक perfect busy-wait भी 50ms का delta रखेगा। गंभीर HFT के लिए, co-location का उपयोग किया जाता है — server भौतिक रूप से एक्सचेंज के matching engine के बगल में बैठा होता है।
5. वर्चुअल/सिंथेटिक ऑर्डर: आपके सिस्टम में अदृश्य
वर्चुअल ऑर्डर: ऑर्डर तब तक केवल बॉट की memory में मौजूद रहते हैं जब तक trigger फायर नहीं हो जाता
यह शायद algo trader के arsenal में सबसे कम आंका गया उपकरण है। एक virtual order (जिसे synthetic order भी कहा जाता है) एक ऐसा ऑर्डर है जो केवल आपके सिस्टम में मौजूद होता है। यह एक्सचेंज को तब तक नहीं भेजा जाता जब तक एक trigger condition पूरी नहीं हो जाती (आमतौर पर — कीमत किसी खास स्तर तक पहुंचना)।
यह कैसे काम करता है
- आपका algorithm तय करता है: "मैं BTC को $40,000 पर खरीदना चाहता हूं"
- एक्सचेंज को limit order भेजने के बजाय, यह memory में एक virtual order बनाता है
- यह WebSocket price stream को subscribe करता है
- जब bid/ask $40,000 तक पहुंचता है — एक्सचेंज को एक वास्तविक market या limit order भेजा जाता है
वर्चुअल ऑर्डर क्यों मायने रखते हैं
कोई जानकारी लीक नहीं होती। आपका ऑर्डर ऑर्डर बुक में अदृश्य है। कोई भी नहीं — न अन्य traders, न HFT algorithms, यहां तक कि एक्सचेंज खुद भी नहीं — execution के क्षण तक आपके इरादों के बारे में जानता है। यह मौलिक रूप से शक्ति के संतुलन को बदल देता है।
Front-running से सुरक्षा। क्रिप्टो एक्सचेंजों पर, खासकर कम पारदर्शी वालों पर, यह उचित संदेह है कि बड़े limit orders के बारे में जानकारी का उपयोग front-running के लिए किया जा सकता है (इस पर studies भी हैं)। Virtual orders इस जोखिम को समाप्त करते हैं।
Grid bots. एक classic grid bot अलग-अलग price levels पर 50-200 orders का एक grid रखता है। अगर आप उन सभी को एक्सचेंज को भेजते हैं — तो बुक में 200 orders होते हैं जो: (a) सभी को दिखाई देते हैं, (b) एक्सचेंज पर order limit का उपयोग करते हैं (आमतौर पर प्रति account 200-300 open orders), (c) अगर कीमत तेजी से हिलती है, तो वे सभी fill हो जाते हैं और आपके पास एक विशाल position रह जाती है। Virtual orders इन तीनों समस्याओं को हल करते हैं।
गिरते चाकुओं को पकड़ना। रणनीति: मौजूदा कीमत से -5%, -10%, -15% नीचे के levels पर virtual buy orders रखें। अगर बाजार गिरता है — orders धीरे-धीरे trigger होते हैं। अगर नहीं गिरता — तो आप कुछ भी risk नहीं करते और कोई एक्सचेंज order slots का उपयोग नहीं करते।
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
);
}
}
वर्चुअल ऑर्डर की कमियां
-
Latency gap. जिस क्षण आप कीमत देखते हैं और जिस क्षण वास्तविक ऑर्डर एक्सचेंज तक पहुंचता है, उसके बीच समय बीत जाता है। एक अस्थिर बाजार में, कीमत उन 20-100ms में उड़ सकती है। समाधान: थोड़ा आक्रामक limit order भेजें (एक buffer के साथ)।
-
छूटे हुए fills. अगर कीमत ने एक ही tick में (flash crash) आपके level को "छेद" दिया और वापस उछल गई — आप समय पर react नहीं कर पाएंगे। एक regular limit order जो बुक में बैठा होता, fill हो जाता; एक virtual order नहीं होता।
-
State management. Virtual orders memory में रहते हैं। अगर process crash होती है — orders खो जाते हैं। समाधान: persistent storage (Redis, SQLite, file) restart पर recovery के साथ।
6. Conditional/Smart Orders: ऑर्डर Combinatorics
जब एक भी ऑर्डर पर्याप्त नहीं होता, traders उन्हें conditional constructions में जोड़ते हैं। कुछ एक्सचेंजों पर natively supported होते हैं, अन्य programmatically implement किए जाते हैं।
OCO (One Cancels Other)
दो orders जुड़े होते हैं: अगर एक execute होता है — दूसरा automatically cancel हो जाता है। Classic उदाहरण: आप एक long position में हैं और take-profit और stop-loss दोनों set करना चाहते हैं। जो भी पहले trigger हो — दूसरे को cancel होना चाहिए।
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
एक तीन-भाग वाली construction: एक primary entry order + exit के लिए OCO (take-profit + stop-loss)। मूलतः, एक ही call में एक पूरा trade lifecycle:
- Entry: limit buy order
- Take-profit: limit sell order (ऊपर)
- Stop-loss: stop-market sell order (नीचे)
जब entry fill होती है, TP और SL automatically रखे जाते हैं। जब इनमें से कोई एक fill होता है — दूसरा cancel हो जाता है।
If-Then Logic
सबसे flexible विकल्प — arbitrary conditions के साथ order chains:
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},
},
]
}
]
ऐसी constructions किसी भी एक्सचेंज द्वारा natively supported नहीं होती हैं — केवल programmatic implementation। यह उन कारणों में से एक है कि algotrading systems अनिवार्य रूप से अपना खुद का order management layer विकसित करते हैं।
7. Market Makers विशेष ऑर्डर प्रकारों का उपयोग कैसे करते हैं
Market making अपना ही एक universe है, और order toolkit उसी के अनुरूप है। एक market maker का काम लगातार bid और ask quote करना है, spread पर कमाना है, जबकि adverse selection को कम से कम करना है (वह स्थिति जहां एक informed trader आपके खिलाफ trade करता है)।
Post-only एक Must-Have के रूप में
एक market maker के लिए, post-only कोई विकल्प नहीं है — यह एक आवश्यकता है। अगर आपका ऑर्डर गलती से taker के रूप में execute हो जाता है — maker rebate प्राप्त करने के बजाय, आप एक taker fee चुकाते हैं। एक दिन में हजारों orders के बीच, यह विनाशकारी है।
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 orders
कुछ एक्सचेंजों पर (Kraken, Bitfinex), hidden orders उपलब्ध हैं — वे ऑर्डर बुक में दिखाई नहीं देते लेकिन एक्सचेंज पर होते हैं और matching में भाग लेते हैं। Tradeoff: आप maker के रूप में भी taker fees चुकाते हैं, लेकिन आपको anonymity मिलती है।
एक market maker के लिए, यह inventory management का एक उपकरण है: अगर एक बड़ी position जमा हो गई है, तो आप बाजार को अपना इरादा बताए बिना उसे unwind करने के लिए एक hidden order रख सकते हैं।
Pegged orders
सबसे अच्छे bid/ask से pegged एक ऑर्डर। उदाहरण के लिए, Coinbase Advanced Trade पर, आप एक ऐसा ऑर्डर रख सकते हैं जो automatically सबसे अच्छे bid को track करता है और हमेशा कतार के आगे रहता है। यह एक्सचेंज स्तर पर एक native chasing order है — लेकिन यह universally available होने से बहुत दूर है।
Bulk order management
Professional market makers batch APIs का उपयोग करके एक ही HTTP request में एक साथ दर्जनों orders को cancel और place करते हैं। Binance पर यह batchOrders है, Bybit पर — place-batch-order। इससे latency और rate limit pressure कम होता है।
8. ऑर्डर प्रकार तुलना तालिका
| ऑर्डर प्रकार | Execution गारंटी | Price गारंटी | बुक में दिखाई देता है | एक्सचेंजों पर Native | कार्यान्वयन जटिलता |
|---|---|---|---|---|---|
| Market | हां | नहीं | नहीं (तत्काल) | हां | कोई नहीं |
| Limit | नहीं | हां | हां | हां | कोई नहीं |
| Stop-market | हां (trigger के बाद) | नहीं | नहीं | हां | कोई नहीं |
| Stop-limit | नहीं | हां | नहीं (trigger तक) | हां | कोई नहीं |
| Trailing stop | हां (trigger के बाद) | नहीं | नहीं | आंशिक | कम |
| Iceberg | नहीं | हां | आंशिक | आंशिक | मध्यम |
| Post-only | नहीं | हां | हां | हां | कोई नहीं |
| TWAP | नहीं (slices पर निर्भर) | नहीं | आंशिक | नहीं | मध्यम |
| VWAP | नहीं | नहीं | आंशिक | नहीं | उच्च |
| Chasing limit | limit से अधिक | आंशिक | हां (current order) | नहीं | मध्यम |
| समय-आधारित | प्रकार पर निर्भर | प्रकार पर निर्भर | नहीं (समय T तक) | नहीं | कम |
| Virtual/Synthetic | limit से कम | प्रकार पर निर्भर | नहीं | नहीं | मध्यम |
| OCO | हां (दो में से एक) | आंशिक | हां (दोनों) | आंशिक | मध्यम |
| Bracket | हां | आंशिक | हां | दुर्लभ | उच्च |
| Hidden | नहीं | हां | नहीं | दुर्लभ | कोई नहीं |
| Pegged | नहीं | Dynamic | हां | बहुत दुर्लभ | उच्च (अगर programmatic) |
निष्कर्ष: रणनीति के building block के रूप में ऑर्डर
ऑर्डर प्रकार सिर्फ "interface में buttons" नहीं हैं। वे मौलिक primitives हैं जिनसे किसी भी trading system की execution layer बनाई जाती है। "backtesting में रणनीति लाभदायक है" और "production में रणनीति लाभदायक है" के बीच का अंतर अक्सर ठीक यहीं होता है — आप एक्सचेंज को orders कैसे भेजते हैं, इसमें।
कुछ practical takeaways:
- मानक orders से शुरू करें, सुनिश्चित करें कि आप nuances समझते हैं (stop-limit बनाम stop-market, IOC बनाम FOK)। अधिकांश गलतियां यहीं होती हैं।
- Virtual orders grid bots के लिए must-have हैं। अगर आप 50 से अधिक orders रख रहे हैं — उन सभी को एक्सचेंज को न भेजें।
- Chasing तब आवश्यक है जब fill rate कीमत से अधिक मायने रखता है। लेकिन हमेशा max_chase_distance सेट करें — नहीं तो आप बहुत दूर drift कर सकते हैं।
- समय-आधारित execution niche है लेकिन funding arb और event-driven रणनीतियों के लिए शक्तिशाली है।
- एक custom order management layer किसी भी गंभीर algotrading system के लिए अनिवार्य है। Exchange-native order types पर्याप्त नहीं हैं।
अगर आप एक trading system बना रहे हैं और गहराई से जाना चाहते हैं — order book में queue position, CCXT में WebSocket methods, और funding rate arbitrage पर हमारे लेख देखें।
संदर्भ और स्रोत
- CCXT Library — क्रिप्टो एक्सचेंजों के साथ काम करने के लिए एक unified library, 100+ एक्सचेंजों का समर्थन करती है
- Binance API Documentation — Binance ऑर्डर प्रकारों का documentation
- Bybit API v5 — Bybit documentation, batch orders सहित
- 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 — queue position estimation पर सामग्री
- Trading Technologies (TT) — advanced order types के साथ एक professional platform
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.