Nous Ă©crivons des robots de trading en utilisant le cadre graphique StockSharp. 2e partie



Nous continuons Ă  parler de la crĂ©ation de robots de trading Ă  l'aide de la plate- forme StockSharp . Le premier article portait sur la crĂ©ation du projet et le dessin des principaux Ă©lĂ©ments du systĂšme commercial. Dans la matiĂšre finale du cycle, nous mettrons directement en Ɠuvre la stratĂ©gie de trading.

Création d'un panneau de portfolio


Par analogie avec la barre d'outils, créez un panneau de journalisation. Pour ce faire, ajoutez un autre UserControl au dossier XAML. Donnez-lui le nom PortfolioGridControl. Ajoutez-y un élément 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> 

Dans le constructeur PortfolioGridControl, nous devons nous abonner aux événements de l'apparition d'un nouveau portefeuille et à l'événement de l'apparition d'une nouvelle position chez Connector.

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

Ainsi, lors de la création d'un nouveau portefeuille, il apparaßtra dans le panneau de portefeuille et lorsqu'une nouvelle position apparaßt dans le panneau de portefeuille, elle sera mise à jour.

Dans la partie centrale de MainWindow, ajoutez le panneau PortfolioGridControl 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> 

Exécutez pour vérifier:



Nous avons un onglet avec des portefeuilles.

Création d'un panel de commandes


La barre de commandes en S # .API a la possibilité de passer des commandes, de retirer des commandes et de se réinscrire. Par analogie avec la barre d'outils, créez un panneau de commande, ajoutez un autre UserControl au dossier XAML. Donnez-lui le nom OrderGridControl. Ajoutez-y l'élément 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 a un événement d'enregistrement OrderRegistering, un événement de réinscription OrderReRegistering et un événement d'annulation OrderCanceling.

Créons leurs gestionnaires:

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

Dans le gestionnaire d'Ă©vĂ©nements d'enregistrement des demandes, nous crĂ©ons une fenĂȘtre OrderWindow dans laquelle vous devez spĂ©cifier les sources de donnĂ©es pour les instruments, les portefeuilles et les donnĂ©es de marchĂ©. Dans notre cas, ce sera tout Connector.

Ensuite, nous appelons OrderWindow avec la mĂ©thode ShowModal. Si le bouton OK a Ă©tĂ© enfoncĂ© dans cette fenĂȘtre, alors via le connecteur, nous nous enregistrons en utilisant la mĂ©thode 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); } 

Dans le gestionnaire d'Ă©vĂ©nements de rĂ©inscription d'Ă©vĂ©nement, nous faisons tout de la mĂȘme maniĂšre. Seulement dans ce cas, l'objet Order vient Ă  l'Ă©vĂ©nement - c'est une commande qui doit ĂȘtre rĂ©enregistrĂ©e. Par consĂ©quent, dans OrderWindow, nous spĂ©cifions Order = order.ReRegisterClone(newVolume: order.Balance) pour remplir les champs de la fenĂȘtre OrderWindow.

Ensuite, nous appelons OrderWindow avec la mĂ©thode ShowModal. Si le bouton OK a Ă©tĂ© cliquĂ© dans cette fenĂȘtre, nous rĂ©enregistrerons l'application via le connecteur Ă  l'aide de la mĂ©thode ReRegisterClone. Nous lui transfĂ©rons l'ancienne application, qui doit ĂȘtre annulĂ©e, et la nouvelle, qui doit ĂȘtre dĂ©finie.

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

Dans le gestionnaire d'Ă©vĂ©nement d'annulation de la demande, il suffit d'appeler la mĂ©thode CancelOrder et de lui passer la commande, qui doit ĂȘtre annulĂ©e:

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

Pour que les commandes soient affichées dans OrderGrid, vous devez vous abonner aux événements de l'apparition d'une nouvelle commande et de l'événement d'erreur d'enregistrement dans le constructeur OrderGridControl, puis transférer ces événements vers OrderGrid:

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

Dans la partie centrale de MainWindow, ajoutez le panneau OrderGridControl 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> 

Exécutez pour vérifier:



Création de votre propre panneau de transactions


Par analogie avec la barre d'outils, créez un panel de nos propres transactions. Dans le dossier XAML, ajoutez un autre UserControl. Donnez-lui le nom MyTradeGridControl. Ajoutez-y l'élément 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> 

Dans le constructeur MyTradeGridControl, nous devons nous abonner aux événements de l'apparition d'une nouvelle transaction et la transférer vers MyTradeGrid:

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

Dans la partie centrale de MainWindow, ajoutez le panneau OrderGridControl 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> 

Exécutez pour vérifier:



Créer un panel avec une stratégie


Nous allons crĂ©er un panneau de stratĂ©gie de la mĂȘme maniĂšre que tous les panneaux prĂ©cĂ©dents. Dans le dossier XAML, ajoutez un autre UserControl. Donnez-lui le nom StrategyControl. En utilisant LayoutControl, nous avons divisĂ© l'Ă©cran en deux parties. Sur le cĂŽtĂ© gauche il y aura un onglet avec un graphique en chandelier et un onglet avec des statistiques de stratĂ©gie:

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

Ici, StatisticParameterGrid est utilisé pour afficher les statistiques de stratégie et EquityCurveChart est utilisé pour afficher le graphique des profits et pertes. StatisticParameterGrid doit définir une valeur MaxHeight, sinon l'application ne démarre pas.

Le cĂŽtĂ© droit configurera les propriĂ©tĂ©s de la stratĂ©gie dans PropertyGridEx. Les boutons de dĂ©marrage et d'arrĂȘt de la stratĂ©gie seront Ă©galement situĂ©s:

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

Code complet:

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

Dans le constructeur StrategyControl, définissez le connecteur comme source de données pour le PropertyGridEx, dans presque tous les contrÎles, nous avons effectué des actions similaires:

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

Nous devons en quelque sorte transférer la stratégie sous notre contrÎle. Pour ce faire, créez une méthode BindStraregy dans StrategyControl, qui prendra la stratégie, enregistrez le lien vers celle-ci dans une variable locale et définissez également la stratégie dans PropertyGridEx et StatisticParameterGrid.

En utilisant la méthode SetChart, nous transférons le graphique des bougies de graphique à la stratégie; aprÚs cela, vous pouvez obtenir la stratégie de graphique en utilisant la méthode GetChart. Nous avons également défini le connecteur de la stratégie.

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

Lorsque vous travaillez avec le tableau des profits et pertes, il convient de noter que la stratĂ©gie commencera et s'arrĂȘtera, peut-ĂȘtre plusieurs fois, le poĂšme doit ĂȘtre effacĂ© Ă  chaque lancement de la stratĂ©gie. Pour cela, nous allons crĂ©er la mĂ©thode ResetEquityCurveChart dans laquelle nous allons d'abord effacer EquityCurveChart. AprĂšs cela, nous devons crĂ©er des Ă©lĂ©ments graphiques pour EquityCurveChart, ils peuvent spĂ©cifier le nom, la couleur et le type de ligne.

AprÚs cela, nous souscrivons à l'événement de changement PnL de la stratégie et dans le gestionnaire de cet événement, dessinons une nouvelle valeur sur le graphique de résultat 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); }; } 

Dans le gestionnaire d'événements pour avoir cliqué sur le bouton Démarrer, nous appellerons cette méthode. Et nous allons également réinitialiser l'état de la stratégie et l'exécuter:

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

Dans le gestionnaire d'Ă©vĂ©nements pour avoir cliquĂ© sur le bouton ArrĂȘter, nous arrĂȘterons la stratĂ©gie.
void privé StopStrategyButton_Click (expéditeur d'objet, RoutedEventArgs e):

 { _strategy.Stop(); } 

Dans la partie centrale de MainWindow, ajoutez le panneau StrategyControl 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 Header="SimpleStrategyControl"> <myxaml:StrategyControl x:Name="SimpleStrategyControl" /> </dxlc:LayoutGroup> </dxlc:LayoutGroup> 

Création de stratégie


Par exemple, envisagez de créer une stratégie de chandelier simple. Elle achÚtera si la bougie grossit (vert) et vendra si la bougie diminue (rouge).

Créons un autre dossier dans le projet - nous y stockerons toutes nos stratégies. Dans ce dossier, créez une nouvelle classe, appelez-la SimpleStrategy. Toutes les stratégies S # doivent hériter de la classe de base de la stratégie Strategy.

 public class SimpleStrategy : Strategy {} 

Puisque notre stratégie utilise des bougies, nous créerons la propriété publique CandleSeries et dans le constructeur de notre stratégie, nous la définirons sur la valeur par défaut.

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

Ici, nous avons indiqué que les bougies dans la CandleSeries seront TimeFrameCandle, avec un intervalle de 15 secondes (TimeSpan.FromSeconds (15)). Pour CandleSeries, vous pouvez spécifier le mode de création de bougie BuildCandlesMode. Nous avons indiqué que des bougies seront construites (MarketDataBuildModes.Build). Par défaut, ils seront construits à partir de ticks, mais vous pouvez spécifier d'autres types de données.

Puisque nous avons fait de CandleSeries une propriĂ©tĂ© publique, CandleSeries peut ĂȘtre davantage personnalisĂ© Ă  partir du PropertyGridEx dĂ©crit dans le paragraphe prĂ©cĂ©dent. Toutes les stratĂ©gies ont des mĂ©thodes qui peuvent ĂȘtre remplacĂ©es, nous devons remplacer la mĂ©thode OnStarted. Il est appelĂ© avant de dĂ©marrer la stratĂ©gie et vous permet de lui prĂ©dĂ©finir un Ă©tat de dĂ©part.

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

Ici, pour CandleSeries, nous définissons l'outil qui est spécifié dans PropertyGridEx. Créez ensuite une rÚgle pour le traitement de la bougie finie. Dans la rÚgle, spécifiez la méthode qui traitera chaque bougie finie - dans notre cas, c'est la méthode ProcessCandle. Il sera décrit plus loin. Une fois que tout est défini, nous nous abonnons pour l'apparence des bougies sur CandleSeries dans le connecteur via la méthode SubscribeCandles. Dans notre cas, la méthode ProcessCandle contient la logique principale de la stratégie:

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

Tout d'abord, nous devons dĂ©terminer si la bougie est construite en temps rĂ©el ou historique. Si la bougie est historique, nous l'ignorons. Toutes les stratĂ©gies ne l'exigent pas, par exemple, les stratĂ©gies basĂ©es sur des lunettes ne l'exigent pas, car les lunettes fonctionnent toujours en temps rĂ©el. Il n'existe aucun moyen universel de dĂ©terminer si une bougie est «en temps rĂ©el» ou historique, et dans chaque stratĂ©gie, ce problĂšme devra ĂȘtre rĂ©solu indĂ©pendamment, en fonction des besoins. Dans ce cas, nous comparerons simplement l'heure de fermeture de la bougie avec l'heure dans le connecteur, et si elle ne dĂ©passe pas un certain dĂ©calage, la bougie aura un statut en temps rĂ©el.

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

Ensuite, nous regardons de quel type de bougie il s'agit et quelle est la position actuelle de la stratégie. Si la bougie croßt, alors avec une position égale à 0, nous ouvrirons la position avec un ordre de marché pour le volume défini par nous dans le PropertyGridEx. Si la bougie grossit et que la position est inférieure à 0, alors nous inversons la position:

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


On fait le contraire pour une bougie décroissante:

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

Pour le moment, notre stratĂ©gie est prĂȘte Ă  fonctionner. Il doit ĂȘtre transmis Ă  SimpleStrategyControl, que nous avons crĂ©Ă© dans le paragraphe prĂ©cĂ©dent Ă  l'aide de la mĂ©thode BindStraregy. Nous le faisons dans le constructeur MainWindow immĂ©diatement aprĂšs l'initialisation des composants MainWindow.

 SimpleStrategyControl.BindStraregy(new SimpleStrategy()); 


Exécutez pour vérifier:





La stratégie fonctionne, des accords sont conclus, mais jusqu'à présent, il n'y a pas de bougies et d'offres sur le graphique.

Ajouter des bougies et des offres au graphique de la stratégie


Dans la section sur le panneau de stratégie utilisant la méthode SetChart, nous avons trahi le graphique des bougies du graphique dans la stratégie. Dans la méthode OnStarted de la stratégie, nous vérifions si le graphique est défini pour la stratégie et s'il est défini, puis nous initialisons le graphique et nous souscrivons également aux événements de l'apparition d'une nouvelle transaction propre et d'un changement de bougie.

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

MĂ©thode d'initialisation du graphique 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); }); } 

Ici, nous enregistrons le lien vers le graphique dans une variable locale. Nous effaçons le calendrier. Nous créons et transférons également les éléments du graphique pour les bougies et les offres. Construction _chart.GuiSync (() => {...}); nécessaire pour initialiser le planning dans le thread principal.

Graphique de traitement des bougies sur un graphique:

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

Ici, nous obtenons une bougie de l'Ă©vĂ©nement CandleSeriesProcessing du connecteur, crĂ©ons un ChartDrawData pour l'afficher sur le graphique. Nous indiquons les donnĂ©es temporelles.Group (candle.OpenTime), indique que la bougie doit ĂȘtre ajoutĂ©e Ă  l'Ă©lĂ©ment bougie du graphique .Add (_chartCandleElement, candle);. Et nous indiquons que les graphiques doivent dessiner de nouvelles donnĂ©es.

Nous effectuons des actions similaires pour les transactions:

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

Exécutez pour vérifier:



BrĂšve conclusion


Pour créer une application complexe et d'aspect professionnel, vous n'avez pas besoin de passer beaucoup de temps. Pendant plusieurs heures, nous avons créé une application à part entiÚre avec la possibilité de configurer, d'afficher le trading direct et le trading algorithmique.
N'ayez pas peur d'essayer de créer vos propres programmes de trading. Nous espérons que cet article vous aidera à vous familiariser avec ce sujet.

Auteur : Ivan Zalutsky

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


All Articles