
Wir sprechen weiterhin über die Erstellung von Handelsrobotern mithilfe der
StockSharp- Plattform. Der
erste Artikel befasste sich mit der Erstellung des Projekts und der Zeichnung der Hauptelemente des Handelssystems. Im letzten Material des Zyklus werden wir die Handelsstrategie direkt umsetzen.
Erstellen eines Portfolio-Panels
Erstellen Sie in Analogie zur Symbolleiste ein Protokollfenster. Fügen Sie dazu dem XAML-Ordner ein weiteres UserControl hinzu. Geben Sie ihm den Namen PortfolioGridControl. Fügen Sie ein PortfolioGrid-Element hinzu.
<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>
Im PortfolioGridControl-Konstruktor müssen wir Ereignisse des Auftretens eines neuen Portfolios und des Ereignisses des Auftretens einer neuen Position bei Connector abonnieren.
public PortfolioGridControl() { InitializeComponent(); MainWindow.Instance.Connector.NewPortfolio += PortfolioGrid.Portfolios.Add; MainWindow.Instance.Connector.NewPosition += PortfolioGrid.Positions.Add; }
Wenn Sie ein neues Portfolio erstellen, wird es im Portfolio-Bereich angezeigt, und wenn eine neue Position im Portfolio-Bereich angezeigt wird, wird es aktualisiert.
Fügen Sie im zentralen Teil von MainWindow das erstellte PortfolioGridControl-Bedienfeld hinzu:
<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>
Führen Sie aus, um Folgendes zu überprüfen:

Wir haben eine Registerkarte mit Portfolios.
Erstellen eines Auftragspanels
Die Bestellleiste in S # .API bietet die Möglichkeit, Bestellungen aufzugeben, Bestellungen zurückzuziehen und sich erneut zu registrieren. Erstellen Sie in Analogie zur Symbolleiste ein Auftragsfenster und fügen Sie dem XAML-Ordner ein weiteres UserControl hinzu. Geben Sie ihm den Namen OrderGridControl. Fügen Sie das OrderGrid-Element hinzu:
<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 verfügt über ein OrderRegistering-Registrierungsereignis, ein OrderReRegistering-Registrierungsereignis und ein OrderCanceling-Stornierungsereignis.
Lassen Sie uns ihre Handler erstellen:
<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>
Im Anforderungsregistrierungsereignishandler erstellen wir ein OrderWindow-Fenster, in dem Sie Datenquellen für Instrumente, Portfolios und Marktdaten angeben müssen. In unserem Fall ist alles Connector.
Dann rufen wir OrderWindow mit der ShowModal-Methode auf. Wenn in diesem Fenster die OK-Taste gedrückt wurde, registrieren wir uns über den Connector mit der RegisterOrder-Methode:
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); }
Im Event-Handler für die erneute Registrierung machen wir alles auf die gleiche Weise. Nur in diesem Fall kommt das Order-Objekt zum Ereignis - dies ist eine Bestellung, die erneut registriert werden muss. Daher geben wir in OrderWindow
Order = order.ReRegisterClone(newVolume: order.Balance)
an, um die Felder des OrderWindow-Fensters auszufüllen.
Dann rufen wir OrderWindow mit der ShowModal-Methode auf. Wenn in diesem Fenster auf die Schaltfläche OK geklickt wurde, wird die Anwendung mithilfe der ReRegisterClone-Methode über den Connector erneut registriert. Wir übertragen darauf den alten Antrag, der storniert werden muss, und den neuen, der eingestellt werden muss.
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); }
Rufen Sie im Ereignishandler für die Anforderung von Abbrüchen einfach die CancelOrder-Methode auf und übergeben Sie die Bestellung an diese, die storniert werden muss:
private void OrderGrid_OnOrderCanceling(Order order) { MainWindow.Instance.Connector.CancelOrder(order); }
Damit Bestellungen in OrderGrid angezeigt werden, müssen Sie die Ereignisse des Auftretens einer neuen Bestellung und das Registrierungsfehlerereignis im OrderGridControl-Konstruktor abonnieren und diese Ereignisse dann an OrderGrid übertragen:
public OrderGridControl() { InitializeComponent(); MainWindow.Instance.Connector.NewOrder += OrderGrid.Orders.Add; MainWindow.Instance.Connector.OrderRegisterFailed += OrderGrid.AddRegistrationFail; }
Fügen Sie im zentralen Teil von MainWindow das erstellte OrderGridControl-Bedienfeld hinzu:
<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>
Führen Sie aus, um Folgendes zu überprüfen:

Erstellen Sie Ihr eigenes Transaktionsfenster
Erstellen Sie in Analogie zur Symbolleiste ein Panel mit unseren eigenen Transaktionen. Fügen Sie im XAML-Ordner ein weiteres UserControl hinzu. Geben Sie ihm den Namen MyTradeGridControl. Fügen Sie das MyTradeGrid-Element hinzu:
<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>
Im MyTradeGridControl-Konstruktor müssen wir die Ereignisse des Auftretens einer neuen eigenen Transaktion abonnieren und an MyTradeGrid übertragen:
public MyTradeGridControl() { InitializeComponent(); MainWindow.Instance.Connector.NewMyTrade += MyTradeGrid.Trades.Add; }
Fügen Sie im zentralen Teil von MainWindow das erstellte OrderGridControl-Bedienfeld hinzu:
<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>
Führen Sie aus, um Folgendes zu überprüfen:

Erstellen eines Panels mit einer Strategie
Wir werden ein Strategie-Panel auf die gleiche Weise wie alle vorherigen Panels erstellen. Fügen Sie im XAML-Ordner ein weiteres UserControl hinzu. Geben Sie ihm den Namen StrategyControl. Mit LayoutControl teilen wir den Bildschirm in zwei Teile. Auf der linken Seite befindet sich eine Registerkarte mit einem Candlestick-Diagramm und eine Registerkarte mit Strategiestatistiken:
<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>
Hier wird StatisticParameterGrid zum Anzeigen von Strategiestatistiken und EquityCurveChart zum Anzeigen des Gewinn- und Verlustdiagramms verwendet. StatisticParameterGrid muss einen MaxHeight-Wert festlegen, sonst wird die Anwendung nicht gestartet.
Auf der rechten Seite werden die Eigenschaften der Strategie in PropertyGridEx konfiguriert. Die Schaltflächen zum Starten und Stoppen der Strategie befinden sich:
<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>
Vollständiger Code:
<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>
Legen Sie im StrategyControl-Konstruktor den Connector als Datenquelle für PropertyGridEx fest. In fast jedem Steuerelement haben wir ähnliche Aktionen ausgeführt:
public StrategyControl() { InitializeComponent(); PropertyGridEx.SecurityProvider = MainWindow.Instance.Connector; PropertyGridEx.Portfolios = new PortfolioDataSource(MainWindow.Instance.Connector); }
Wir müssen die Strategie irgendwie auf unsere Kontrolle übertragen. Erstellen Sie dazu in StrategyControl eine BindStraregy-Methode, die die Strategie übernimmt, den Link dazu in einer lokalen Variablen speichert und die Strategie auch in PropertyGridEx und StatisticParameterGrid festlegt.
Mit der SetChart-Methode übertragen wir das Diagramm der Diagrammkerzen in die Strategie. Danach können Sie die Diagrammstrategie mit der GetChart-Methode abrufen. Wir setzen auch den Konnektor für die Strategie.
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; }
Bei der Arbeit mit dem Gewinn- und Verlustplan sollte beachtet werden, dass die Strategie startet und stoppt, möglicherweise mehrmals. Das Gedicht muss bei jedem Start der Strategie gelöscht werden. Dazu erstellen wir die ResetEquityCurveChart-Methode, mit der wir zuerst das EquityCurveChart löschen. Dann müssen wir grafische Elemente für EquityCurveChart erstellen. Sie können den Namen, die Farbe und den Linientyp angeben.
Danach abonnieren wir das PnL-Änderungsereignis der Strategie und zeichnen im Handler dieses Ereignisses einen neuen Wert in das EquityCurveChart-Gewinn- / Verlustdiagramm:
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); }; }
Im Event-Handler zum Klicken auf die Schaltfläche Start rufen wir diese Methode auf. Und wir werden auch den Status der Strategie zurücksetzen und ausführen:
private void StartStrategyButton_Click(object sender, RoutedEventArgs e) { ResetEquityCurveChart(); _strategy.Reset(); _strategy.Start(); }
Im Event-Handler zum Klicken auf die Schaltfläche Stop stoppen wir die Strategie.
private void StopStrategyButton_Click (Objektabsender, RoutedEventArgs e):
{ _strategy.Stop(); }
Fügen Sie im zentralen Teil von MainWindow das erstellte StrategyControl-Bedienfeld hinzu:
<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>
Strategieerstellung
Ziehen Sie beispielsweise in Betracht, eine einfache Candlestick-Strategie zu erstellen. Sie wird kaufen, wenn die Kerze wächst (grün) und verkaufen, wenn die Kerze abnimmt (rot).
Lassen Sie uns einen weiteren Ordner im Projekt erstellen - wir werden alle unsere Strategien darin speichern. Erstellen Sie in diesem Ordner eine neue Klasse und nennen Sie sie SimpleStrategy. Alle S # -Strategien müssen von der Basisklasse der Strategiestrategie erben.
public class SimpleStrategy : Strategy {}
Da unsere Strategie Kerzen verwendet, erstellen wir die öffentliche Eigenschaft CandleSeries und setzen sie im Konstruktor unserer Strategie auf den Standardwert.
public class SimpleStrategy : Strategy { public CandleSeries Series { get; set; } public SimpleStrategy() { Series = new CandleSeries(typeof(TimeFrameCandle), new Security(), TimeSpan.FromSeconds(15)) { BuildCandlesMode = MarketDataBuildModes.Build }; } }
Hier haben wir angegeben, dass die Kerzen in der CandleSeries TimeFrameCandle mit einem Intervall von 15 Sekunden sind (TimeSpan.FromSeconds (15)). Für CandleSeries können Sie den BuildCandlesMode-Kerzenerstellungsmodus angeben. Wir haben angegeben, dass Kerzen gebaut werden (MarketDataBuildModes.Build). Standardmäßig werden sie aus Häkchen erstellt, Sie können jedoch auch andere Datentypen angeben.
Da wir CandleSeries zu einer öffentlichen Eigenschaft gemacht haben, kann CandleSeries über das im vorherigen Absatz beschriebene PropertyGridEx weiter angepasst werden. Alle Strategien haben Methoden, die überschrieben werden können. Wir müssen die OnStarted-Methode überschreiben. Es wird vor dem Starten der Strategie aufgerufen und ermöglicht es Ihnen, einen Startzustand festzulegen.
protected override void OnStarted() { _connector = (Connector)Connector; Series.Security = Security; _connector .WhenCandlesFinished(Series) .Do(ProcessCandle) .Apply(this); _connector.SubscribeCandles(Series); base.OnStarted(); }
Hier definieren wir für CandleSeries das Tool, das in PropertyGridEx angegeben ist. Erstellen Sie dann eine Regel für die Verarbeitung der fertigen Kerze. Geben Sie in der Regel die Methode an, mit der jede fertige Kerze verarbeitet wird. In unserem Fall ist dies die ProcessCandle-Methode. Es wird später beschrieben. Nachdem alles festgelegt ist, abonnieren wir das Erscheinen von Kerzen auf CandleSeries im Connector über die SubscribeCandles-Methode. In unserem Fall enthält die ProcessCandle-Methode die Hauptlogik der Strategie:
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))); } }
Zunächst müssen wir feststellen, ob die Kerze in Echtzeit gebaut wird oder historisch ist. Wenn die Kerze historisch ist, ignorieren wir sie. Nicht alle Strategien erfordern dies, zum Beispiel erfordern Strategien, die auf Brillen basieren, dies nicht, da Brillen immer in Echtzeit laufen. Es gibt keine universelle Methode, um festzustellen, ob eine Kerze „in Echtzeit“ oder historisch ist, und in jeder Strategie muss dieses Problem je nach den Anforderungen unabhängig gelöst werden. In diesem Fall vergleichen wir einfach die Zeit, zu der die Kerze schließt, mit der Zeit im Anschluss. Wenn eine bestimmte Verzögerung nicht überschritten wird, hat die Kerze einen Echtzeitstatus.
private bool IsRealTime(Candle candle) { return (Connector.CurrentTime - candle.CloseTime).TotalSeconds < 10; }
Als nächstes schauen wir uns an, um welche Art von Kerze es sich handelt und wie die aktuelle Position der Strategie ist. Wenn die Kerze wächst, eröffnen wir die Position mit einer Position gleich 0 mit einer Marktorder für das von uns in PropertyGridEx festgelegte Volumen. Wenn die Kerze wächst und die Position kleiner als 0 ist, kehren wir die Position um:
if (candle.OpenPrice < candle.ClosePrice && Position <= 0) { RegisterOrder(this.BuyAtMarket(Volume + Math.Abs(Position))); }
Wir machen das Gegenteil für eine abnehmende Kerze:
else if (candle.OpenPrice > candle.ClosePrice && Position >= 0) { RegisterOrder(this.SellAtMarket(Volume + Math.Abs(Position))); }
Im Moment ist unsere Strategie bereit zu arbeiten. Es muss an das SimpleStrategyControl übergeben werden, das wir im vorherigen Absatz mit der BindStraregy-Methode erstellt haben. Wir tun dies im MainWindow-Konstruktor unmittelbar nach der Initialisierung der MainWindow-Komponenten.
SimpleStrategyControl.BindStraregy(new SimpleStrategy());
Führen Sie aus, um Folgendes zu überprüfen:


Die Strategie funktioniert, Geschäfte werden gemacht, aber bisher gibt es keine Kerzen und Geschäfte auf dem Chart.
Hinzufügen von Kerzen und Deals zum Diagramm aus der Strategie
Im Abschnitt über das Strategiefenster mit der SetChart-Methode haben wir das Diagramm der Diagrammkerzen in die Strategie verraten. In der OnStarted-Methode der Strategie prüfen wir, ob das Diagramm für die Strategie festgelegt ist, und wenn es festgelegt ist, initialisieren wir das Diagramm und abonnieren auch die Ereignisse des Auftretens einer neuen eigenen Transaktion und eines Kerzenwechsels.
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-Diagramminitialisierungsmethode:
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); }); }
Hier speichern wir den Link zu Chart in einer lokalen Variablen. Wir klären den Zeitplan. Wir erstellen auch Elemente für Kerzen und Angebote und übertragen sie auf das Diagramm. Konstruktion _chart.GuiSync (() => {...}); benötigt, um den Zeitplan im Hauptthread zu initialisieren.
CandleSeriesProcessing-Diagramm zum Zeichnen von Kerzen auf einem Diagramm:
private void CandleSeriesProcessing(CandleSeries candleSeries, Candle candle) { var data = new ChartDrawData(); data.Group(candle.OpenTime) .Add(_chartCandleElement, candle); _chart.Draw(data); }
Hier erhalten wir eine Kerze aus dem CandleSeriesProcessing-Ereignis des Connectors. Erstellen Sie eine ChartDrawData, um sie im Diagramm anzuzeigen. Wir geben die Zeitdaten an. Gruppe (candle.OpenTime), geben an, dass die Kerze zum Kerzenelement des Diagramms hinzugefügt werden soll .Add (_chartCandleElement, candle); Und wir weisen darauf hin, dass die Grafiken neue Daten zeichnen müssen.
Wir führen ähnliche Aktionen für Transaktionen durch:
public void DrawMyTrade(MyTrade myTrade) { var data = new ChartDrawData(); data.Group(myTrade.Trade.Time) .Add(_tradesElem, myTrade); _chart.Draw(data); }
Führen Sie aus, um Folgendes zu überprüfen:

Kurzer Abschluss
Um eine komplexe und professionell aussehende Anwendung zu erstellen, müssen Sie nicht viel Zeit aufwenden. Seit mehreren Stunden haben wir eine vollwertige Anwendung erstellt, mit der direkter Handel und algorithmischer Handel konfiguriert, angezeigt werden können.
Haben Sie keine Angst, Ihre eigenen Handelsprogramme zu erstellen. Wir hoffen, dass dieser Artikel Ihnen hilft, sich in dieser Angelegenheit wohl zu fühlen.
Verfasser : Ivan Zalutsky