Nous écrivons des robots de trading en utilisant le cadre graphique StockSharp. Partie 1



Dans notre blog, nous écrivons beaucoup sur les technologies et les outils utiles liés à la négociation d'actions. L'un d'eux est la plate-forme gratuite StockSharp , qui peut être utilisée pour le développement professionnel de terminaux de trading et de robots de trading en C #. Dans cet article, nous montrerons comment utiliser le cadre graphique inclus dans S # .API afin de créer un terminal de trading avec la possibilité d'exécuter des stratégies algorithmiques.

Ce qui est nécessaire


  1. Visual Studio 2017 (Communauté, version gratuite), nous y programmerons.
  2. Connexion au trading sur la bourse, dans les exemples de ce texte, l'interface SMARTcom d'ITI Capital est utilisée .

Création de projet


Créez une nouvelle application WPF dans Visual Studio:



Ensuite, vous devez ajouter la bibliothèque S # .API. Vous pouvez découvrir comment procéder dans la documentation . La meilleure option est d'installer à l'aide de Nuget.

Étant donné que tous les éléments graphiques S # .API sont basés sur DevExpress et que les bibliothèques DevExpress sont fournies avec S # .API, il serait stupide de ne pas les utiliser. Passons à l'éditeur de fenêtre MainWindow.xaml:



Remplacez Window par DXWindow, nous en aurons besoin pour utiliser différents schémas de couleurs:



Visual Studio lui-même nous proposera d'insérer les bibliothèques nécessaires.

Nous diviserons la fenêtre en trois parties - en haut, il y aura une bande avec des boutons pour configurer les connexions et les connexions, en bas, il y aura une fenêtre avec des journaux et au milieu tous les autres panneaux. La façon la plus simple de casser une fenêtre est d'utiliser LayoutControl de DevExpress.

Dans les trois parties résultantes, nous ajouterons les éléments dont nous avons besoin.

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

Configuration d'une connexion à un connecteur


Ajoutez deux boutons, l'un est le bouton des paramètres de connexion et le second est le bouton de connexion. Pour ce faire, utilisez le bouton SimpleButton de DevExpress. Les boutons seront situés en haut de l'application. Dans chaque bouton, nous plaçons les images familières de S # .Designer , S # .Data et 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> 

Dans le coin supérieur droit du formulaire d'écran, nous verrons l'image suivante:



Double-cliquez sur chaque bouton pour créer des gestionnaires d'événements pour cliquer sur le bouton. Dans le code MainWindow, vous devez déclarer le connecteur, ainsi que l'emplacement et le nom de fichier dans lesquels les paramètres du connecteur seront stockés.

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

Dans le gestionnaire d'événements pour avoir cliqué sur le bouton des paramètres du connecteur, nous ouvrirons la fenêtre de configuration du connecteur et l'enregistrerons dans un fichier.

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

Dans le constructeur, nous vérifierons s'il existe un répertoire et un fichier avec les paramètres du connecteur, et s'il y en a un, nous le chargerons dans le connecteur:

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

La plupart des objets S # .API ont des méthodes Save et Load qui peuvent être utilisées pour enregistrer et charger cet objet à partir d'un fichier XML.

Dans le gestionnaire de méthode en cliquant sur le bouton de connexion, nous connectons le connecteur.

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

Vous pouvez maintenant exécuter le programme et le vérifier.

Définir un thème sombre


De nombreux traders préfèrent les thèmes sombres aux applications de trading. Par conséquent, nous assombrissons immédiatement le thème du programme. Car vous devez trouver le fichier App.xaml:



Et remplacez Application par un graphique: ExtendedBaseApplication, et Visual Studio lui-même nous proposera d'insérer les bibliothèques nécessaires.

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

Et dans le fichier App.xaml.cs vous devez supprimer ": Application".

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

Dans le constructeur de MainWindow, écrivez ApplicationThemeHelper.ApplicationThemeName = Theme.VS2017DarkName;

Code complet en ce 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(); } } 

Exécutez pour vérifier le sujet sombre:



Créer une barre d'outils


Ajoutez un dossier dans lequel nous allons stocker tous les contrôles que nous avons créés et appelez-le XAML. Ajoutez-y notre premier UserControll, donnez-lui le nom SecurityGridControl.



Nous y ajoutons un élément SecurityPicker. Il affichera les outils disponibles. Par analogie avec la fenêtre principale, nous utiliserons le LayoutControl de 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> 

Passons au concepteur de la fenêtre principale et changeons la partie centrale en vue signets. Dans l'un des signets, nous placerons le contrôleur que nous avons créé avec SecurityPicker:

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

Maintenant que nous avons la barre d'outils, nous devons lui donner une source de données, dans notre cas, c'est un connecteur. Vous pouvez simplement MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
dans le constructeur MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
MainWindow
SecurityPanel.SecPicker.SecurityProvider = Connector;
.

Mais vous ne devez pas obstruer MainWindow avec du code qui ne s’y applique pas. Par conséquent, nous allons créer la variable statique Instance et lui affecter MainWindow dans le constructeur MainWindow:

 public static MainWindow Instance; … Instance = this; … 

Maintenant, n'importe où dans notre programme, nous pouvons accéder aux propriétés de MainWindow via le code MainWindow.Instance.XXX.

Dans le constructeur SecurityGridControl, de cette façon, nous spécifions Connector comme source de données:

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

Exécutez pour vérifier:



Ajout de journalisation


Le programme, le connecteur ou le robot doivent être contrôlés. Pour cela, S # .API a une classe LogManager spéciale. Cette classe reçoit des messages des sources et les transmet aux auditeurs. Dans notre cas, les sources seront le connecteur, les stratégies, etc., et l'auditeur sera un fichier et un panneau de journalisation.

Dans le code MainWindow, nous déclarons l'objet LogManager et l'endroit où il sera stocké:

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

Dans le constructeur MainWindow, créez un LogManager, définissez la source du connecteur et le fichier d'écoute pour celui-ci:

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

Par analogie avec la barre d'outils, créez un panneau de journalisation dans le dossier XAML, ajoutez un autre UserControl. Donnez-lui le nom MonitorControl. Ajoutez-y l'élément Monitor.

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

Dans le constructeur MonitorControl, définissez LogManager sur Monitor en tant qu'écouteur:

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

Ajoutez le MonitorControl créé au bas de MainWindow:

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

Exécutez pour vérifier:



Créer un panneau en verre


Par analogie avec les panneaux précédents, créez un panneau en verre, ajoutez un autre UserControl au dossier XAML. Donnez-lui le nom MarketDepthControl.

Dans MainWindow, nous avons déjà utilisé LayoutControl, dans ce contrôle, nous utiliserons également LayoutControl. Nous divisons le panneau en deux parties horizontalement:

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

Ajoutez SecurityPicker sur le côté gauche - nous l'avons rencontré lorsque nous avons créé la barre d'outils.

 <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 doit définir une valeur MaxHeight, sinon l'application ne démarre pas.

Sous le verre, nous allons placer les éléments de la tâche du portefeuille, le prix et le volume de la commande:

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

Il convient de noter la propriété Label de LayoutItem, elle vous permet de définir le texte devant l'élément. Ainsi que l'élément SpinEdit de DevExpress dans lequel il est pratique de définir des valeurs numériques. Ces éléments se présentent comme suit:



Ci-dessous, nous placerons les boutons d'achat et de vente:

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

Code complet:

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

Dans le constructeur MarketDepthControl, définissez la source des outils pour SecurityPicker et la source des portefeuilles pour PortfolioComboBox, dans notre cas, ce sera Connector:

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

Créez un gestionnaire d'événements de sélection d'outils dans SecurityPicker. Nous y vérifions si l'outil reçu n'est pas égal à zéro. S'il n'est pas égal à zéro, nous sauvegardons l'outil reçu dans une variable locale, il nous sera utile lors de la mise à jour du verre. Ensuite, nous nettoyons et enregistrons l'outil reçu dans le connecteur pour recevoir un verre en utilisant la méthode RegisterMarketDepth. En utilisant la méthode GetMarketDepth, nous obtenons le verre actuel de l'instrument afin de mettre à jour MarketDepthControl avec lui.

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

Pour que le verre soit constamment mis à jour dans le constructeur MarketDepthControl, nous nous abonnons à l'événement de changement de verre MarketDepthChanged sur le connecteur. Dans le gestionnaire de cet événement, nous vérifierons à quel outil appartient le verre reçu et s'il appartient à l'outil sélectionné dans SecurityPicker, nous le mettons à jour: 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); } 

Dans la partie centrale de MainWindow, ajoutez le panneau MarketDepthControl créé:

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

À ce stade, vous pouvez exécuter le programme et vérifier le fonctionnement de la mise à jour des lunettes.
Créez un gestionnaire d'événements pour cliquer sur les boutons d'achat et de vente. Dans chaque gestionnaire, nous créons une commande, nous y indiquons l'outil sélectionné dans SecurityPicker, le portefeuille sélectionné dans PortfolioComboBox, le volume et le prix du SpinEdit correspondant. Enregistrez l'application dans Connector à l'aide de la méthode 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); } 

Les deux processeurs ne diffèrent que dans le sens de l'application.

Faisons en sorte que la valeur SpinEditPrice change en fonction du prix du devis sélectionné lors de la sélection de devis dans un verre. Pour ce faire, créez un gestionnaire d'événements SelectionChanged pour MarketDepthControl. Dans lequel nous mettrons à jour la valeur de SpinEditPrice au prix du devis sélectionné si le devis sélectionné n'est pas égal à zéro.

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

Exécutez pour vérifier:



Sauvegarde des données du marché


Pour enregistrer des portefeuilles, des outils, des plateformes, nous avons besoin de la classe CsvEntityRegistry. Il est nécessaire de refaire l'emplacement de stockage de l'entité et d'appeler la méthode Init pour les charger.

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

Pour économiser des bougies, des offres, etc. nous avons besoin de StorageRegistry:

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

Nous avons également besoin du registre SnapshotRegistry des magasins d'instantanés:

 _snapshotRegistry = new SnapshotRegistry(_snapshotRegistryDir); 

Tout cela, nous le transmettons au connecteur lors de sa création:

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

Ici, nous avons également indiqué que le connecteur se reconnectera lorsque la connexion sera déconnectée et indiquera également le nombre de jours d'historique à télécharger. String Connector.LookupAll (); demande les données disponibles:

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

Après avoir chargé l'application, en allant dans le dossier Data, nous verrons que de nouveaux dossiers sont apparus:



Lors de la reconnexion, les barres d'outils et les portefeuilles seront déjà remplis.

Nous avons approché en douceur la fin de la première partie. À ce stade, le programme vous permet d'afficher toutes les données de marché dont nous disposons. La partie suivante démontrera les plus délicieux - à savoir, le commerce en mode manuel et automatique.

À suivre ...

Auteur : Ivan Zalutsky

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


All Articles