نكتب روبوتات التداول باستخدام إطار StockSharp الرسومي. الجزء 1



في مدونتنا ، نكتب الكثير عن التقنيات والأدوات المفيدة المتعلقة بتداول الأسهم. أحدها هو منصة StockSharp المجانية ، والتي يمكن استخدامها في التطوير المهني لمحطات التداول والروبوتات التجارية في C #. في هذه المقالة ، سنعرض كيفية استخدام الإطار الرسومي المضمن في S # .API من أجل إنشاء محطة تداول مع القدرة على تشغيل استراتيجيات حسابية.

ما هو المطلوب


  1. Visual Studio 2017 (مجتمع ، نسخة مجانية) ، سنقوم ببرمجته.
  2. الاتصال بالتداول في البورصة ، في الأمثلة الواردة في هذا النص ، يتم استخدام واجهة SMARTcom من ITI Capital .

إنشاء المشروع


قم بإنشاء تطبيق WPF جديد في Visual Studio:



ثم تحتاج إلى إضافة مكتبة S # .API. يمكنك معرفة كيفية القيام بذلك في الوثائق . الخيار الأفضل هو التثبيت باستخدام Nuget.

نظرًا لأن جميع عناصر الرسوم البيانية S # .API تعتمد على DevExpress ، وأن مكتبات DevExpress تأتي مع S # .API ، فسيكون من الغباء عدم استخدامها. دعنا نذهب إلى محرر النوافذ MainWindow.xaml:



استبدال النافذة بـ DXWindow ، سنحتاج إلى ذلك لاستخدام أنظمة ألوان مختلفة:



سوف يقدم لنا Visual Studio نفسه إدراج المكتبات اللازمة.

سنقوم بتقسيم النافذة إلى ثلاثة أجزاء - في الجزء العلوي ، سيكون هناك شريط به أزرار لإعداد التوصيلات والاتصالات ، في الجزء السفلي ستكون هناك نافذة بها سجلات ، وفي الوسط جميع اللوحات الأخرى. أسهل طريقة لكسر نافذة هي مع Devout's LayoutControl.

في الأجزاء الثلاثة الناتجة ، سنضيف العناصر التي نحتاجها.

<dx:DXWindow x:Class="ShellNew.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <dxlc:LayoutControl Padding="0" Name="LayoutControlRoot" Orientation="Vertical"> <dxlc:LayoutGroup HorizontalAlignment="Stretch" Height="25"> <!--  --> </dxlc:LayoutGroup> <dxlc:LayoutGroup HorizontalAlignment="Stretch" > <!--  --> </dxlc:LayoutGroup> <dxlc:LayoutGroup HorizontalAlignment="Stretch" > <!--  --> </dxlc:LayoutGroup> </dxlc:LayoutControl> </dx:DXWindow> 

تكوين اتصال للموصل


أضف زرين ، أحدهما هو زر إعدادات الاتصال ، والثاني هو زر الاتصال. للقيام بذلك ، استخدم زر SimpleButton من DevExpress. ستكون الأزرار موجودة في الجزء العلوي من التطبيق. في كل زر نضع الصور المألوفة من S # .Designer و S # .Data و S # .Terminal .

 <dx:DXWindow x:Class="ShellNew.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol" xmlns:xaml="http://schemas.stocksharp.com/xaml" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <dxlc:LayoutControl Padding="0" Name="LayoutControlRoot" Orientation="Vertical"> <dxlc:LayoutGroup HorizontalAlignment="Stretch" Height="25"> <!--  --> <dxlc:LayoutItem Width="40"> <dx:SimpleButton x:Name="SettingsButton" Click="SettingsButton_Click" > <Image Source="{xaml:ThemedIcons Key=Settings}" Width="16" /> </dx:SimpleButton> </dxlc:LayoutItem> <dxlc:LayoutItem Width="40"> <dx:SimpleButton x:Name="ConnectButton" Click="ConnectButton_Click" > <Image Source="{xaml:ThemedIcons Key=Connect}" Width="16" /> </dx:SimpleButton> </dxlc:LayoutItem> </dxlc:LayoutGroup> <dxlc:LayoutGroup HorizontalAlignment="Stretch" View="Tabs"> <!--  --> </dxlc:LayoutGroup> <dxlc:LayoutGroup HorizontalAlignment="Stretch" > <!--  --> </dxlc:LayoutGroup> </dxlc:LayoutControl> </dx:DXWindow> 

في الزاوية اليمنى العليا من نموذج الشاشة ، سنرى الصورة التالية:



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

 public readonly Connector Connector; private const string _dir = "Data"; private static readonly string _settingsFile = $@"{_dir}\connection.xml"; 

في معالج الأحداث للنقر على زر إعدادات الموصل ، سنفتح نافذة تكوين الموصل ونحفظه في ملف.

 private void SettingsButton_Click(object sender, RoutedEventArgs e) { if (Connector.Configure(this)) { new XmlSerializer<SettingsStorage>().Serialize(Connector.Save(), _settingsFile); } } 

في المُنشئ ، سوف نتحقق مما إذا كان هناك دليل وملف به إعدادات الموصل ، وإذا كان هناك دليل ، فسنقوم بتحميله في الموصل:

 //---------------------------------------------------------------------------------- Directory.CreateDirectory(_dir); Connector = new Connector(); if (File.Exists(_settingsFile)) { Connector.Load(new XmlSerializer<SettingsStorage>().Deserialize(_settingsFile)); } //---------------------------------------------------------------------------------- 

تحتوي معظم كائنات S # .API على أساليب حفظ وتحميل يمكن استخدامها لحفظ هذا الكائن وتحميله من ملف XML.

في معالج الأسلوب بالنقر على زر الاتصال ، نقوم بتوصيل الموصل.

  private void ConnectButton_Click(object sender, RoutedEventArgs e) { Connector.Connect(); } 

الآن يمكنك تشغيل البرنامج والتحقق منه.

وضع سمة الظلام


يفضل العديد من المتداولين السمات الداكنة على تطبيقات التداول. لذلك ، نجعل فورا موضوع البرنامج مظلمة. لتحتاج إلى العثور على ملف App.xaml:



واستبدل التطبيق بالتخطيط: ExtendedBaseApplication فيه ، وسوف يعرضنا Visual Studio نفسه لإدراج المكتبات اللازمة.

 <charting:ExtendedBaseApplication x:Class="ShellNew.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:charting="http://schemas.stocksharp.com/xaml" StartupUri="MainWindow.xaml"> </charting:ExtendedBaseApplication> 

وفي ملف App.xaml.cs تحتاج إلى حذف ": التطبيق".

 namespace ShellNew { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App { } } 

في مُنشئ MainWindow ، اكتب ApplicationThemeHelper.ApplicationThemeName = Theme.VS2017DarkName;

كود كامل في الوقت الحالي:

 public partial class MainWindow { public readonly Connector Connector; private const string _dir = "Data"; private static readonly string _settingsFile = $@"{_dir}\connection.xml"; public MainWindow() { //---------------------------------------------------------------------------------- ApplicationThemeHelper.ApplicationThemeName = Theme.VS2017DarkName; //---------------------------------------------------------------------------------- Directory.CreateDirectory(_dir); Connector = new Connector(); if (File.Exists(_settingsFile)) { Connector.Load(new XmlSerializer<SettingsStorage>().Deserialize(_settingsFile)); } //---------------------------------------------------------------------------------- InitializeComponent(); } private void SettingsButton_Click(object sender, RoutedEventArgs e) { if (Connector.Configure(this)) { new XmlSerializer<SettingsStorage>().Serialize(Connector.Save(), _settingsFile); } } private void ConnectButton_Click(object sender, RoutedEventArgs e) { Connector.Connect(); } } 

تشغيل للتحقق من الموضوع المظلم:



إنشاء شريط الأدوات


أضف مجلدًا حيث سنخزن جميع عناصر التحكم التي أنشأناها ، وسميها XAML. قم بإضافة UserControll الأول الخاص بنا ، وقم بتسميته اسم SecurityGridControl.



نضيف عنصر SecurityPicker واحدًا إليه. سيعرض الأدوات المتاحة. عن طريق القياس مع النافذة الرئيسية ، سنستخدم LayoutControl من DevExpress.

 <UserControl x:Class="ShellNew.XAML.SecurityGridControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:xaml="http://schemas.stocksharp.com/xaml" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <xaml:SecurityPicker x:Name="SecPicker" /> </UserControl> 

دعنا نذهب إلى مصمم الإطار الرئيسي وتغيير الجزء المركزي إلى عرض الإشارات المرجعية. في إحدى الإشارات المرجعية ، سنضع جهاز التحكم الذي أنشأناه بواسطة SecurityPicker:

 <dxlc:LayoutGroup HorizontalAlignment="Stretch" View="Tabs"> <!--  --> <dxlc:LayoutGroup Header="Securities"> <myxaml:SecurityGridControl x:Name="SecurityPanel" /> </dxlc:LayoutGroup> </dxlc:LayoutGroup> 

الآن بعد أن أصبح لدينا شريط الأدوات ، نحتاج إلى إعطائه مصدر بيانات ، في حالتنا هو موصل. يمكنك ببساطة MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
في منشئ MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
.

ولكن يجب ألا تسد MainWindow برمز لا ينطبق عليه. لذلك ، سنقوم بإنشاء متغير ثابت Instance وتعيين MainWindow إليه في مُنشئ MainWindow:

 public static MainWindow Instance; … Instance = this; … 

الآن ، في أي مكان في برنامجنا ، يمكننا الوصول إلى خصائص MainWindow من خلال رمز MainWindow.Instance.XXX.

في مُنشئ SecurityGridControl ، وبهذه الطريقة نحدد الرابط كمصدر للبيانات:

 public SecurityGridControl() { InitializeComponent(); SecPicker.SecurityProvider = MainWindow.Instance.Connector; } 

تشغيل للتحقق:



مضيفا تسجيل


يجب التحكم في البرنامج أو الموصل أو الروبوت. لهذا ، S # .API لديه فئة LogManager خاصة. يستقبل هذا الفصل الرسائل من المصادر ويمررها إلى المستمعين. في حالتنا ، ستكون المصادر هي الموصل ، الاستراتيجيات ، إلخ ، وسيكون المستمع ملفًا ولوحة سجل.

في رمز MainWindow ، نعلن عن كائن LogManager والمكان الذي سيتم تخزينه فيه:

 public readonly LogManager LogManager; private static readonly string _logsDir = $@"{_dir}\Logs\"; 

في مُنشئ MainWindow ، قم بإنشاء LogManager ، واضبط ملف مصدر الإصغاء و الموصل عليه:

 //---------------------------------------------------------------------------------- LogManager = new LogManager(); LogManager.Sources.Add(Connector); LogManager.Listeners.Add(new FileLogListener { SeparateByDates = SeparateByDateModes.SubDirectories, LogDirectory = _logsDir }); //---------------------------------------------------------------------------------- 

عن طريق القياس مع شريط الأدوات ، قم بإنشاء لوحة سجل في مجلد XAML ، وقم بإضافة UserControl آخر. اعطائها اسم MonitorControl. أضف عنصر الشاشة إليه.

 <UserControl x:Class="ShellNew.XAML.MonitorControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:xaml="http://schemas.stocksharp.com/xaml" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <xaml:Monitor x:Name="Monitor" /> </UserControl> 

في مُنشئ MonitorControl ، قم بتعيين LogManager على Monitor كمستمع:

 public MonitorControl() { InitializeComponent(); MainWindow.Instance.LogManager.Listeners.Add(new GuiLogListener(Monitor)); } 

إضافة MonitorControl التي تم إنشاؤها إلى أسفل MainWindow:

 <dxlc:LayoutGroup HorizontalAlignment="Stretch" dxlc:LayoutControl.AllowVerticalSizing="True"> <!--  --> <myxaml:MonitorControl x:Name="MonitorControl" /> </dxlc:LayoutGroup> 

تشغيل للتحقق:



إنشاء لوحة زجاجية


عن طريق القياس مع اللوحات السابقة ، قم بإنشاء لوحة زجاجية ، وقم بإضافة UserControl آخر إلى مجلد XAML. اعطائها اسم MarketDepthControl.

في MainWindow استخدمنا بالفعل LayoutControl ، في هذا التحكم سوف نستخدم LayoutControl أيضًا. نقسم اللوحة إلى جزأين أفقيًا:

  <UserControl x:Class="ShellNew.XAML.MarketDepthControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol" mc:Ignorable="d"> <dxlc:LayoutControl Padding="0" Name="LayoutControlRoot" Orientation="Horizontal"> <dxlc:LayoutGroup> <!--Left--> </dxlc:LayoutGroup> <dxlc:LayoutGroup Orientation="Vertical" dxlc:LayoutControl.AllowHorizontalSizing="True"> <!--Rigth--> </dxlc:LayoutGroup> </dxlc:LayoutControl> </UserControl> 

أضف SecurityPicker إلى الجانب الأيسر - قابلناه عندما أنشأنا شريط الأدوات.

 <dxlc:LayoutGroup> <xaml:SecurityPicker x:Name="SecPicker" SecuritySelected="SecPicker_SecuritySelected" /> </dxlc:LayoutGroup>       .     : <dxlc:LayoutGroup Orientation="Vertical" dxlc:LayoutControl.AllowHorizontalSizing="True"> <dxlc:LayoutItem VerticalAlignment="Stretch"> <xaml:MarketDepthControl x:Name="MarketDepth" MaxHeight="2000" SelectionChanged="MarketDepth_SelectionChanged" /> </dxlc:LayoutItem> </dxlc:LayoutGroup> 

يحتاج MarketDepthControl إلى تعيين بعض القيمة MaxHeight ، وإلا لن يتم تشغيل التطبيق.

تحت الزجاج ، سنضع عناصر مهمة الحافظة والسعر وحجم الطلب:

 <dxlc:LayoutItem Label="Portfolio" Height="20"> <xaml:PortfolioComboBox x:Name="PortfolioComboBox" /> </dxlc:LayoutItem> <dxlc:LayoutItem Label="Price" Height="20"> <dxe:SpinEdit MinValue="0" Name="SpinEditPrice" /> </dxlc:LayoutItem> <dxlc:LayoutItem Label="Volume" Height="20"> <dxe:SpinEdit MinValue="0" Name="SpinEditVolume" /> </dxlc:LayoutItem> 

تجدر الإشارة إلى خاصية تسمية LayoutItem ، فهي تسمح لك بتعيين النص أمام العنصر. بالإضافة إلى عنصر SpinEdit من DevExpress والذي يعد ملائماً لضبط القيم العددية. هذه العناصر تبدو كما يلي:



أدناه سنضع أزرار البيع والشراء:

 <dxlc:LayoutGroup Orientation="Horizontal" Height="20" VerticalAlignment="Stretch"> <dxlc:LayoutItem VerticalAlignment="Stretch"> <dx:SimpleButton Content="Buy" x:Name="BuyButton" Click="BuyButton_Click" /> </dxlc:LayoutItem> <dxlc:LayoutItem VerticalAlignment="Stretch"> <dx:SimpleButton Content="Sell" x:Name="SelltButton" Click="SelltButton_Click" /> </dxlc:LayoutItem> </dxlc:LayoutGroup> 

كود كامل:

 <UserControl x:Class="ShellNew.XAML.MarketDepthControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol" xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" xmlns:xaml="http://schemas.stocksharp.com/xaml" xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" mc:Ignorable="d"> <dxlc:LayoutControl Padding="0" Name="LayoutControlRoot" Orientation="Horizontal"> <dxlc:LayoutGroup> <xaml:SecurityPicker x:Name="SecPicker" SecuritySelected="SecPicker_SecuritySelected" /> </dxlc:LayoutGroup> <dxlc:LayoutGroup Orientation="Vertical" dxlc:LayoutControl.AllowHorizontalSizing="True"> <dxlc:LayoutItem VerticalAlignment="Stretch"> <xaml:MarketDepthControl x:Name="MarketDepth" MaxHeight="2000" SelectionChanged="MarketDepth_SelectionChanged" /> </dxlc:LayoutItem> <dxlc:LayoutItem Label="Portfolio" Height="20"> <xaml:PortfolioComboBox x:Name="PortfolioComboBox" /> </dxlc:LayoutItem> <dxlc:LayoutItem Label="Price" Height="20"> <dxe:SpinEdit MinValue="0" Name="SpinEditPrice" /> </dxlc:LayoutItem> <dxlc:LayoutItem Label="Volume" Height="20"> <dxe:SpinEdit MinValue="0" Name="SpinEditVolume" /> </dxlc:LayoutItem> <dxlc:LayoutGroup Orientation="Horizontal" Height="20" VerticalAlignment="Stretch"> <dxlc:LayoutItem VerticalAlignment="Stretch"> <dx:SimpleButton Content="Buy" x:Name="BuyButton" Click="BuyButton_Click" /> </dxlc:LayoutItem> <dxlc:LayoutItem VerticalAlignment="Stretch"> <dx:SimpleButton Content="Sell" x:Name="SelltButton" Click="SelltButton_Click" /> </dxlc:LayoutItem> </dxlc:LayoutGroup> </dxlc:LayoutGroup> </dxlc:LayoutControl> </UserControl> 

في مُنشئ MarketDepthControl ، قم بتعيين مصدر الأدوات الخاصة بـ SecurityPicker ومصدر الحقائب الخاصة بـ PortfolioComboBox ، وفي حالتنا ، سيكون الرابط:

 public MarketDepthControl() { InitializeComponent(); SecPicker.SecurityProvider = MainWindow.Instance.Connector; PortfolioComboBox.Portfolios = new PortfolioDataSource(MainWindow.Instance.Connector); } 

إنشاء معالج حدث تحديد أداة في SecurityPicker. في ذلك ، نتحقق مما إذا كانت الأداة المستلمة لا تساوي الصفر. إذا كان لا يساوي الصفر ، فنحن نحفظ الأداة المستلمة في متغير محلي ، وسيكون ذلك مفيدًا لنا عند تحديث الزجاج. ثم نقوم بتنظيف وتسجيل الأداة المستلمة في الموصل لاستلام كوب باستخدام أسلوب RegisterMarketDepth. باستخدام أسلوب GetMarketDepth ، نحصل على الزجاج الحالي للأداة من أجل تحديث MarketDepthControl به.

 private Security _selectedSecurity; private void SecPicker_SecuritySelected(Security security) { if (security == null) return; _selectedSecurity = security; MainWindow.Instance.Connector.RegisterMarketDepth(_selectedSecurity); var marketDepth = MainWindow.Instance.Connector.GetMarketDepth(_selectedSecurity); MarketDepth.UpdateDepth(marketDepth); } 

لكي يتم تحديث الزجاج باستمرار في مُنشئ MarketDepthControl ، نحن نشترك في حدث تغيير الزجاج MarketDepthChanged على الموصل. في معالج هذا الحدث ، سوف نتحقق من الأداة التي ينتمي إليها الزجاج المستلم ، وإذا كان ينتمي إلى الأداة المحددة في SecurityPicker ، فإننا نقوم بتحديثها: MarketDepthControl.

 public MarketDepthControl() { InitializeComponent(); SecPicker.SecurityProvider = MainWindow.Instance.Connector; PortfolioComboBox.Portfolios = new PortfolioDataSource(MainWindow.Instance.Connector); MainWindow.Instance.Connector.MarketDepthChanged += Connector_MarketDepthChanged; } private void Connector_MarketDepthChanged(MarketDepth marketDepth) { if (_selectedSecurity == null || marketDepth.Security != _selectedSecurity) return; MarketDepth.UpdateDepth(marketDepth); } 

في الجزء الرئيسي من MainWindow ، أضف لوحة MarketDepthControl التي تم إنشاؤها:

 <dxlc:LayoutGroup HorizontalAlignment="Stretch" View="Tabs"> <!--  --> <dxlc:LayoutGroup Header="Securities"> <myxaml:SecurityGridControl x:Name="SecurityPanel" /> </dxlc:LayoutGroup> <dxlc:LayoutGroup Header="Portfolios"> <myxaml:PortfolioGridControl x:Name="PortfolioGridControl" /> </dxlc:LayoutGroup> <dxlc:LayoutGroup Header="Orders"> <myxaml:OrderGridControl x:Name="OrderGridControl" /> </dxlc:LayoutGroup> <dxlc:LayoutGroup Header="MyTrades"> <myxaml:MyTradeGridControl x:Name="MyTradeGridControl" /> </dxlc:LayoutGroup> <dxlc:LayoutGroup Header="MarketDepth"> <myxaml:MarketDepthControl x:Name="MarketDepthControl" /> </dxlc:LayoutGroup> </dxlc:LayoutGroup> 

في هذه المرحلة ، يمكنك تشغيل البرنامج والتحقق من تشغيل تحديث النظارات.
قم بإنشاء معالج أحداث للنقر فوق أزرار البيع والشراء. في كل معالج نقوم بإنشاء طلب ، نشير فيه إلى الأداة المحددة في SecurityPicker ، والمحفظة المحددة في PortfolioComboBox ، والحجم والسعر من SpinEdit المقابل. تسجيل التطبيق في رابط باستخدام الأسلوب RegisterOrder.

 private void BuyButton_Click(object sender, RoutedEventArgs e) { Order order = new Order() { Security = _selectedSecurity, Portfolio = PortfolioComboBox.SelectedPortfolio, Volume = SpinEditVolume.Value, Price = SpinEditPrice.Value, Direction = StockSharp.Messages.Sides.Buy, }; MainWindow.Instance.Connector.RegisterOrder(order); } private void SelltButton_Click(object sender, RoutedEventArgs e) { Order order = new Order() { Security = _selectedSecurity, Portfolio = PortfolioComboBox.SelectedPortfolio, Volume = SpinEditVolume.Value, Price = SpinEditPrice.Value, Direction = StockSharp.Messages.Sides.Sell, }; MainWindow.Instance.Connector.RegisterOrder(order); } 

كل المعالجات تختلف فقط في اتجاه التطبيق.

دعنا نجعل قيمة SpinEditPrice تتغير حسب سعر الاقتباس المحدد عند اختيار علامات الاقتباس في كوب. للقيام بذلك ، قم بإنشاء معالج حدث SelectionChanged لـ MarketDepthControl. حيث سنقوم بتحديث قيمة SpinEditPrice بسعر الاقتباس المحدد إذا كان السعر المحدد لا يساوي الصفر.

 private void MarketDepth_SelectionChanged(object sender, GridSelectionChangedEventArgs e) { if (MarketDepth.SelectedQuote == null) return; SpinEditPrice.Value = MarketDepth.SelectedQuote.Price; } 

تشغيل للتحقق:



حفظ بيانات السوق


لحفظ المحافظ والأدوات والمنصات ، نحتاج إلى فئة CsvEntityRegistry. من الضروري إعادة موقع تخزين الكيان واستدعاء طريقة التهيئة لتحميلها.

  _csvEntityRegistry = new CsvEntityRegistry(_csvEntityRegistryDir); _csvEntityRegistry.Init(); 

لحفظ الشموع والصفقات ، إلخ. نحن بحاجة إلى StorageRegistry:

  _storageRegistry = new StorageRegistry { DefaultDrive = new LocalMarketDataDrive(_storageRegistryDir), }; 

نحتاج أيضًا إلى سجل SnapshotRegistry لمتاجر اللقطات:

 _snapshotRegistry = new SnapshotRegistry(_snapshotRegistryDir); 

كل هذا نمرر إلى الرابط عندما يتم إنشاؤه:

 Connector = new Connector(_csvEntityRegistry, _storageRegistry, _snapshotRegistry) { IsRestoreSubscriptionOnReconnect = true, StorageAdapter = { DaysLoad = TimeSpan.FromDays(3) }, }; Connector.LookupAll(); 

هنا أشرنا أيضًا إلى أن الموصل سوف يعيد الاتصال عندما يتم قطع الاتصال ، وأيضًا يشير إلى عدد أيام السجل المطلوب تنزيلها. سلسلة رابط. LookupAll () ؛ يطلب البيانات المتاحة:

 //---------------------------------------------------------------------------------- Directory.CreateDirectory(_dir); _csvEntityRegistry = new CsvEntityRegistry(_csvEntityRegistryDir); _csvEntityRegistry.Init(); _storageRegistry = new StorageRegistry { DefaultDrive = new LocalMarketDataDrive(_storageRegistryDir), }; _snapshotRegistry = new SnapshotRegistry(_snapshotRegistryDir); Connector = new Connector(_csvEntityRegistry, _storageRegistry, _snapshotRegistry) { IsRestoreSubscriptionOnReconnect = true, StorageAdapter = { DaysLoad = TimeSpan.FromDays(3) }, }; Connector.LookupAll(); if (File.Exists(_settingsFile)) { Connector.Load(new XmlSerializer<SettingsStorage>().Deserialize(_settingsFile)); } //---------------------------------------------------------------------------------- 

بعد تحميل التطبيق ، والانتقال إلى مجلد البيانات ، سنرى ظهور مجلدات جديدة:



عند إعادة الاتصال ، سيتم بالفعل ملء أشرطة الأدوات والمحافظ.

لقد اقتربنا بسلاسة من نهاية الجزء الأول. في هذه المرحلة ، يسمح لك البرنامج بعرض جميع بيانات السوق المتاحة لنا. سيوضح الجزء التالي الأكثر لذيذًا - ألا وهو التداول في الوضع اليدوي والتلقائي.

أن تستمر ...

المؤلف : إيفان زالوتسكي

Source: https://habr.com/ru/post/ar432812/


All Articles