تخطَّ إلى المحتوى

إنشاء وسيط مخصص

استخدم وسيطًا مخصصًا لربط AQE بجهة تنفيذ. يتولى مهايئك الاتصال ونقل البيانات ورصد الحساب وتنفيذ الأوامر. وتحتفظ الاستراتيجية بملكية إشاراتها التداولية؛ ويتلقى الوسيط طلبات أوامر غير قابلة للتغيير بدلًا من شجرة الإشارات التداولية الكاملة للاستراتيجية.

يتبع هذا الدليل واجهات AQE 0.2.0. تأكّد من توافق تطبيقك مع السمات في نسخة شيفرة AQE التي تستخدمها استراتيجيتك. ابدأ بطبقة اتصال محاكية أو ببيئة الاختبار المعزولة لجهة التنفيذ، لا بحساب تداول مباشر ممول.

1. تنفيذ الاتصال وإدارة الأوامر

Section titled “1. تنفيذ الاتصال وإدارة الأوامر”

أنشئ نوع Rust ينفّذ aq_engine::core::broker::traits::{Broker, OrderManagementProvider}. يجب أن يكون Send + Sync وأن يمتلك اتصاله وذاكراته المؤقتة وقائمة انتظار أحداثه.

السمةالدوال المطلوبةالمسؤولية
Brokerconnect, disconnect, is_connectedإدارة دورة حياة النقل والتنظيف حتى بعد إلغاء محاولة اتصال.
Brokerget_name, get_account_typeتعريف المهايئ وبيئة الحساب بدقة.
OrderManagementProvidersubmit_order, cancel_orderإرسال BrokerOrderRequest وإلغاء أمر وسيط بمعرّفه.
OrderManagementProviderupdate_take_profit, update_stop_lossتعديل الحماية بالسعر والكمية المقدَّمَين.
OrderManagementProviderclose_position, close_all_positionsطلب إغلاق المراكز وإدارة الحماية المتبقية.
OrderManagementProviderget_orders, get_orderإعادة سجلات Order في AQE بهويات الوسيط وحالاته الحقيقية.
OrderManagementProviderget_positions, get_positionإعادة سجلات Position؛ وتأخذ دالة المركز الواحد رمزًا.
OrderManagementProviderget_accountإعادة Account يتضمن الأرصدة والعملة والقوة الشرائية والحدود.
OrderManagementProviderdrain_trade_events_bounded, has_pending_trade_eventsإتاحة قائمة انتظار أحداث مرتبة وغير حاجبة.
OrderManagementProvidersubscribe_to_trade_stream, unsubscribe_from_trade_streamإدارة دوال استدعاء التداول ودورة حياتها.

تتطلب عدة دوال صراحةً قيمًا مستقبلية تحقق قيد Send، بما فيها connect وتعديلات الأوامر الفردية وget_orders وget_positions وget_account. اتبع توقيعات السمات بدقة؛ يصلح تنفيذ async fn عندما تحقق قيمته المستقبلية قيد Send. لا تحتفظ أبدًا بحارس قفل غير Send عبر .await، ولا تنفّذ عمليات اتصال حاجبة على خيط عمل تابع لبيئة التشغيل.

بالنسبة إلى جهة لا تدعم دفع الأحداث، خطط لكيفية إنتاج الاستطلاع الدوري لأحداث دورة الحياة ودعمه لعقد الاشتراك المطلوب. لا تعلن TradeEventStream إلا إذا كان الوسيط يوفّر الأحداث فعلًا دون استطلاع AQE الدوري.

أعِد تعريف Broker::get_features() بشريحة ثابتة من قيم BrokerFeature. لا تعلن إلا الميزات التي يدعمها المهايئ فعلًا، مثل MarketOrder أو LimitOrder أو PartialClose أو BrokerManagedOco. أعلن AmendLimitPrice وAmendStopPrice كلًا على حدة عندما تدعم الجهة تعديل أسعار الدخول المقابلة في أمر لم يُنفَّذ بعد.

أبلِغ عن القوة الشرائية باتساق: تعني BuyingPowerLeveraged أن القوة الشرائية المعادة تتضمن الرافعة المالية بالفعل. اربط الحدود القصوى المدعومة بـAccount.max_total_orders وAsset.max_total_size؛ أما حجم الأمر الفردي فموضعه Asset.max_order_size. لا تختلق حدودًا للوسيط أو تعلن تقديرات موثوقة تعتمد فقط على حسابات عامة للقيمة الاسمية.

لأي عملية غير مدعومة، أعِد BrokerError::UnsupportedOperation قبل أي تعديل عبر النقل. لا تستبدل نوع أمر آخر بصمت، ولا تُعِد نجاحًا.

2. تحويل الطلبات مع الحفاظ على معرّفاتها

Section titled “2. تحويل الطلبات مع الحفاظ على معرّفاتها”

تتلقى submit_order كائن BrokerOrderRequest. طابق رمزه واتجاهه وكميته ونوع الأمر وفئته وأسعار الحد والوقف ومستويات الحماية والوقف المتحرك مع التمثيل المدعوم لدى الجهة.

احتفظ بـclient_order_id للربط، واستخدمه معرّف أمر العميل لدى الجهة عند دعمه. يظل ثابتًا عبر إعادة المحاولات أو استرداد نية الدخول نفسها؛ وليس دليلًا على أن الجهة أنشأت أمرًا. أعِد معرّف أمر الوسيط الفعلي في Order الناتج.

حافظ على التمييز بين هذه النتائج:

النتيجةسلوك المهايئ
غير مدعوم قبل الإرسالإعادة UnsupportedOperation؛ لم يحدث أي تعديل.
رفض مثبت قبل استدعاء تعديل الوسيطاستخدام SubmissionRejected مع السبب.
انتهاء مهلة النقل بعد الإرسالالحفاظ على عدم اليقين. لا تدّعِ الرفض ولا تُعِد الإرسال دون تحقق.
طلب مقبولإعادة حالة الأمر المرصودة لدى الوسيط؛ فالقبول وحده لا يعني التنفيذ.
تنفيذ أو رفض أو إلغاء أو إغلاق لاحقإصدار بيانات تثبت الحدث في دورة الحياة، مع الأمر والحدث المقابلَين.

الدالة replace_order اختيارية وتعيد افتراضيًا خطأ عدم الدعم. أعِد تعريفها لاستبدال سعر أو كمية دخول معلّق. وهي ليست بديلًا عن update_take_profit أو update_stop_loss.

الدالة amend_entry_prices(order_id, limit_price, stop_price) دالة اختيارية منفصلة لتغيير مكوّن الحد أو سعر تفعيل الوقف لدخول معلّق دون تغيير كميته. يعيد تطبيقها الافتراضي خطأ عدم الدعم. نفّذها قبل إعلان أي من قدرتَي التعديل. لا توجّه تعديل سعر تفعيل الوقف إلى update_stop_loss، التي تتحكم في أوامر الوقف الوقائية.

تعبئة سجلات الحساب والأوامر والمراكز

Section titled “تعبئة سجلات الحساب والأوامر والمراكز”

يجب أن تتضمن صيغ إنشاء هياكل Rust كل حقل في النوع الحالي، بما في ذلك الحقول الاختيارية. تساعد #[serde(default)] على قراءة السجلات القديمة المحفوظة بصيغة تسلسلية؛ لكنها لا تجعل إدراج الحقل اختياريًا عند إنشاء هيكل في Rust.

السجل والحقولمتطلبات المهايئ
Account.account_id, currency, accrued_commission, max_total_ordersأبقِ عمليات الرصد مرتبطة بالحساب الفعلي وعملته. املأ العمولة المستحقة استنادًا إلى أدلة الوسيط، والحد الأقصى للأوامر المعلّقة عند الإبلاغ عنه. القيم الافتراضية القديمة ليست دليلًا على غياب التكاليف أو الحدود.
Position.order_idحقل اختياري جديد لتذكرة التنفيذ أو المركز الدقيقة المرتبطة بالدخول. استخدم Some(...) فقط عندما يستطيع المهايئ إثبات الارتباط؛ واستخدم None للسجلات القديمة أو المجمّعة حسب الرمز ذات المالكين المتعددين. لا تختلق هوية من الرمز أبدًا.
Position.entry_commissionاحتفظ بعمولة دخول المركز مستقلةً عن أرباحه وخسائره التداولية غير المحققة. لا تحتسب الرسم نفسه مرة أخرى عند الإبلاغ عن المحاسبة النهائية.
Order.filled_qty, realized_pnl, commission, swapاستخدم كميات التنفيذ التراكمية للدخول في لقطة الدخول، لكن استخدم فقط الكمية المنفّذة في عملية الخروج المعنية عند الإبلاغ عن حدث خروج. احتفظ بقيم التنفيذ والقيم النقدية التي يبلّغ عنها الوسيط؛ فالقبول ليس تنفيذًا.
Order.position_accounting, OrderLifecycleCloseDetails.position_accountingأدلة PositionCloseAccounting اختيارية لمركز يمكن إثبات ملكيته. أبقِها None عند عدم الدعم أو الغموض؛ فهي ليست مطلوبة لمجرد تنفيذ إرسال الأوامر.
BrokerLifecycleSnapshot.snapshot_complete, captured_atلا تضع علامة الاكتمال إلا بعد حصر كامل بيانات دورة الحياة المعنية، واحتفظ بوقت رصدها. لا يمكن للقطة فارغة وغير مكتملة أن تثبت اختفاء أمر أو مركز.

عند إنشاء Order، احتفظ بمعرّفات الإشارة التداولية والاستراتيجية إلى جانب معرّف أمر الوسيط الحقيقي. أعِد البيانات الوصفية الحالية لـAsset مع الأوامر والمراكز، بما في ذلك قواعد التداول وجدوله ورسومه عند معرفتها. راجع البيانات الوصفية لمصدر البيانات المخصص للاطلاع على حقول الأداة المالية.

البحث عن المراكز بهوية الدخول الدقيقة

Section titled “البحث عن المراكز بهوية الدخول الدقيقة”

قد تعرض get_position(symbol) بيانات مجمّعة. تجري الدالة الأحدث get_position_by_order_id(order_id, symbol) بحثًا دقيقًا غير متزامن وتعيد Result<Option<Position>, BrokerError>. يفحص تنفيذها الافتراضي get_positions() ويرفض هوية الأمر الغامضة أو المفقودة بدلًا من اختيار مركز عشوائي على الرمز نفسه. أعِد تعريفها إذا احتاجت جهة التنفيذ إلى بحث مخصص بالتذكرة.

للمحاكاة الدقيقة في الذاكرة أو لذاكرة مؤقتة مخصصة، يمكن أن تعيد position_snapshot_reader كائن PositionSnapshotReader: دالة استدعاء مملوكة وآمنة للاستخدام عبر الخيوط، تأخذ معرّف الأمر والرمز. أبقِها خالية من عمليات النقل. لا تُعِد Ok(None) إلا عند رصد غياب المركز؛ وأعِد خطأً عندما تكون البيانات غير متاحة أو يتعذر إثبات الهوية المطلوبة. تستخدم قرارات الاستراتيجية المباشرة ذاكرة لقطات AQE المؤقتة ذات الطوابع الزمنية، لا طلب شبكة إضافيًا من دالة استدعاء الإشارة التداولية.

3. تسليم أحداث دورة الحياة بموثوقية

Section titled “3. تسليم أحداث دورة الحياة بموثوقية”

احتفظ بقائمة انتظار من (Order, TradeUpdateEvent) بترتيب المصدر. تزيل drain_trade_events_bounded(max_events) ذلك العدد من الأحداث كحد أقصى وتترك الباقي في القائمة. لا يزيل حد مقداره صفر أي شيء. لا تُفرغ القائمة كاملةً ثم تقتطع المتجه المُعاد.

توضّح هذه الدالة المساعدة كيفية التعامل مع قائمة الانتظار دون فرض مكتبة أقفال معينة. استدعِها أثناء حماية قائمة انتظار المهايئ بحارس قفل قصير العمر:

use aq_engine::core::broker::types::{Order, TradeUpdateEvent};
use std::collections::VecDeque;
pub fn take_trade_events(
queue: &mut VecDeque<(Order, TradeUpdateEvent)>,
max_events: usize,
) -> Vec<(Order, TradeUpdateEvent)> {
let count = max_events.min(queue.len());
queue.drain(..count).collect()
}

تتحقق has_pending_trade_events من جاهزية القائمة دون عمليات إدخال وإخراج للشبكة أو قاعدة البيانات. نفّذ دوال الاستدعاء خارج الأقفال وأبقِها قصيرة. انشر أحداث التنفيذ الجزئي وتحديثات الأوامر الوقائية التابعة بدقة، وعالج رسائل المزوّد المكررة أو الواردة خارج ترتيبها بدلًا من اختلاق حالات نهائية.

تولّد أغلفة الأحداث الافتراضية المحايدة تجاه الوسيط معرّفات أحداث بتوقيت مصدر غير معروف. أعِد تعريف subscribe_to_broker_event_stream ومعالجة أغلفة البيانات المرتبطة بها عندما يستطيع مهايئك توفير هويات وأرقام تسلسلية وطوابع زمنية موثوقة لـBrokerOrderEvent.

4. معالجة الحماية والاسترداد

Section titled “4. معالجة الحماية والاسترداد”

تتولى close_position إدارة أوامر الحماية عند الإغلاق: يلغي الإغلاق الكامل الأوامر الأصلية التابعة المتبقية، ويحافظ الإغلاق الجزئي على الحماية أو يعدّل حجمها بما يناسب التعرّض المتبقي. تؤكد Ok(true) استلام الأمر، لا إتمام الإغلاق. أرسل بيانات تثبت النتيجة النهائية للتداول بصورة منفصلة.

تحسّن نقاط الاستدعاء الاختيارية الإشراف والاسترداد:

نقطة الاستدعاءمتى تنفّذها
get_cached_accountإعادة أحدث لقطة حساب دون إدخال وإخراج عبر النقل.
get_cached_positionsتوفير مراكز دون نقل للتنفيذ الحتمي في الذاكرة، لا كبديل للتحديثات المباشرة ذات الطوابع الزمنية.
get_cached_lifecycle_snapshotتوفير عرض كامل وموثوق لدورة الحياة دون إدخال وإخراج؛ وإعادة None حتى يتوفر.
estimate_order_marginالحصول على تقدير موثوق للطلب الدقيق دون وضعه.
reconcile_submissionالبحث عن الحساب وأمر العميل المحددَين دون إعادة إرساله.
reconcile_order_lifecycleحسم معرّفات الأوامر باستخدام سجل الأوامر وهوية المركز بعد إعادة التشغيل.
lifecycle_reconcilerتوفير Arc<dyn OrderLifecycleReconciler> مملوك للاسترداد بعد إعادة التشغيل.
get_position_by_order_id, position_snapshot_readerتحديد تذكرة الدخول الدقيقة، مع الفصل بين التحديث غير المتزامن والبحث الخالي من عمليات النقل.
pending_cancellation_recovery, retry_cancellationدعم الاسترداد القائم على الأدلة لإلغاء غير محسوم، عبر عامل الأوامر ذي الحالة الدائمة.
execution_fill_history_readerتوفير سجل تنفيذ محدود وللقراءة فقط لحساب وأمر دخول ورمز محددة بدقة.
position_valuation_readerتوفير تقييمات بعملة الحساب وللقراءة فقط للمراكز الفعلية المحددة بدقة، لا تقدير شامل للرمز.
account_cash_flow_readerتوفير سجلات تمويل الحساب وتسوياته للقراءة فقط، مع هوية المصدر والتسلسل ونطاق التغطية.
configure_live_session, configure_asset_metadataقبول سياق الجلسة وقواعد الأصول عندما يحتاجهما المهايئ.

تعيد آلية التحقق الافتراضية من نتيجة الإرسال Unsupported. وتستخدم آلية التحقق الافتراضية من دورة الحياة get_orders()، وتُرجع Unknown للمعرّفات التي لم تجدها؛ ولا يمكنها إثبات إغلاق المركز الناتج عن أمر منفّذ. لا تفسّر أبدًا غياب أمر أو وجود لقطة غير مكتملة أو انتهاء مهلة على أنه دليل على الإلغاء أو الإغلاق.

استرداد الإلغاءات دون إعادة إرسال الأوامر

Section titled “استرداد الإلغاءات دون إعادة إرسال الأوامر”

توفّر pending_cancellation_recovery(account, order) دليلًا للقراءة فقط على أن الإلغاء غير المحسوم لا يزال يستهدف أمرًا معلّقًا. تعيد افتراضيًا None، وهو ليس دليلًا على حالة نهائية. لا يجوز استدعاء retry_cancellation إلا من عامل الأوامر ذي الحالة الدائمة، وبعد تسجيل محاولة استرداد. يجب ألا ترسل نقطة الاستدعاء هذه أمرًا أو تغلقه أو تستبدله؛ بل يجب أن تحصل على دليل موثوق على الإلغاء، وأن تمرّره عبر آلية اختزال أحداث الوسيط المعتادة. تنفيذها الافتراضي غير مدعوم. لا تضف مؤقّتًا مستقلًا لإعادة المحاولة يتجاوز هذه العملية.

إبقاء التحليلات اختيارية وللقراءة فقط

Section titled “إبقاء التحليلات اختيارية وللقراءة فقط”

تعيد نقاط استدعاء قراءة السجل والتقييم والتدفقات النقدية None افتراضيًا. يمكن لمهايئ التنفيذ الاحتفاظ بهذه القيم الافتراضية عندما يتعذر عليه توفير الأدلة. يجب أن تظل التحليلات غير المدعومة غير متاحة، لا أن تُستبدل بسجل فارغ مختلق أو محفظة بلا مراكز مفتوحة أو تدفق نقدي صفري.

  • تعيد ExecutionFillHistoryReader::read(account_id, entry_order_id, symbol) كائن ExecutionFillHistory لمركز يمكن إثبات ارتباطه بأمر دخول واحد. احتفظ بمعرّفات عمليات التنفيذ وتوقيتها لدى المصدر؛ ويمكن أن تضيف position_snapshot تحققًا من الكمية مستندًا إلى رصد مستقل. لا يُعدّ السجل المفقود أو المجمّع بالمقاصة دليلًا على عدم وجود عمليات تنفيذ.
  • تعيد PositionValuationReader::read_positions(account_id, symbol, position_ids) كائن PositionValuations لدفعة محدودة من المراكز المحددة بدقة. احتفظ بعملة الحساب وas_of_us وتوقيت عرض السعر والأرباح والخسائر التداولية وعوائد الاحتفاظ وتكاليفه، وبأساس صريح للقيمة الاسمية أو سبب عدم توفره. تمثل NotOpen رصدًا لغياب المركز، لا تنفيذ إغلاق أو إذنًا بإغلاق إشارة تداولية.
  • تعيد AccountCashFlowReader::read(account_id, source_id, after_sequence) كائن AccountCashFlowPage يتضمن هوية المصدر والعملة والتغطية الزمنية ومؤشر التسلسل والسجلات. سجّل التمويل أو التسويات الفعلية؛ ولا تستنتج إيداعات أو سحوبات من تغيّرات حقوق ملكية الحساب أو عمليات التنفيذ أو حالة الإشارة التداولية.

تعيد الدوال الثلاث نتيجة اختيارية داخل Result. تختلف القراءة غير المتاحة والخطأ عن رصد كامل وموثوق لا يحتوي على سجلات مطابقة. ويجب ألا تضع هذه الدوال أوامر أبدًا أو تجري مطابقة لدورة الحياة كأثر جانبي لقراءة التحليلات.

5. الجمع بين التنفيذ والبيانات

Section titled “5. الجمع بين التنفيذ والبيانات”

يقبل UnifiedBroker نوع التنفيذ الخاص بك مباشرةً. تعمل هذه الدالة المساعدة مع أي وسيط ومصدر بيانات متوافقَين؛ ويجب أن يكون كلا المهايئَين قد نفّذ سماته الخاصة بالفعل:

use aq_engine::core::broker::{
traits::{Broker, DataFeed, DataProvider, OrderManagementProvider},
UnifiedBroker,
};
pub fn live_with<E, D>(execution: E, datafeed: D) -> UnifiedBroker<E, D>
where
E: Broker + OrderManagementProvider,
D: DataFeed + DataProvider,
{
UnifiedBroker::new(execution, datafeed)
}

استخدم PaperBroker مع UnifiedBroker::new_backtest للمحاكي التاريخي المدمج. لا يؤدي تنفيذ سمات الوسيط المباشر وحدها إلى تحويل جهة تنفيذ بعيدة إلى ذلك المحاكي. دعم أداة اختيار الاتصالات في AQS تكامل مستقل لسطح المكتب، وليس نتيجة تلقائية لتنفيذ السمات.

6. التحقق قبل الاستخدام المباشر

Section titled “6. التحقق قبل الاستخدام المباشر”
  1. اختبر فشل الاتصال والإلغاء وإعادة الاتصال والإيقاف الكامل.
  2. اختبر كل نوع أمر معلَن وقاعدة دقة وحد للسعة.
  3. تحقّق من التنفيذ الجزئي والإلغاء وتحديثات الحماية والإغلاق الجزئي وإلغاء الحماية المتبقية عند الإغلاق الكامل.
  4. اختبر سحب الأحداث المحدود بحدود صفر وواحد وعدة أحداث؛ وتأكّد من الحفاظ على الترتيب والأحداث المتبقية.
  5. حاكِ انتهاء مهلة إرسال بعد قبول الجهة. تأكّد من أن الاسترداد لا يكرّر الأمر.
  6. أعِد التشغيل مع أوامر معلّقة ومراكز مفتوحة؛ وتحقّق من استمرار التمييز بين النتائج غير المعروفة والنتائج المؤكدة.
  7. قارن عمليات رصد الحساب والأوامر والمراكز بسجلات بيئة الاختبار المعزولة للجهة قبل التفكير في الاستخدام المباشر.
  8. أبقِ عمليتَي دخول على الرمز نفسه منفصلتين. اختبر البحث بالتذكرة الدقيقة والهوية غير المعروفة واللقطات غير المكتملة، بدلًا من اختيار أول مركز يطابق الرمز.
  9. حاكِ إلغاءً غير محسوم يمتد عبر إعادة تشغيل، وتحقّق من أن مسار الاسترداد ذي الحالة الدائمة وحده يستطيع إعادة محاولة الإلغاء.
  10. اختبر دوال القراءة الاختيارية ببيانات غير مدعومة وغير مكتملة ومتقادمة وتابعة لحساب آخر. تأكّد من أن قراءات التحليلات لا تستطيع إرسال أوامر أو اختلاق أدلة محاسبية.

في نسخة AQE المحلية، ابدأ بما يلي:

  • src/core/broker/mod.rs: سمات التنفيذ والقيم الافتراضية والتركيب.
  • src/core/broker/commands.rs: BrokerOrderRequest وSubmissionResolution.
  • src/core/broker/types/mod.rs: أنواع الحساب والأمر والمركز ودورة الحياة والأخطاء.
  • src/core/broker/features.rs: علامات القدرات الأصلية.
  • src/core/broker/fill_history.rs وposition_valuation.rs وaccount_cash_flow.rs: عقود التحليلات الاختيارية المخصّصة للقراءة فقط.
  • live-sync-protocol/src/position_accounting.rs وposition_valuation.rs: الأدلة المحاسبية والتحقق من صحة التقييم.
  • src/core/broker/mt5_broker.rs وsrc/core/broker/paper_broker.rs: التطبيقان المباشر والمحاكى.

التالي: إنشاء مصدر بيانات مخصص أو التشغيل المباشر.