المشكلة: في الوقت الحالي ، فإن البرنامج الأكثر ملاءمة وكاملة (يشار إليه فيما يلي باسم البرنامج) للتشغيل الآلي التجاري في سوق الأسهم الروسي هو TSLAB الشهير.
على الرغم من المزايا التي لا شك فيها في شكل محرر مرئي مناسب لكتابة نصوص التداول ، والتي تتيح لك كتابة الروبوتات حتى بدون معرفة لغات البرمجة ، هناك عدد من العيوب التي تجعل استخدام هذا البرنامج غير مربح للغاية بالنسبة لي. لا أعتقد ذلك فقط بالنسبة لي ، بالنظر إلى أن متوسط حجم الحساب في موسبيرز كقاعدة لا يتجاوز 500 ألف روبل.
1. التكلفة: رسوم الاشتراك 4500 روبل في الشهر + استئجار خادم افتراضي (1000 روبل في الشهر)
تضع هذه التكلفة الثابتة عبئًا ثقيلًا جدًا على النتيجة المالية لتجريتي. لذلك ، وجود حساب حجم 500 ألف روبل وعلى أمل الحصول على ما لا يقل عن 20 ٪ سنويا منه ، مع التكاليف الحالية تحتاج إلى كسب حوالي 32-35 ٪ من أجل الوصول إلى الربحية المخطط لها.
2. عدم استقرار العمل: على الرغم من أن خوارزمياتي تعمل بشكل رئيسي مع أوامر السوق (نوع الأوامر ، التي تفترض التنفيذ بنسبة 100 ٪) ، فقد تضاعفت مراكزي كثيرًا أو لم تنفذ على الإطلاق.
الهدف: كتابة برنامج لأتمتة التداول لتقليل التكاليف الثابتة من خلال واجهة ملائمة لإنشاء نصوص تداول تتيح لك كتابة روبوتات التداول دون أي معرفة عميقة في البرمجة.
يتم عرض بنية المشروع بالكامل مع التحسينات الحالية والوظائف والتحسينات المخططة في الشكل أدناه.

الرابط الأكثر أهمية في البرنامج هو بلا شك موقع Tradingview (يشار إليه فيما بعد باسم TV). إنه يقدم لنا فقط وظائف ملائمة لكتابة نصوص التداول الخاصة به بسبب لغة Pine_Script المدمجة.
اللغة ، بالمناسبة ، لا تتطلب معرفة محددة وتشبه أساسًا حزمة Easy Language of Metastock ، كما أن توفر المساعدة عبر الإنترنت باللغة الروسية يجعل كتابة التعليمات البرمجية ممتعة قدر الإمكان.
مثال على استراتيجية لاختراق المتوسط المتحرك (حرفيًا في ثلاثة سطور من الكود):
mov_average=sma(close,x) strategy.entry("My Long Entry Id", strategy.long,when=close>mov_average) strategy.entry("My Short Entry Id", strategy.short,when=close<mov_average)
الآن مع وجود واجهة ملائمة لكتابة نصوص التداول ، يبقى إنشاء عملية إرسال التطبيقات من التلفزيون مباشرة إلى نظام التداول (في حالتي ، هذا Quik) ، أو مباشرة إلى خادم الوسيط. المشكلة الوحيدة هي أن التلفزيون ليس لديه واجهة برمجة تطبيقات مفتوحة لتنفيذ هذه الوظيفة.
في محاولة حل هذه المشكلة ، كان أول ما حدث بالنسبة لي هو استخدام مكون إضافي لاختبار WebSelenium ومن خلال البحث عن محددات XPath للعثور على العناصر التي نحتاجها والتي تكون مسؤولة عن إشارات البيع والشراء.
يتم عرض الإشارات نفسها في الجدول ، ويجب ألا تكون هناك أي مشاكل. ولكن للبحث عن الإشارة القصوى ، تطلب الجدول التمرير ، لكن لم أتمكن من العثور على عنصر التمرير (انظر الشكل أدناه).

لذلك ، كان علي أن أبحث عن حل آخر.
بصريا ، يتم عرض إشارات التلفزيون في عنصر قماش. يمكن تغيير لون الإشارة إذا لزم الأمر (على سبيل المثال: البيع الأحمر ، الشراء الأخضر).
الألوان المحددة في التلفزيون وضعناها في تطبيقنا. يتم كتابة التطبيق نفسه في جافا ، ويتم تنفيذ واجهة رسومية باستخدام مكتبة سوينغ
علاوة على ذلك في البرنامج نفسه ، نحتاج إلى تحديد منطقة الرسم (أو فقط المساحة الممسوحة ضوئيًا) ، والتي سنبحث فيها عن ألوان التحكم.
يوضح الشكل أدناه موقع tradeview مع ثلاث أدوات محددة ، يتم تعيين لون إشارة التداول لكل منها. يتم تكرار هذه الألوان في برنامج Parse_Signal الخاص بي.
.
بعد ضبط منطقة المسح الضوئي وإعداد نوع الأداة التي يتم تداولها (بالمناسبة ، تستغرق إعدادات البرنامج 5 دقائق ويتم حفظها في ملف بامتداد .txt). بعد ذلك ، اضغط على زر "بدء" وسيبدأ البرنامج في العمل.
وهي تعمل في اثنين من المواضيع.
موضوع واحد:
بمسح المنطقة المحددة (في هذه الحالة ، قماش).
نقوم بالمسح بشكل كلاسيكي باستخدام وظيفة فئة الروبوت:
BufferedImage buf= robot.createScreenCapture(new Rectangle(selection.x, selection.y, selection.width, selection.height))
بعد ذلك ، يقوم بتقسيم المسح الناتج إلى مجموعة من البكسل:
int[] pixels = copyFromBufferedImage(buf);
يبحث في مجموعة البكسل عن ألوان التحكم في إشارات التداول. البحث من اليسار إلى اليمين. أي إنه لون البكسل أقصى اليمين الملائم للبرنامج:
for(int i=0;i<pixels.length;i++ ) { if (pixels[i] == (buy.getBackground().getRGB() & 0xFFFFFF)) { position = 1;

يسجل معاملة تجارية (في ملف بامتداد .tri) وفقًا للقالب ، اعتمادًا على اللون الموجود. هنا ، في الواقع ، كل شيء بسيط في محطة التداول Quik ، من الممكن قراءة المعاملات تلقائيًا من ملف. يكفي أن نسجلها وفقًا لنمط معين. Quik ، عند ظهور إدخال جديد ، يرسل طلبًا إلى خادم الوسيط. تتم قراءة الملف كل 500 مللي ثانية. يمكن إرسال المعلومات حول إشارات التداول اختياريًا إما إلى البريد أو الهاتف أو إلى نظام التداول (يمكن اختيار ثلاثة معلمات في وقت واحد). 1 موضوع يعمل بتردد 500 مللي ثانية.
if (position==1&&status!=1&&b1==1) { if(dialog.isSend_phone()==true) { new SMS().sendSms(dialog.getPhone(), "TS_1: "+ (String)dialog.cbFirst.getSelectedItem()+" "+price+" "+new Date(), "TEST-SMS", dialog.getLogin(), dialog.getPassword());} if(dialog.isSend_trade()==true){ tr.Order_Buy();} if(dialog.isSend_mail()==true){ test.sendSignal("BUY","TS_1: Buy in signal at price "+ (String)dialog.cbFirst.getSelectedItem()+" "+price+" "+new Date());} status = 1;} ...................... ......................
2 يقوم تدفق البرنامج بتنفيذ طلب سعر الأداة المتداولة عن طريق تحليل صفحة html لموقع Finam . يتم استخدام البرنامج المساعد JSOUP. هنا ، أنا ببساطة تحميل صفحات HTML والبحث عن رمز أداة التداول المطلوبة (على سبيل المثال: Si ، Sber ، إلخ).
public void run() { while (true) { Document doc = null; Document doc_2 = null; try { doc = Jsoup.connect("https://www.finam.ru/quotes/futures/moex/").get(); doc_2 = Jsoup.connect("https://www.finam.ru/profile/mosbirzha-fyuchersy/sbrf").get();} catch (IOException e) { e.printStackTrace(); continue;} StringBuffer buffer = new StringBuffer(doc.text()); StringBuffer buffer_2 = new StringBuffer(doc_2.text()); Map<String, String> map = new HashMap<>() try {map.put(elements[1], buffer.substring(buffer.indexOf("Si "), buffer.indexOf("Si ") + 8).split("Si ")[1]); map.put(elements[2], buffer.substring(buffer.indexOf("RTS "), buffer.indexOf("RTS ") + 10).split("RTS ")[1]); map.put(elements[3], buffer.substring(buffer.indexOf("LKOH "), buffer.indexOf("LKOH ") + 10).split("LKOH ")[1]); map.put(elements[4], buffer.substring(buffer.indexOf("BR "), buffer.indexOf("BR ") +8).split("BR ")[1]); map.put(elements[5], buffer.substring(buffer.indexOf("GAZP "), buffer.indexOf("GAZP ") + 10).split("GAZP ")[1]); map.put(elements[6], buffer.substring(buffer.indexOf("GOLD "), buffer.indexOf("GOLD ") + 11).split("GOLD ")[1]); map.put(elements[7], buffer.substring(buffer.indexOf("MOEX "), buffer.indexOf("MOEX ") + 10).split("MOEX ")[1]); map.put(elements[8], buffer.substring(buffer.indexOf("MIX "), buffer.indexOf("MIX ") + 10).split("MIX ")[1]); map.put(elements[9], "0"); map.put(elements[10], buffer_2.substring(buffer_2.indexOf(" "), buffer_2.indexOf(" ") + 23).split(" ")[2] + buffer_2.substring(buffer_2.indexOf(" "), buffer_2.indexOf(" ") + 23).split(" ")[3]);} catch (Exception e) { System.out.println(e); text.setText(" "); continue;} price = String.valueOf((int) Double.parseDouble(map.get((String)
من الواضح أن هذا رابط ضعيف في البرنامج ، لأن أي تغيير في صفحة html سيؤدي إلى استثناء. لذلك ، من المخطط في المستقبل طلب تبادل المعلومات للطلب مباشرة من خلال Quik ، أو مباشرة من خادم الوسيط.
للقيام بذلك ، يمكنك استخدام مكتبة .dll الجاهزة لـ Quik في C # ، لكن منذ أن كتبت بلغة Java ، سيكون من الأسهل تطبيق نص برمجي في lua (لغة Quik المضمنة) ، والتي ستسجل أسعار البيع والشراء في ملف منفصل ، يقوم البرنامج بضبطه. Parse_Signal وسوف تقرأ بعد ذلك.
تجدر الإشارة إلى أننا في الواقع نحصل على مجموعة ضخمة من TV + Parser + Quik. وعلى الرغم من ثبات هذا الحل ، من المخطط في المستقبل إرسال تطبيقات ليس إلى كويك ، ولكن مباشرة إلى خادم الوسيط (على سبيل المثال: استخدام واجهة أتلنتس من ألورا كخيار ). يتم بالفعل تنفيذ المكتبة مرة أخرى في C # ، لذلك يجب عليك التوصل إلى شيء ما.
سمح لي هذا البرنامج بحل المهام الأولية التي حددتها لنفسي:
وهي في بعض الأحيان لخفض التكاليف الثابتة.
يتم نشر رمز البرنامج في المجال العام.
إذا كان شخص ما مستعدًا لمشاركة أفكاره حول التفاعل مع التلفزيون ، فسوف يسعدني جدًا أن أراها في التعليقات.