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



نواصل الحديث عن إنشاء روبوتات تجارية باستخدام منصة StockSharp . تناولت المادة الأولى إنشاء المشروع ورسم العناصر الرئيسية للنظام التجاري. في المادة النهائية للدورة ، سنقوم بتنفيذ استراتيجية التداول مباشرة.

إنشاء لوحة محفظة


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

<UserControl x:Class="ShellNew.XAML.PortfolioGridControl" 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:PortfolioGrid x:Name="PortfolioGrid" /> </UserControl> 

في مُنشئ PortfolioGridControl ، نحتاج إلى الاشتراك في أحداث ظهور محفظة جديدة وحدث ظهور وظيفة جديدة في الموصل.

 public PortfolioGridControl() { InitializeComponent(); MainWindow.Instance.Connector.NewPortfolio += PortfolioGrid.Portfolios.Add; MainWindow.Instance.Connector.NewPosition += PortfolioGrid.Positions.Add; } 

وبالتالي ، عند إنشاء محفظة جديدة ، ستظهر في لوحة المحفظة ، وعندما يظهر مركز جديد في لوحة المحفظة ، سيتم تحديثه.

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

 <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> 

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



لدينا علامة تبويب مع المحافظ.

إنشاء لوحة أوامر


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

 <UserControl x:Class="ShellNew.XAML.OrderGridControl" 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:OrderGrid x:Name="OrderGrid" /> </UserControl> 

يحتوي OrderGrid على حدث تسجيل OrderRegistering وحدث إعادة التسجيل OrderReRegistering وحدث إلغاء OrderCanceling.

لنقم بإنشاء معالجاتهم:

 <UserControl x:Class="ShellNew.XAML.OrderGridControl" 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:OrderGrid x:Name="OrderGrid" OrderRegistering="OrderGrid_OnOrderRegistering" OrderReRegistering="OrderGrid_OnOrderReRegistering" OrderCanceling="OrderGrid_OnOrderCanceling" /> </UserControl> 

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

ثم ندعو OrderWindow مع أسلوب ShowModal. إذا تم الضغط على الزر "موافق" في هذه النافذة ، فعندئذٍ من خلال الموصل نقوم بالتسجيل باستخدام طريقة RegisterOrder:

 private void OrderGrid_OnOrderRegistering() { var newOrder = new OrderWindow { Title = "Order registering", Order = new Order(), SecurityProvider = MainWindow.Instance.Connector, MarketDataProvider = MainWindow.Instance.Connector, Portfolios = new PortfolioDataSource(MainWindow.Instance.Connector), }; if (newOrder.ShowModal(this)) MainWindow.Instance.Connector.RegisterOrder(newOrder.Order); } 

في معالج حدث إعادة التسجيل ، نفعل كل شيء بنفس الطريقة. في هذه الحالة فقط ، يأتي كائن Order إلى الحدث - وهذا أمر يحتاج إلى إعادة التسجيل. لذلك ، في OrderWindow ، نحدد Order = order.ReRegisterClone(newVolume: order.Balance) لملء حقول نافذة OrderWindow.

ثم ندعو OrderWindow مع أسلوب ShowModal. إذا تم النقر فوق الزر "موافق" في هذه النافذة ، فسنقوم بإعادة تسجيل التطبيق من خلال الموصل باستخدام طريقة ReRegisterClone. ننقل إليه التطبيق القديم ، الذي يجب إلغاؤه ، والجديد ، والذي يجب تعيينه.

 private void OrderGrid_OnOrderReRegistering(Order order) { var window = new OrderWindow { Title = "Order re-registering", SecurityProvider = MainWindow.Instance.Connector, MarketDataProvider = MainWindow.Instance.Connector, Portfolios = new PortfolioDataSource(MainWindow.Instance.Connector), Order = order.ReRegisterClone(newVolume: order.Balance) }; if (window.ShowModal(this)) MainWindow.Instance.Connector.ReRegisterOrder(order, window.Order); } 

في معالج أحداث إلغاء الطلب ، ما عليك سوى استدعاء أسلوب CancelOrder وتمرير الطلب إليه ، والذي يجب إلغاؤه:

 private void OrderGrid_OnOrderCanceling(Order order) { MainWindow.Instance.Connector.CancelOrder(order); } 

لكي يتم عرض الطلبات في OrderGrid ، تحتاج إلى الاشتراك في أحداث ظهور طلب جديد وحدث خطأ التسجيل في مُنشئ OrderGridControl ، ثم نقل هذه الأحداث إلى OrderGrid:

 public OrderGridControl() { InitializeComponent(); MainWindow.Instance.Connector.NewOrder += OrderGrid.Orders.Add; MainWindow.Instance.Connector.OrderRegisterFailed += OrderGrid.AddRegistrationFail; } 

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

 <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> 

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



إنشاء لوحة المعاملات الخاصة بك


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

 <UserControl x:Class="ShellNew.XAML.MyTradeGridControl" 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:MyTradeGrid x:Name="MyTradeGrid" /> </UserControl> 

في مُنشئ MyTradeGridControl ، نحتاج إلى الاشتراك في أحداث ظهور معاملة جديدة ونقلها إلى MyTradeGrid:

 public MyTradeGridControl() { InitializeComponent(); MainWindow.Instance.Connector.NewMyTrade += MyTradeGrid.Trades.Add; } 

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

 <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> 

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



إنشاء لوحة مع استراتيجية


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

 <dxlc:LayoutGroup Orientation="Vertical"> <dxlc:LayoutGroup View="Tabs" Name="StatistisAndChartLayoutGroup"> <dxlc:LayoutGroup Header="Chart"> <xaml:Chart x:Name="Chart" /> </dxlc:LayoutGroup> <dxlc:LayoutGroup Header="Statistic"> <dxlc:LayoutItem VerticalAlignment="Stretch" dxlc:LayoutControl.AllowHorizontalSizing="True" > <xaml:StatisticParameterGrid x:Name="StatisticParameterGrid" MaxHeight="2000"/> </dxlc:LayoutItem> <dxlc:LayoutItem VerticalAlignment="Stretch" > <xaml:EquityCurveChart x:Name="EquityCurveChart" /> </dxlc:LayoutItem> </dxlc:LayoutGroup> </dxlc:LayoutGroup> </dxlc:LayoutGroup> 

هنا ، يتم استخدام StatisticParameterGrid لعرض إحصائيات الإستراتيجية ، ويستخدم EquityCurveChart لعرض مخطط الربح والخسارة. يحتاج StatisticParameterGrid إلى تعيين بعض القيمة MaxHeight ، وإلا لن يتم تشغيل التطبيق.

سيقوم الجانب الأيمن بتكوين خصائص الاستراتيجية في PropertyGridEx. سيتم وضع أزرار بدء وإيقاف الاستراتيجية:

 <dxlc:LayoutGroup View="Group" dxlc:LayoutControl.AllowHorizontalSizing="True" dxlc:DockLayoutControl.Dock="Right" Orientation="Vertical"> <dxlc:LayoutItem VerticalAlignment="Stretch"> <xaml:PropertyGridEx x:Name="PropertyGridEx" /> </dxlc:LayoutItem> <dxlc:LayoutItem VerticalAlignment="Stretch" Height="20"> <dx:SimpleButton x:Name="StartStrategyButton" Content="Start strategy" ToolTip="Start strategy" Click="StartStrategyButton_Click" /> </dxlc:LayoutItem> <dxlc:LayoutItem VerticalAlignment="Stretch" Height="20"> <dx:SimpleButton x:Name="StopStrategyButton" Content="Stop strategy" ToolTip="Stop strategy" Click="StopStrategyButton_Click" /> </dxlc:LayoutItem> </dxlc:LayoutGroup> 

كود كامل:

 <UserControl x:Class="ShellNew.XAML.StrategyControl" 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:xaml="http://schemas.stocksharp.com/xaml" xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" mc:Ignorable="d"> <dxlc:LayoutControl> <dxlc:LayoutGroup Orientation="Vertical"> <dxlc:LayoutGroup View="Tabs" Name="StatistisAndChartLayoutGroup"> <dxlc:LayoutGroup Header="Chart"> <xaml:Chart x:Name="Chart" /> </dxlc:LayoutGroup> <dxlc:LayoutGroup Header="Statistic"> <dxlc:LayoutItem VerticalAlignment="Stretch" dxlc:LayoutControl.AllowHorizontalSizing="True" > <xaml:StatisticParameterGrid x:Name="StatisticParameterGrid" MaxHeight="2000"/> </dxlc:LayoutItem> <dxlc:LayoutItem VerticalAlignment="Stretch" > <xaml:EquityCurveChart x:Name="EquityCurveChart" /> </dxlc:LayoutItem> </dxlc:LayoutGroup> </dxlc:LayoutGroup> </dxlc:LayoutGroup> <dxlc:LayoutGroup View="Group" dxlc:LayoutControl.AllowHorizontalSizing="True" dxlc:DockLayoutControl.Dock="Right" Orientation="Vertical"> <dxlc:LayoutItem VerticalAlignment="Stretch"> <xaml:PropertyGridEx x:Name="PropertyGridEx" /> </dxlc:LayoutItem> <dxlc:LayoutItem VerticalAlignment="Stretch" Height="20"> <dx:SimpleButton x:Name="StartStrategyButton" Content="Start strategy" ToolTip="Start strategy" Click="StartStrategyButton_Click" /> </dxlc:LayoutItem> <dxlc:LayoutItem VerticalAlignment="Stretch" Height="20"> <dx:SimpleButton x:Name="StopStrategyButton" Content="Stop strategy" ToolTip="Stop strategy" Click="StopStrategyButton_Click" /> </dxlc:LayoutItem> </dxlc:LayoutGroup> </dxlc:LayoutControl> </UserControl> 

في مُنشئ StrategyControl ، عيّن الرابط كمصدر بيانات لـ PropertyGridEx ، وفي كل عنصر تحكم تقريبًا ، قمنا بتنفيذ إجراءات مماثلة:

 public StrategyControl() { InitializeComponent(); PropertyGridEx.SecurityProvider = MainWindow.Instance.Connector; PropertyGridEx.Portfolios = new PortfolioDataSource(MainWindow.Instance.Connector); } 

نحن بحاجة إلى نقل الاستراتيجية بطريقة أو بأخرى إلى سيطرتنا. للقيام بذلك ، قم بإنشاء طريقة BindStraregy في StrategyControl ، والتي ستأخذ الإستراتيجية ، واحفظ الارتباط بها في متغير محلي ، وقم أيضًا بتعيين الإستراتيجية في PropertyGridEx و StatisticParameterGrid.

باستخدام طريقة SetChart ، نقوم بنقل مخطط الشموع إلى الإستراتيجية ؛ بعد ذلك ، يمكنك الحصول على إستراتيجية الرسم البياني باستخدام طريقة GetChart. نحن أيضا تعيين رابط للاستراتيجية.

 private Strategy _strategy; public void BindStraregy(Strategy strategy) { _strategy = strategy; PropertyGridEx.SelectedObject = strategy; StatisticParameterGrid.Parameters. AddRange(_strategy.StatisticManager.Parameters); _strategy.SetChart(Chart); _strategy.Connector = MainWindow.Instance.Connector; } 

عند العمل وفقًا لجدول الأرباح والخسائر ، تجدر الإشارة إلى أن الاستراتيجية ستبدأ وتتوقف ، وربما عدة مرات ، ويجب أن يتم مسح القصيدة مع كل إطلاق للاستراتيجية. لهذا الغرض ، سنقوم بإنشاء طريقة ResetEquityCurveChart التي سنقوم أولاً بمسح EquityCurveChart بها. بعد ذلك نحتاج إلى إنشاء عناصر رسومية لـ EquityCurveChart ، يمكنهم تحديد اسم ولون ونوع الخط.

بعد ذلك ، نحن نشترك في حدث تغيير PnL الخاص بالاستراتيجية وفي رسم هذا الحدث ، نرسم قيمة جديدة على مخطط الربح / الخسارة EquityCurveChart:

 private void ResetEquityCurveChart() { EquityCurveChart.Clear(); var pnl = EquityCurveChart. CreateCurve("PNL", Colors.Green, ChartIndicatorDrawStyles.Area); var unrealizedPnL = EquityCurveChart. CreateCurve("unrealizedPnL", Colors.Black, ChartIndicatorDrawStyles.Line); var commissionCurve = EquityCurveChart .CreateCurve("commissionCurve", Colors.Red, ChartIndicatorDrawStyles.Line); _strategy.PnLChanged += () => { var data = new ChartDrawData(); data.Group(_strategy.CurrentTime) .Add(pnl, _strategy.PnL) .Add(unrealizedPnL, _strategy.PnLManager.UnrealizedPnL ?? 0) .Add(commissionCurve, _strategy.Commission ?? 0); EquityCurveChart.Draw(data); }; } 

في معالج الأحداث للنقر فوق الزر "ابدأ" ، سوف نسمي هذه الطريقة. وسوف نقوم أيضًا بإعادة ضبط حالة الاستراتيجية وتشغيلها:

 private void StartStrategyButton_Click(object sender, RoutedEventArgs e) { ResetEquityCurveChart(); _strategy.Reset(); _strategy.Start(); } 

في معالج الأحداث للنقر فوق الزر "إيقاف" ، سنوقف الاستراتيجية.
الفراغ الخاص StopStrategyButton_Click (مرسل الكائن ، RoutedEventArgs e):

 { _strategy.Stop(); } 

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

 <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 Header="SimpleStrategyControl"> <myxaml:StrategyControl x:Name="SimpleStrategyControl" /> </dxlc:LayoutGroup> </dxlc:LayoutGroup> 

خلق استراتيجية


على سبيل المثال ، فكر في إنشاء استراتيجية بسيطة للشمعدان. ستشتري إذا كانت الشمعة تنمو (خضراء) وتبيع إذا كانت الشمعة تتناقص (حمراء).

لنقم بإنشاء مجلد آخر في المشروع - سنقوم بتخزين جميع استراتيجياتنا فيه. في هذا المجلد ، قم بإنشاء فئة جديدة ، أطلق عليها اسم SimpleStrategy. يجب أن ترث جميع استراتيجيات S # من الفئة الأساسية لاستراتيجية الاستراتيجية.

 public class SimpleStrategy : Strategy {} 

نظرًا لأن استراتيجيتنا تستخدم الشموع ، فإننا سننشئ CandleSeries للملكية العامة وفي مُنشئ استراتيجيتنا سنقوم بتعيينها على القيمة الافتراضية.

 public class SimpleStrategy : Strategy { public CandleSeries Series { get; set; } public SimpleStrategy() { Series = new CandleSeries(typeof(TimeFrameCandle), new Security(), TimeSpan.FromSeconds(15)) { BuildCandlesMode = MarketDataBuildModes.Build }; } } 

أشرنا هنا إلى أن الشموع في CandleSeries ستكون TimeFrameCandle ، مع فاصل زمني قدره 15 ثانية (TimeSpan.FromSeconds (15)). بالنسبة إلى CandleSeries ، يمكنك تحديد وضع إنشاء الشموع BuildCandlesMode. أشرنا إلى أنه سيتم بناء الشموع (MarketDataBuildModes.Build). بشكل افتراضي ، سيتم إنشاؤها من علامات التجزئة ، ولكن يمكنك تحديد أنواع البيانات الأخرى.

نظرًا لأننا جعلنا CandleSeries ملكية عامة ، يمكن تخصيص CandleSeries أيضًا من PropertyGridEx الموضح في الفقرة السابقة. جميع الاستراتيجيات لها طرق يمكن تجاوزها ، نحتاج إلى تجاوز طريقة OnStarted. يتم استدعاؤه قبل بدء الإستراتيجية ويسمح لك بضبطها مسبقًا على حالة البدء.

 protected override void OnStarted() { _connector = (Connector)Connector; Series.Security = Security; _connector .WhenCandlesFinished(Series) .Do(ProcessCandle) .Apply(this); _connector.SubscribeCandles(Series); base.OnStarted(); } 

هنا ، من أجل CandleSeries ، نقوم بتعريف الأداة المحددة في PropertyGridEx. ثم قم بإنشاء قاعدة لمعالجة الشمعة النهائية. في القاعدة ، حدد الطريقة التي ستقوم بمعالجة كل شمعة منتهية - في حالتنا ، هذه هي الطريقة ProcessCandle. سيتم وصفها لاحقا. بعد تعيين كل شيء ، نحن نشترك في ظهور الشموع على CandleSeries في الموصل من خلال طريقة SubscCandles. في حالتنا ، تحتوي طريقة ProcessCandle على المنطق الرئيسي للاستراتيجية:

 private void ProcessCandle(Candle candle) { if (!IsRealTime(candle)) return; if (candle.OpenPrice < candle.ClosePrice && Position <= 0) { RegisterOrder(this.BuyAtMarket(Volume + Math.Abs(Position))); } else if (candle.OpenPrice > candle.ClosePrice && Position >= 0) { RegisterOrder(this.SellAtMarket(Volume + Math.Abs(Position))); } } 

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

 private bool IsRealTime(Candle candle) { return (Connector.CurrentTime - candle.CloseTime).TotalSeconds < 10; } 

بعد ذلك ، ننظر إلى نوع الشمعة ، وما هو الموقف الحالي للاستراتيجية. إذا كانت الشمعة تنمو ، فمع وضع يساوي 0 ، فسوف نفتح الصفقة بأمر من السوق لوحدة التخزين التي وضعناها في PropertyGridEx. إذا كانت الشمعة تنمو وكان الموضع أقل من 0 ، فإننا "نعكس" الموضع:

 if (candle.OpenPrice < candle.ClosePrice && Position <= 0) { RegisterOrder(this.BuyAtMarket(Volume + Math.Abs(Position))); } 


نفعل العكس لشمعة ضعيفة:

 else if (candle.OpenPrice > candle.ClosePrice && Position >= 0) { RegisterOrder(this.SellAtMarket(Volume + Math.Abs(Position))); } 

في الوقت الحالي ، استراتيجيتنا جاهزة للعمل. يجب أن يتم تمريره إلى SimpleStrategyControl ، والذي أنشأناه في الفقرة السابقة باستخدام طريقة BindStraregy. نقوم بذلك في مُنشئ MainWindow فور تهيئة مكونات MainWindow.

 SimpleStrategyControl.BindStraregy(new SimpleStrategy()); 


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





تعمل الإستراتيجية والصفقات ، لكن حتى الآن لا توجد شموع وصفقات على الرسم البياني.

إضافة الشموع وصفقات إلى المخطط من الاستراتيجية


في القسم الخاص بلوحة الإستراتيجية باستخدام طريقة SetChart ، قمنا بخيانة مخطط الشموع في الإستراتيجية. في طريقة OnStarted للاستراتيجية ، نتحقق مما إذا كان المخطط قد تم تعيينه للإستراتيجية وإذا تم تعيينه ، فإننا نقوم بعد ذلك بتهيئة المخطط ، والاشتراك في أحداث ظهور معاملة جديدة خاصة وتغيير شمعة.

 protected override void OnStarted() { _connector = (Connector)Connector; if (this.GetChart() is Chart chart) { InitChart(chart); NewMyTrade += DrawMyTrade; _connector.CandleSeriesProcessing += CandleSeriesProcessing; } Series.Security = Security; _connector .WhenCandlesFinished(Series) .Do(ProcessCandle) .Apply(this); _connector.SubscribeCandles(Series); base.OnStarted(); } 

طريقة تهيئة مخطط InitChart:

 private ChartCandleElement _chartCandleElement; private ChartTradeElement _tradesElem; private Chart _chart; private void InitChart(Chart chart) { _chart = chart; _chart.GuiSync(() => { _chart.ClearAreas(); var candlesArea = new ChartArea(); _chart.AddArea(candlesArea); _chartCandleElement = new ChartCandleElement(); _chart.AddElement(candlesArea, _chartCandleElement); _tradesElem = new ChartTradeElement { FullTitle = "Trade" }; _chart.AddElement(candlesArea, _tradesElem); }); } 

هنا نحفظ الرابط إلى الرسم البياني في متغير محلي. نحن مسح الجدول الزمني. نحن أيضا إنشاء ونقل إلى عناصر المخطط الرسم البياني للشموع والصفقات. Construction _chart.GuiSync (() => {...})؛ اللازمة من أجل تهيئة الجدول في الموضوع الرئيسي.

CandleSeries مخطط الرسم البياني لرسم الشموع على الرسم البياني:

 private void CandleSeriesProcessing(CandleSeries candleSeries, Candle candle) { var data = new ChartDrawData(); data.Group(candle.OpenTime) .Add(_chartCandleElement, candle); _chart.Draw(data); } 

هنا نحصل على شمعة من الحدث CandleSeriesProcessing الموصل ، إنشاء ChartDrawData لعرضه على المخطط. نشير إلى بيانات time.Group (candle.OpenTime) ، ونشير إلى أنه يجب إضافة الشمعة إلى عنصر الشموع في المخطط .Add (_chartCandleElement، candle)؛. ونشير إلى أن الرسومات تحتاج إلى رسم بيانات جديدة.

نقوم بتنفيذ إجراءات مماثلة للمعاملات:

 public void DrawMyTrade(MyTrade myTrade) { var data = new ChartDrawData(); data.Group(myTrade.Trade.Time) .Add(_tradesElem, myTrade); _chart.Draw(data); } 

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



استنتاج موجز


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

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

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


All Articles