Wir schreiben Handelsroboter mit dem grafischen Framework von StockSharp. Teil 1



In unserem Blog schreiben wir viel über Technologien und nützliche Tools im Zusammenhang mit dem Aktienhandel. Eine davon ist die kostenlose StockSharp- Plattform, die für die professionelle Entwicklung von Handelsterminals und Handelsrobotern in C # verwendet werden kann. In diesem Artikel wird gezeigt, wie das in S # .API enthaltene grafische Framework verwendet wird, um ein Handelsterminal mit der Fähigkeit zum Ausführen algorithmischer Strategien zu erstellen.

Was wird benötigt


  1. Visual Studio 2017 (Community, kostenlose Version), darin werden wir programmieren.
  2. Verbindung zum Handel an der Börse, in den Beispielen in diesem Text wird die SMARTcom- Schnittstelle von ITI Capital verwendet .

Projekterstellung


Erstellen Sie eine neue WPF-Anwendung in Visual Studio:



Dann müssen Sie die S # .API-Bibliothek hinzufügen. Wie das geht, erfahren Sie in der Dokumentation . Die beste Option ist die Installation mit Nuget.

Da alle S # .API-Grafikelemente auf DevExpress basieren und DevExpress-Bibliotheken mit S # .API geliefert werden, wäre es dumm, sie nicht zu verwenden. Gehen wir zum Fenstereditor MainWindow.xaml:



Ersetzen Sie das Fenster durch DXWindow. Wir benötigen dies, um verschiedene Farbschemata zu verwenden:



Visual Studio selbst bietet uns an, die erforderlichen Bibliotheken einzufügen.

Wir werden das Fenster in drei Teile teilen - oben befindet sich ein Streifen mit Schaltflächen zum Einrichten von Verbindungen und Verbindungen, unten befindet sich ein Fenster mit Protokollen und in der Mitte alle anderen Felder. Der einfachste Weg, ein Fenster zu brechen, ist mit LayoutControl von DevExpress.

In den resultierenden drei Teilen werden wir die Elemente hinzufügen, die wir benötigen.

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

Konfigurieren einer Verbindung zu einem Connector


Fügen Sie zwei Schaltflächen hinzu, eine ist die Schaltfläche für die Verbindungseinstellungen und die zweite ist die Schaltfläche für die Verbindung. Verwenden Sie dazu die SimpleButton-Schaltfläche von DevExpress. Die Schaltflächen befinden sich oben in der Anwendung. In jede Schaltfläche platzieren wir die Bilder, die aus S # .Designer , S # .Data und S # .Terminal bekannt sind .

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

In der oberen rechten Ecke des Bildschirmformulars sehen wir das folgende Bild:



Doppelklicken Sie auf jede Schaltfläche, um Ereignishandler zum Klicken auf die Schaltfläche zu erstellen. Im MainWindow-Code müssen Sie den Connector sowie den Speicherort und den Dateinamen deklarieren, in dem die Connector-Einstellungen gespeichert werden.

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

Im Ereignishandler zum Klicken auf die Schaltfläche Connector-Einstellungen öffnen wir das Connector-Konfigurationsfenster und speichern es in einer Datei.

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

Im Konstruktor prüfen wir, ob es ein Verzeichnis und eine Datei mit den Connector-Einstellungen gibt, und wenn es eines gibt, laden wir es in den Connector:

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

Die meisten S # .API-Objekte verfügen über Save and Load-Methoden, mit denen dieses Objekt aus einer XML-Datei gespeichert und geladen werden kann.

Im Methodenhandler, der auf die Schaltfläche Verbinden klickt, verbinden wir den Konnektor.

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

Jetzt können Sie das Programm ausführen und überprüfen.

Ein dunkles Thema einstellen


Viele Händler bevorzugen dunkle Themen gegenüber Handelsanwendungen. Deshalb machen wir das Thema des Programms sofort dunkel. Für Sie müssen die App.xaml-Datei finden:



Ersetzen Sie die Anwendung durch Diagramm: ExtendedBaseApplication, und Visual Studio selbst bietet uns an, die erforderlichen Bibliotheken einzufügen.

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

Und in der Datei App.xaml.cs müssen Sie ": Application" löschen.

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

Schreiben Sie im Konstruktor von MainWindow ApplicationThemeHelper.ApplicationThemeName = Theme.VS2017DarkName;

Vollständiger Code im Moment:

 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(); } } 

Führen Sie das dunkle Thema aus:



Symbolleiste erstellen


Fügen Sie einen Ordner hinzu, in dem alle von uns erstellten Steuerelemente gespeichert werden, und nennen Sie ihn XAML. Fügen Sie unseren ersten UserControll hinzu und geben Sie ihm den Namen SecurityGridControl.



Wir fügen ein SecurityPicker-Element hinzu. Es werden die verfügbaren Werkzeuge angezeigt. In Analogie zum Hauptfenster verwenden wir das LayoutControl von 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> 

Gehen wir zum Designer des Hauptfensters und ändern den zentralen Teil in die Lesezeichenansicht. In eines der Lesezeichen wird der mit SecurityPicker erstellte Controller eingefügt:

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

Nachdem wir die Symbolleiste haben, müssen wir ihr eine Datenquelle geben, in unserem Fall handelt es sich um einen Konnektor. Sie können einfach in den MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
Konstruktor MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
.

Sie sollten MainWindow jedoch nicht mit Code verstopfen, der nicht für MainWindow gilt. Daher erstellen wir die statische Instanzvariable und weisen ihr im MainWindow-Konstruktor MainWindow zu:

 public static MainWindow Instance; … Instance = this; … 

Jetzt können wir überall in unserem Programm über den Code MainWindow.Instance.XXX auf die Eigenschaften von MainWindow zugreifen.

Im SecurityGridControl-Konstruktor geben wir auf diese Weise Connector als Datenquelle an:

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

Führen Sie aus, um Folgendes zu überprüfen:



Protokollierung hinzufügen


Das Programm, der Anschluss oder der Roboter müssen gesteuert werden. Zu diesem Zweck verfügt S # .API über eine spezielle LogManager-Klasse. Diese Klasse empfängt Nachrichten von Quellen und leitet sie an Listener weiter. In unserem Fall sind die Quellen Connector, Strategien usw., und der Listener ist eine Datei und ein Protokollfenster.

Im MainWindow-Code deklarieren wir das LogManager-Objekt und den Ort, an dem es gespeichert wird:

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

Erstellen Sie im MainWindow-Konstruktor einen LogManager, legen Sie die Connector-Quell- und Listener-Datei dafür fest:

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

Erstellen Sie in Analogie zur Symbolleiste ein Protokollfenster im XAML-Ordner und fügen Sie ein weiteres UserControl hinzu. Geben Sie ihm den Namen MonitorControl. Fügen Sie das Monitor-Element hinzu.

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

Setzen Sie im MonitorControl-Konstruktor LogManager als Listener auf Monitor:

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

Fügen Sie das erstellte MonitorControl unten in MainWindow hinzu:

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

Führen Sie aus, um Folgendes zu überprüfen:



Erstellen Sie eine Glasscheibe


Erstellen Sie in Analogie zu den vorherigen Bedienfeldern eine Glasscheibe und fügen Sie dem XAML-Ordner ein weiteres UserControl hinzu. Geben Sie ihm den Namen MarketDepthControl.

In MainWindow haben wir bereits LayoutControl verwendet, in diesem Steuerelement wird auch LayoutControl verwendet. Wir teilen die Platte horizontal in zwei Teile:

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

Fügen Sie SecurityPicker auf der linken Seite hinzu - wir haben uns mit ihm getroffen, als wir die Symbolleiste erstellt haben.

 <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 muss einen MaxHeight-Wert festlegen, sonst wird die Anwendung nicht gestartet.

Unter dem Glas platzieren wir die Elemente der Portfolioaufgabe, des Preises und des Auftragsvolumens:

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

Beachten Sie die Label-Eigenschaft von LayoutItem, mit der Sie den Text vor dem Element festlegen können. Sowie das SpinEdit-Element von DevExpress, in dem es bequem ist, numerische Werte festzulegen. Diese Elemente sehen wie folgt aus:



Unten platzieren wir die Kauf- und Verkaufsknöpfe:

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

Vollständiger Code:

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

Legen Sie im MarketDepthControl-Konstruktor die Quelle der Tools für SecurityPicker und die Quelle der Portfolios für PortfolioComboBox fest. In unserem Fall ist dies Connector:

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

Erstellen Sie in SecurityPicker einen Ereignishandler für die Werkzeugauswahl. Darin prüfen wir, ob das empfangene Werkzeug ungleich Null ist. Wenn es nicht gleich Null ist, speichern wir das empfangene Werkzeug in einer lokalen Variablen. Dies ist für uns beim Aktualisieren des Glases hilfreich. Anschließend bereinigen und registrieren wir das empfangene Tool im Connector für den Empfang eines Glases mithilfe der RegisterMarketDepth-Methode. Mit der GetMarketDepth-Methode erhalten wir das aktuelle Glas für das Instrument, um MarketDepthControl damit zu aktualisieren.

 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); } 

Damit das Glas im MarketDepthControl-Konstruktor ständig aktualisiert wird, abonnieren wir das MarketDepthChanged-Glaswechselereignis auf dem Connector. Im Handler dieses Ereignisses prüfen wir, zu welchem ​​Werkzeug das empfangene Glas gehört. Wenn es zu dem in SecurityPicker ausgewählten Werkzeug gehört, aktualisieren wir es: 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); } 

Fügen Sie im zentralen Teil von MainWindow das erstellte MarketDepthControl-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> 

In dieser Phase können Sie das Programm ausführen und die Funktion zum Aktualisieren der Brille überprüfen.
Erstellen Sie einen Event-Handler, um auf die Schaltflächen Kaufen und Verkaufen zu klicken. In jedem Handler erstellen wir eine Bestellung, in der wir das in SecurityPicker ausgewählte Tool, das in PortfolioComboBox ausgewählte Portfolio, das Volumen und den Preis aus dem entsprechenden SpinEdit angeben. Registrieren Sie die Anwendung in Connector mit der RegisterOrder-Methode.

 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); } 

Beide Prozessoren unterscheiden sich nur in der Richtung der Anwendung.

Lassen Sie den SpinEditPrice-Wert um den Preis des ausgewählten Angebots ändern, wenn Sie Angebote in einem Glas auswählen. Erstellen Sie dazu einen SelectionChanged-Ereignishandler für MarketDepthControl. In diesem Fall aktualisieren wir den Wert von SpinEditPrice zum Preis des ausgewählten Angebots, wenn das ausgewählte Angebot nicht gleich Null ist.

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

Führen Sie aus, um Folgendes zu überprüfen:



Marktdaten speichern


Um Portfolios, Tools und Plattformen zu speichern, benötigen wir die CsvEntityRegistry-Klasse. Es ist erforderlich, den Speicherort der Entität zu wiederholen und die Init-Methode aufzurufen, um sie zu laden.

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

Um Kerzen, Angebote usw. zu sparen. Wir brauchen StorageRegistry:

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

Wir benötigen auch die SnapshotRegistry-Registrierung von Snapshot-Speichern:

 _snapshotRegistry = new SnapshotRegistry(_snapshotRegistryDir); 

All dies übergeben wir an den Connector, wenn er erstellt wird:

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

Hier haben wir auch angegeben, dass der Connector die Verbindung wieder herstellt, wenn die Verbindung getrennt wird, und wie viele Tage des Verlaufs heruntergeladen werden sollen. String Connector.LookupAll (); fordert verfügbare Daten an:

 //---------------------------------------------------------------------------------- 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)); } //---------------------------------------------------------------------------------- 

Nachdem Sie die Anwendung geladen und in den Datenordner gewechselt haben, werden neue Ordner angezeigt:



Beim erneuten Verbinden werden die Symbolleisten und Portfolios bereits gefüllt.

Wir näherten uns reibungslos dem Ende des ersten Teils. In dieser Phase können Sie mit dem Programm alle uns zur Verfügung stehenden Marktdaten anzeigen. Der nächste Teil zeigt das Köstlichste - nämlich den Handel sowohl im manuellen als auch im automatischen Modus.

Fortsetzung folgt...

Verfasser : Ivan Zalutsky

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


All Articles