أنواع الأوامر في التداول الخوارزمي: من أوامر الحد المطاردة إلى الأوامر الافتراضية
عندما يفتح المبتدئ واجهة المنصة، يرى زرين: "شراء" و"بيع". وعندما يفتح المتداول الخوارزمي قاعدة الكود الخاصة به، يرى سبعة وعشرين نوعاً من الأوامر، وثلاثة مستويات من التجريد، وكومة من الحالات الحدية التي تجعله يريد إغلاق الحاسوب والذهاب لبيع الخيار في السوق. لكن الخيار لن يمكّنك للأسف من تنفيذ مراجحة معدل التمويل في الساعة 3:59 بتوقيت UTC — لذا دعونا نتعمق في الموضوع.
في هذا المقال، سنمر بالرحلة كاملة من أوامر المنصة الأساسية إلى التركيبات الافتراضية التركيبية التي توجد فقط في نظامك ولا تظهر أبداً في دفتر الأوامر. توقع TypeScript وPython وبعض المعاناة وقليلاً من التنوير.
1. أوامر المنصة القياسية: الأساس الذي لا غنى عنه
تصنيف أنواع الأوامر القياسية: من أمر السوق إلى أمر الجبل الجليدي
قبل بناء أي شيء معقد، نحتاج للتأكد من فهمنا الصحيح لوحدات البناء الأساسية. من المدهش عدد الأشخاص الذين يخلطون بين أمر الوقف المحدد وأمر الوقف السوقي، ثم يتساءلون لماذا لم "يعمل" وقفهم (المفاجأة: لقد عمل، لكن الأمر المحدد لم يُنفذ بسبب الانزلاق السعري).
أمر السوق (Market order)
أبسط وأخطر نوع في آن واحد. تقول للمنصة: "اشترِ/بِع الآن، بأي سعر متاح." تأخذ المنصة السيولة من دفتر الأوامر بدءاً من أفضل سعر. إذا لم يكن الحجم عند أفضل مستوى كافياً — ينزلق إلى مستويات أعمق.
متى تستخدمه: الخروج الطارئ من المركز، تنفيذ إشارة حيث السرعة أهم من السعر.
المخاطر الخفية: في سوق ضعيف السيولة، يمكن لأمر سوق بقيمة 100 BTC أن يحرك السعر عدة نقاط مئوية. الاختبارات الخلفية التي تنمذج أوامر السوق دون حساب تأثير السوق هي مجرد خيال.
الأمر المحدد (Limit order)
تحدد سعراً دقيقاً. يدخل الأمر في دفتر الأوامر وينتظر حتى يوافق أحد على سعرك. إذا كان سعر أمر الشراء المحدد أعلى من السعر السوقي الحالي — فسيُنفذ فوراً (مثل أمر السوق، لكن مع ضمان حد أقصى للسعر).
النقطة الجوهرية: الأمر المحدد لا يضمن التنفيذ. قد يصل السعر إلى مستواك ثم ينعكس، وتبقى أنت في طابور الانتظار (المزيد عن هذا في مقالنا عن موقع الطابور).
أمر الوقف السوقي وأمر الوقف المحدد
هنا تبدأ منطقة الالتباس. كلا النوعين هما أوامر "نائمة" تُفعّل عند الوصول إلى سعر التفعيل (سعر الوقف). لكن:
- أمر الوقف السوقي (Stop-market): عند التفعيل يتحول إلى أمر سوق. ضمان التنفيذ لكن ليس السعر.
- أمر الوقف المحدد (Stop-limit): عند التفعيل يتحول إلى أمر محدد. ضمان السعر (لا أسوأ من المحدد) لكن ليس التنفيذ.
في سوق العملات الرقمية المتقلب، يمكن لأمر الوقف المحدد أن "يخطئ" — السعر اخترق الوقف، وُضع الأمر المحدد، لكن السوق قد طار بعيداً بالفعل. تبقى مع أمر محدد غير منفذ وخسارة متزايدة. هذا هو السبب في استخدام أمر الوقف السوقي بشكل أكثر شيوعاً لوقف الخسارة.
الوقف المتحرك (Trailing stop)
وقف "يتبع" السعر على مسافة محددة. السعر يرتفع — الوقف يرتفع. السعر ينخفض — الوقف يبقى مكانه. مفيد لحماية الأرباح في استراتيجيات تتبع الاتجاه.
دعم المنصات: ليست كل المنصات تدعم الوقف المتحرك الأصلي. غالباً ما ينفذه المتداولون الخوارزميون برمجياً — لمزيد من التحكم في المعلمات (معدل الاستدعاء، سعر التفعيل، حجم الخطوة).
أمر الجبل الجليدي (Iceberg order)
أمر لا يُظهر في دفتر الأوامر سوى جزء صغير من الحجم الإجمالي. تريد شراء 1,000 BTC، لكنك تُظهر 10 فقط في الدفتر. عندما تُنفذ أول 10 — تظهر الـ 10 التالية.
لماذا: لإخفاء نواياك الحقيقية عن السوق. أمر كبير في الدفتر هو إشارة للجميع بأن "شخصاً كبيراً يريد الشراء/البيع." استجابةً لذلك، تبدأ خوارزميات التداول عالي التردد بالتقدم على الصفقة، ويبتعد السعر عنك.
تحذير: في العديد من منصات العملات الرقمية، إما أن أوامر الجبل الجليدي غير مدعومة أو يسهل اكتشافها من خلال نمط الأحجام المتطابقة. تقوم الخوارزميات المتقدمة بعشوائية حجم الجزء المرئي.
معلمات مدة الصلاحية: GTC، GTD، IOC، FOK
هذه ليست أنواعاً مستقلة من الأوامر بل معلمات مدة صلاحية (time-in-force) — كم يبقى الأمر حياً:
| المعلمة | الاسم الكامل | السلوك |
|---|---|---|
| GTC | Good Till Cancelled | يبقى حتى الإلغاء. المعيار الافتراضي |
| GTD | Good Till Date | يبقى حتى تاريخ/وقت محدد |
| IOC | Immediate or Cancel | يُنفذ فوراً (كلياً أو جزئياً)، الباقي يُلغى |
| FOK | Fill or Kill | يُنفذ كلياً فقط وفوراً. إذا تعذر — يُلغى بالكامل |
IOC مقابل FOK: الفرق حاسم. IOC يمكن أن يُنفذ جزئياً — أردت شراء 100 BTC، اشتريت 3، والباقي أُلغي. FOK إما 100 أو لا شيء.
أمر النشر فقط (Post-only / Maker-only)
أمر مضمون الدخول في دفتر الأوامر كصانع سوق ولا يُنفذ أبداً كآخذ سيولة. إذا كان السعر عند تقديم الأمر سيؤدي إلى تنفيذ فوري — ترفضه المنصة (أو تعدّل السعر، حسب المنصة).
لماذا: عمولات صانع السوق عادةً أقل من عمولات آخذ السيولة (في Binance — 0.02% مقابل 0.04% لمستويات VIP). بالنسبة لصانع السوق الذي يقدم آلاف الأوامر يومياً، فارق العمولات هو الفارق بين الربح والخسارة.
2. TWAP وVWAP: كيف تُخفي المؤسسات فيلاً في دفتر الأوامر
عندما يريد صندوق تحوّط شراء مركز بقيمة 50 مليون دولار، لا يضع أمر سوق واحداً. يستخدم خوارزميات التنفيذ — خوارزميات تقسم الأمر الكبير إلى العديد من الأوامر الصغيرة وتنفذها على مدار الوقت لتقليل تأثير السوق.
TWAP (متوسط السعر المرجح بالوقت)
الفكرة بسيطة للغاية: قسّم الحجم الإجمالي إلى أجزاء متساوية ونفّذ على فترات زمنية متساوية.
import asyncio
from datetime import datetime, timedelta
class TWAPExecutor:
"""
منفّذ TWAP: يقسم الأمر الكبير إلى أجزاء متساوية
وينفذها على فترات زمنية متساوية.
"""
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 (متوسط السعر المرجح بالحجم)
VWAP أذكى: يأخذ في الاعتبار ملف حجم التداول النموذجي. إذا كان 30% من حجم التداول اليومي يحدث عادةً بين 9:00 و10:00، فإن VWAP سينفذ 30% من الأمر خلال تلك الفترة. الهدف هو جعل متوسط سعر التنفيذ أقرب ما يمكن إلى VWAP السوقي.
class VWAPExecutor:
"""
منفّذ VWAP: يوزع الحجم بشكل متناسب
مع ملف الحجم التاريخي.
"""
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 trading)، يجب بناء ملف VWAP بحذر.
3. أمر الحد المطارد: عندما يعرف أمرك كيف يطارد السعر
أمر الحد المطارد: الأمر يطارد السعر المتحرك بدرجة عدوانية قابلة للضبط
الآن تبدأ الأمور بالتشويق حقاً. الأمر المحدد القياسي كيان سلبي: يجلس في دفتر الأوامر وينتظر. إذا تحرك السعر — يبقى الأمر غير منفذ. بالنسبة للمتداول الخوارزمي، هذا غالباً غير مقبول: صدرت إشارة الدخول، لكن المركز لم يُبنَ لأن السوق تحرك 0.1%.
أمر الحد المطارد (Chasing limit order) هو غلاف برمجي حول الأمر المحدد يقوم بـ:
- تقديم أمر محدد عند أفضل سعر حالي (أو مع إزاحة طفيفة)
- مراقبة السعر عبر WebSocket
- إذا ابتعد السعر عن الأمر — إلغاؤه وإعادة تقديمه أقرب إلى السعر الحالي
- التكرار حتى يُنفذ الأمر أو يتجاوز الانحراف المسموح
المعلمات الرئيسية
- chase_interval_ms — كم مرة يتم الفحص وإعادة التقديم. 100ms — عدواني، 1000ms — هادئ.
- max_chase_distance — أقصى انحراف عن السعر الأولي، وبعده يُلغى الأمر. حماية من مطاردة سوق هارب.
- aggression_level — مدى قرب الأمر المحدد من سعر السوق.
0— عند أفضل عرض/طلب (سلبي)،1— عبور الفارق (عدواني، فعلياً آخذ سيولة). - 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) {
// انتهاء المهلة
if (Date.now() - this.startTime > this.params.timeoutMs) {
console.log("[CHASE] timeout reached, cancelling");
await this.cancelCurrent();
break;
}
// جلب دفتر الأوامر الحالي
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;
// حساب السعر المستهدف
let targetPrice: number;
if (this.params.side === "buy") {
targetPrice = bestBid + spread * this.params.aggression;
} else {
targetPrice = bestAsk - spread * this.params.aggression;
}
// تسجيل السعر الأولي
if (this.initialPrice === null) {
this.initialPrice = targetPrice;
}
// فحص أقصى مسافة مطاردة
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;
}
// فحص الأمر الحالي
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;
}
// تحديث filledQty للتنفيذ الجزئي
if (order.filled > 0) {
const newFilled = order.filled - (
fills.reduce((s, f) => s + f.qty, 0) - this.filledQty
);
// الأمر في مكانه — هل نحتاج لإعادة التسعير؟
}
const currentPrice = parseFloat(order.price);
const priceDiff = Math.abs(currentPrice - targetPrice);
const tickSize = spread * 0.1 || 0.01;
if (priceDiff > tickSize) {
// السعر تحرك — إعادة التسعير
console.log(
`[CHASE] repricing: ${currentPrice} -> ` +
`${targetPrice.toFixed(4)}`
);
await this.cancelCurrent();
} else {
// الأمر عند السعر الصحيح — انتظار
await this.sleep(this.params.chaseIntervalMs);
continue;
}
}
// تقديم أمر جديد
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 { /* الأمر منفذ أو ملغى بالفعل */ }
this.currentOrderId = null;
}
}
private sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
}
متى تكون المطاردة ضارة
المطاردة أداة قوية، لكن من السهل تحويلها إلى مولد خسائر:
- إغراق الإلغاء/إعادة التقديم. كل إلغاء وإعادة تقديم يمثل حملاً على واجهة API. المنصات تحدد معدل الطلبات، والمطاردة العدوانية قد تؤدي إلى حظر مفتاح API.
- الاختيار العكسي. إذا كان السعر يهرب منك — ربما يعرف السوق شيئاً لا تعرفه. مطاردة السعر في هذه الحالة تعني الشراء عند القمة.
- التحول من صانع إلى آخذ. بعدوانية عالية أنت فعلياً تدفع عمولة آخذ السيولة، لكن مع تأخير (إلغاء + أمر جديد). أحياناً يكون من الأبسط تقديم أمر سوق مباشرة.
4. الأوامر الزمنية: دقة بالملّي ثانية
هناك حالات تحتاج فيها لتنفيذ أمر ليس "عند السعر X" بل "في الوقت T". يبدو غريباً؟ إنها في الواقع فئة كاملة من الاستراتيجيات.
حالات الاستخدام
مراجحة معدل التمويل. في العقود الآجلة الدائمة، يُدفع التمويل كل 8 ساعات (00:00، 08:00، 16:00 بتوقيت UTC على Binance). إذا كان معدل التمويل = +0.1%، تحتاج لتكون في مركز بيع عند لحظة التسوية. الاستراتيجية: فتح مركز بيع قبل ثوانٍ من التسوية، تحصيل التمويل، إغلاق المركز. التوقيت حاسم — ثانية تأخير تعني تمويلاً ضائعاً.
افتتاح/إغلاق الجلسات. في الأسواق التقليدية وبعض مشتقات العملات الرقمية، هناك جلسات ثابتة. مزاد الافتتاح (NYSE، CME) هو اللحظة التي تكون فيها السيولة في ذروتها. تقديم أمر قبل 100ms من المزاد يمنحك ميزة.
التنفيذ المبني على الأخبار. بيانات التضخم تصدر في وقت محدد. الخوارزمية تحلل الرقم من تغذية الأخبار وتقدم أمراً خلال 50ms. هنا يتجمع التنفيذ الزمني مع المنطق المدفوع بالأحداث.
التنفيذ
class TimeBasedOrder {
constructor(
private exchange: any,
private symbol: string,
private side: "buy" | "sell",
private qty: number,
private orderType: "market" | "limit",
private limitPrice?: number
) {}
/**
* جدولة التنفيذ في وقت دقيق.
* يستخدم حلقة انتظار نشطة لأقصى دقة.
*/
async executeAt(targetTime: Date): Promise<any> {
const targetMs = targetTime.getTime();
// المرحلة 1: انتظار تقريبي (نوم)
const coarseWait = targetMs - Date.now() - 500; // الاستيقاظ قبل 500ms
if (coarseWait > 0) {
console.log(
`[TIME-ORDER] sleeping for ${(coarseWait / 1000).toFixed(1)}s`
);
await new Promise((r) => setTimeout(r, coarseWait));
}
// المرحلة 2: انتظار دقيق (انتظار نشط)
while (Date.now() < targetMs) {
// دوران — يستهلك المعالج لكن يحقق دقة ~1ms
}
// المرحلة 3: التنفيذ
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;
}
}
// مثال: تقديم أمر بالضبط في 00:00:00 UTC (تسوية التمويل)
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);
ملاحظة مهمة: دقة الأمر الزمني محدودة ليس بكودك بل بزمن الوصول الشبكي إلى المنصة. إذا كان الـ ping إلى API هو 50ms، فحتى الانتظار النشط المثالي سيعطي فارقاً قدره 50ms. للتداول عالي التردد الجاد، يُستخدم التخزين المشترك (co-location) — الخادم يقع فعلياً بجوار محرك المطابقة في المنصة.
5. الأوامر الافتراضية/التركيبية: الخفيّات في نظامك
الأوامر الافتراضية: أوامر لا توجد إلا في ذاكرة البوت حتى يُطلق المشغّل
هذه ربما أكثر أداة مقلّلة القيمة في ترسانة المتداول الخوارزمي. الأمر الافتراضي (المعروف أيضاً بالأمر التركيبي) هو أمر يوجد فقط في نظامك. لا يُرسل إلى المنصة حتى يتحقق شرط التفعيل (عادةً — وصول السعر إلى مستوى معين).
كيف يعمل
- خوارزميتك تقرر: "أريد شراء BTC بسعر $40,000"
- بدلاً من إرسال أمر محدد إلى المنصة، تنشئ أمراً افتراضياً في الذاكرة
- تشترك في تيار أسعار WebSocket
- عندما يصل العرض/الطلب إلى $40,000 — ترسل أمر سوق أو أمر محدد حقيقي إلى المنصة
لماذا الأوامر الافتراضية مهمة
لا تسريب معلومات. أمرك غير مرئي في دفتر الأوامر. لا أحد — لا متداولون آخرون، ولا خوارزميات تداول عالي التردد، ولا حتى المنصة نفسها — يعلم بنواياك حتى لحظة التنفيذ. هذا يغير ميزان القوى جذرياً.
الحماية من التقدم على الصفقة. في منصات العملات الرقمية، خاصةً الأقل شفافية، هناك شكوك معقولة بأن معلومات الأوامر المحددة الكبيرة قد تُستخدم للتقدم على الصفقة (توجد حتى دراسات حول هذا). الأوامر الافتراضية تقضي على هذا الخطر.
بوتات الشبكة. بوت الشبكة الكلاسيكي يضع شبكة من 50-200 أمر على مستويات سعرية مختلفة. إذا أرسلتها كلها إلى المنصة — فهذه 200 أمر في الدفتر: (أ) مرئية للجميع، (ب) تستهلك حد الأوامر على المنصة (عادةً 200-300 أمر مفتوح لكل حساب)، (ج) عند حركة سعرية حادة تُنفذ كلها وينتهي بك الأمر بمركز ضخم. الأوامر الافتراضية تحل المشاكل الثلاث.
التقاط السكاكين الساقطة. الاستراتيجية: وضع أوامر شراء افتراضية عند مستويات -5%، -10%، -15% من السعر الحالي. إذا انخفض السوق — تُفعّل الأوامر تدريجياً. إذا لم ينخفض — لا مخاطرة ولا استهلاك لحصص الأوامر على المنصة.
التنفيذ بـ TypeScript
interface VirtualOrder {
id: string;
symbol: string;
side: "buy" | "sell";
triggerPrice: number;
qty: number;
/** نوع الأمر الذي يُرسل إلى المنصة عند التفعيل */
executionType: "market" | "limit";
/** للأمر المحدد: الإزاحة من سعر التفعيل */
limitOffset?: number;
status: "pending" | "triggered" | "filled" | "failed";
}
class VirtualOrderManager {
private orders: Map<string, VirtualOrder> = new Map();
private orderCounter = 0;
constructor(private exchange: any) {}
/**
* إنشاء أمر افتراضي. لا يُرسل شيء إلى المنصة.
*/
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;
}
/**
* يُستدعى عند كل تحديث سعر (من 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);
}
}
}
/**
* جلب جميع الأوامر الافتراضية النشطة.
*/
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;
}
}
// --- مثال: بوت شبكة بأوامر افتراضية ---
async function gridBot(exchange: any) {
const manager = new VirtualOrderManager(exchange);
const currentPrice = 42000;
const gridStep = 200; // خطوة الشبكة
const gridLevels = 20; // عدد المستويات في كل اتجاه
const qtyPerLevel = 0.01; // BTC لكل مستوى
// إنشاء الشبكة الافتراضية
for (let i = 1; i <= gridLevels; i++) {
// أوامر شراء أسفل السعر الحالي
manager.addOrder({
symbol: "BTC/USDT",
side: "buy",
triggerPrice: currentPrice - gridStep * i,
qty: qtyPerLevel,
executionType: "limit",
limitOffset: 1, // limit price = trigger + 1 USDT
});
// أوامر بيع أعلى السعر الحالي
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 (كود وهمي لـ ccxt.pro)
while (true) {
const ticker = await exchange.watchTicker("BTC/USDT");
await manager.onPriceUpdate(
"BTC/USDT", ticker.bid, ticker.ask
);
}
}
مخاطر الأوامر الافتراضية
-
فجوة زمن الوصول. بين لحظة رؤية السعر ولحظة وصول الأمر الحقيقي إلى المنصة، يمر وقت. في سوق متقلب، قد يتحرك السعر بعيداً خلال تلك الـ 20-100ms. الحل: إرسال أمر محدد عدواني قليلاً (مع هامش).
-
تفويت التنفيذ. إذا "اخترق" السعر مستواك في نبضة واحدة (انهيار خاطف) وارتد — قد لا تلحق. أمر محدد عادي في الدفتر كان سيُنفذ، الأمر الافتراضي — لن يُنفذ.
-
إدارة الحالة. الأوامر الافتراضية تعيش في الذاكرة. إذا تعطلت العملية — تضيع الأوامر. الحل: تخزين دائم (Redis، SQLite، ملف) مع استعادة عند إعادة التشغيل.
6. الأوامر الشرطية/الذكية: توليفات الأوامر
عندما لا يكفي أمر واحد، يجمع المتداولون بينها في تركيبات شرطية. بعضها مدعوم أصلياً على المنصات، والبعض الآخر يُنفذ برمجياً.
OCO (واحد يلغي الآخر)
أمران مرتبطان: إذا نُفذ أحدهما — يُلغى الآخر تلقائياً. مثال كلاسيكي: أنت في مركز شراء وتريد وضع جني أرباح ووقف خسارة معاً. أيهما يُفعّل أولاً — يجب إلغاء الآخر.
class OCOHandler:
"""
OCO: عند تنفيذ أحد الأمرين، يُلغى الآخر.
"""
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):
"""يفحص الحالات ويلغي الأمر المقترن."""
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 للخروج (جني أرباح + وقف خسارة). في الأساس، دورة تداول كاملة في استدعاء واحد:
- الدخول: أمر شراء محدد
- جني الأرباح: أمر بيع محدد (أعلى)
- وقف الخسارة: أمر بيع وقف سوقي (أدنى)
عند تنفيذ أمر الدخول، يتم تقديم 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. كيف يستخدم صانعو السوق أنواع الأوامر المتخصصة
صناعة السوق عالم قائم بذاته، ومجموعة أدوات الأوامر تتناسب معه. مهمة صانع السوق هي التسعير المستمر لعروض الشراء والبيع، والكسب من الفارق السعري، مع تقليل الاختيار العكسي (الحالة التي يتداول فيها متداول مطّلع ضدك).
أمر النشر فقط كضرورة
بالنسبة لصانع السوق، أمر النشر فقط ليس خياراً — إنه شرط. إذا نُفذ أمرك عن طريق الخطأ كآخذ سيولة — بدلاً من الحصول على مكافأة صانع السوق تدفع عمولة آخذ السيولة. عبر آلاف الأوامر يومياً، هذا كارثي.
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} # حاسم لصانعي السوق
)
ask = await exchange.create_order(
symbol, "limit", "sell", qty, ask_price,
{"postOnly": True}
)
return bid, ask
الأوامر المخفية
في بعض المنصات (Kraken، Bitfinex) تتوفر أوامر مخفية — لا تظهر في دفتر الأوامر لكنها موجودة على المنصة وتشارك في المطابقة. المقايضة: تدفع عمولة آخذ السيولة حتى كصانع سوق، لكنك تحصل على السرية.
بالنسبة لصانع السوق، هذه أداة لإدارة المخزون: إذا تراكم مركز كبير، يمكنك وضع أمر مخفي لتفريغه دون الكشف عن نيتك للسوق.
الأوامر المربوطة (Pegged orders)
أمر مربوط بأفضل عرض/طلب. في Coinbase Advanced Trade مثلاً، يمكنك تقديم أمر يتتبع تلقائياً أفضل عرض شراء ويبقى دائماً في مقدمة الطابور. هذا أمر مطاردة أصلي على مستوى المنصة — لكنه ليس متوفراً في كل مكان.
إدارة الأوامر بالجملة
يستخدم صانعو السوق المحترفون واجهات API الدُفعية لإلغاء وتقديم عشرات الأوامر في طلب HTTP واحد. في Binance هذا هو batchOrders، في Bybit — place-batch-order. هذا يقلل زمن الوصول وضغط حدود المعدل.
8. جدول مقارنة أنواع الأوامر
| نوع الأمر | ضمان التنفيذ | ضمان السعر | مرئي في الدفتر | أصلي على المنصات | تعقيد التنفيذ |
|---|---|---|---|---|---|
| سوق | نعم | لا | لا (فوري) | نعم | صفر |
| محدد | لا | نعم | نعم | نعم | صفر |
| وقف سوقي | نعم (بعد التفعيل) | لا | لا | نعم | صفر |
| وقف محدد | لا | نعم | لا (قبل التفعيل) | نعم | صفر |
| وقف متحرك | نعم (بعد التفعيل) | لا | لا | جزئي | منخفض |
| جبل جليدي | لا | نعم | جزئياً | جزئي | متوسط |
| نشر فقط | لا | نعم | نعم | نعم | صفر |
| TWAP | لا (يعتمد على الشرائح) | لا | جزئياً | لا | متوسط |
| VWAP | لا | لا | جزئياً | لا | عالٍ |
| حد مطارد | أعلى من المحدد | جزئي | نعم (الأمر الحالي) | لا | متوسط |
| زمني | يعتمد على النوع | يعتمد على النوع | لا (حتى الوقت T) | لا | منخفض |
| افتراضي/تركيبي | أقل من المحدد | يعتمد على النوع | لا | لا | متوسط |
| OCO | نعم (واحد من اثنين) | جزئي | نعم (كلاهما) | جزئي | متوسط |
| قوس | نعم | جزئي | نعم | نادر | عالٍ |
| مخفي | لا | نعم | لا | نادر | صفر |
| مربوط | لا | ديناميكي | نعم | نادر جداً | عالٍ (إذا برمجياً) |
الخلاصة: الأمر كوحدة بناء للاستراتيجية
أنواع الأوامر ليست مجرد "أزرار في الواجهة". إنها الأوليات الأساسية التي تُبنى منها طبقة التنفيذ في أي نظام تداول. الفرق بين "الاستراتيجية مربحة في الاختبار الخلفي" و"الاستراتيجية مربحة في الإنتاج" غالباً ما يكمن هنا بالذات — في كيفية إرسالك الأوامر إلى المنصة.
بعض النتائج العملية:
- ابدأ بالأوامر القياسية، وتأكد من فهمك للفروق الدقيقة (وقف محدد مقابل وقف سوقي، IOC مقابل FOK). معظم الأخطاء تحدث هنا.
- الأوامر الافتراضية ضرورية لبوتات الشبكة. إذا كنت تقدم أكثر من 50 أمراً — لا ترسلها كلها إلى المنصة.
- المطاردة ضرورية عندما يكون معدل التنفيذ أهم من السعر. لكن دائماً اضبط max_chase_distance — وإلا قد تنجرف بعيداً جداً.
- التنفيذ الزمني متخصص لكنه أداة قوية لمراجحة معدل التمويل والاستراتيجيات المدفوعة بالأحداث.
- طبقة إدارة أوامر مخصصة حتمية لأي نظام تداول خوارزمي جاد. أنواع الأوامر الأصلية للمنصات لا تكفي.
إذا كنت تبني نظام تداول وتريد التعمق أكثر — اطلع على مقالاتنا عن موقع الطابور في دفتر الأوامر، أساليب WebSocket في CCXT، ومراجحة معدل التمويل.
المراجع والمصادر
- CCXT Library — مكتبة موحدة للعمل مع منصات العملات الرقمية، تدعم أكثر من 100 منصة
- Binance API Documentation — توثيق أنواع أوامر Binance
- Bybit API v5 — توثيق Bybit بما في ذلك الأوامر الدُفعية
- 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) — منصة تداول احترافية بأنواع أوامر متقدمة
MarketMaker.cc Team
البحوث والاستراتيجيات الكمية