Escribimos robots comerciales utilizando el marco gráfico StockSharp. Parte 2



Continuamos hablando sobre la creación de robots comerciales utilizando la plataforma StockSharp . El primer artículo trataba sobre la creación del proyecto y el dibujo de los principales elementos del sistema de comercio. En el material final del ciclo, implementaremos directamente la estrategia comercial.

Crear un panel de cartera


Por analogía con la barra de herramientas, cree un panel de registro. Para hacer esto, agregue otro UserControl a la carpeta XAML. Déle el nombre PortfolioGridControl. Agregue un elemento 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> 

En el constructor PortfolioGridControl, necesitamos suscribirnos a eventos de aparición de una nueva cartera y al evento de aparición de una nueva posición en Connector.

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

Por lo tanto, al crear una nueva cartera, aparecerá en el panel de cartera, y cuando aparezca una nueva posición en el panel de cartera, se actualizará.

En la parte central de MainWindow, agregue el panel PortfolioGridControl creado:

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

Corre para verificar:



Tenemos una pestaña con carteras.

Crear un panel de pedidos


La barra de pedidos en S # .API tiene la capacidad de realizar pedidos, retirar pedidos y volver a registrarse. Por analogía con la barra de herramientas, cree un panel de pedidos, agregue otro UserControl a la carpeta XAML. Déle el nombre OrderGridControl. Agregue el elemento 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 tiene un evento de registro OrderRegistering, un evento de reinscripción OrderReRegistering y un evento de cancelación de OrderCanceling.

Creemos sus manejadores:

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

En el controlador de eventos de solicitud de registro, creamos una ventana OrderWindow en la que debe especificar las fuentes de datos para instrumentos, carteras y datos de mercado. En nuestro caso, todo será Connector.

Luego llamamos OrderWindow con el método ShowModal. Si se presionó el botón OK en esta ventana, entonces a través del conector nos registramos usando el método 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); } 

En el controlador de eventos de reinscripción de eventos, hacemos todo de la misma manera. Solo en este caso, el objeto Order llega al evento; este es un pedido que debe volver a registrarse. Por lo tanto, en OrderWindow, especificamos Order = order.ReRegisterClone(newVolume: order.Balance) para completar los campos de la ventana OrderWindow.

Luego llamamos OrderWindow con el método ShowModal. Si se hizo clic en el botón Aceptar en esta ventana, volveremos a registrar la aplicación a través del conector utilizando el método ReRegisterClone. Le transferimos la aplicación anterior, que debe cancelarse, y la nueva, que debe configurarse.

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

En el controlador de eventos de solicitud de cancelación, simplemente llame al método CancelOrder y páselo, que debe cancelarse:

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

Para que los pedidos se muestren en OrderGrid, debe suscribirse a los eventos de aparición de un nuevo pedido y el evento de error de registro en el constructor OrderGridControl, y luego transferir estos eventos a OrderGrid:

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

En la parte central de MainWindow, agregue el panel OrderGridControl creado:

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

Corre para verificar:



Crear su propio panel de transacciones


Por analogía con la barra de herramientas, cree un panel de nuestras propias transacciones. En la carpeta XAML, agregue otro UserControl. Déle el nombre MyTradeGridControl. Agregue el elemento 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> 

En el constructor MyTradeGridControl, debemos suscribirnos a los eventos de aparición de una nueva transacción propia y transferirla a MyTradeGrid:

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

En la parte central de MainWindow, agregue el panel OrderGridControl creado:

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

Corre para verificar:



Crear un panel con una estrategia


Crearemos un panel de estrategia de la misma manera que todos los paneles anteriores. En la carpeta XAML, agregue otro UserControl. Déle el nombre de StrategyControl. Usando LayoutControl, dividimos la pantalla en dos partes. En el lado izquierdo habrá una pestaña con un gráfico de velas y una pestaña con estadísticas de estrategia:

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

Aquí, StatisticParameterGrid se usa para mostrar estadísticas de estrategia, y EquityCurveChart se usa para mostrar el gráfico de pérdidas y ganancias. StatisticParameterGrid necesita establecer algún valor MaxHeight, de lo contrario la aplicación no se iniciará.

El lado derecho configurará las propiedades de la estrategia en PropertyGridEx. Se ubicarán los botones para iniciar y detener la estrategia:

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

Código completo:

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

En el constructor de StrategyControl, establezca el conector como la fuente de datos para PropertyGridEx, en casi todos los controles realizamos acciones similares:

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

Necesitamos transferir de alguna manera la estrategia a nuestro control. Para hacer esto, cree un método BindStraregy en StrategyControl, que tomará la estrategia, guardará el enlace en una variable local y también establecerá la estrategia en PropertyGridEx y StatisticParameterGrid.

Usando el método SetChart, transferimos el gráfico de velas de gráfico a la estrategia; después de eso, puede obtener la estrategia de gráfico utilizando el método GetChart. También configuramos el conector para la estrategia.

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

Al trabajar con el programa de pérdidas y ganancias, debe tenerse en cuenta que la estrategia comenzará y se detendrá, tal vez varias veces, el poema debe borrarse con cada lanzamiento de la estrategia. Para esto, crearemos el método ResetEquityCurveChart en el que primero borraremos el EquityCurveChart. Después de eso, necesitamos crear elementos gráficos para EquityCurveChart, que pueden especificar el nombre, el color y el tipo de línea.

Después de eso, nos suscribimos al evento de cambio de PnL de la estrategia y en el controlador de este evento dibujamos un nuevo valor en el gráfico de ganancias / pérdidas de 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); }; } 

En el controlador de eventos para hacer clic en el botón Inicio, llamaremos a este método. Y también restableceremos el estado de la estrategia y la ejecutaremos:

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

En el controlador de eventos para hacer clic en el botón Detener, detendremos la estrategia.
privado vacío StopStrategyButton_Click (remitente de objeto, RoutedEventArgs e):

 { _strategy.Stop(); } 

En la parte central de MainWindow, agregue el panel StrategyControl creado:

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

Creación de estrategia


Por ejemplo, considere crear una estrategia de vela simple. Ella comprará si la vela está creciendo (verde) y venderá si la vela está disminuyendo (rojo).

Creemos otra carpeta en el proyecto: almacenaremos todas nuestras estrategias en ella. En esta carpeta, cree una nueva clase, llámela SimpleStrategy. Todas las estrategias S # deben heredar de la clase base de la estrategia Estrategia.

 public class SimpleStrategy : Strategy {} 

Como nuestra estrategia usa velas, crearemos la propiedad pública CandleSeries y en el constructor de nuestra estrategia la estableceremos en el valor predeterminado.

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

Aquí indicamos que las velas en CandleSeries serán TimeFrameCandle, con un intervalo de 15 segundos (TimeSpan.FromSeconds (15)). Para CandleSeries, puede especificar el modo de creación de velas BuildCandlesMode. Indicamos que se construirán velas (MarketDataBuildModes.Build). Por defecto, se construirán a partir de ticks, pero puede especificar otros tipos de datos.

Dado que convertimos a CandleSeries en una propiedad pública, CandleSeries se puede personalizar aún más desde el PropertyGridEx descrito en el párrafo anterior. Todas las estrategias tienen métodos que se pueden anular, debemos anular el método OnStarted. Se llama antes de comenzar la estrategia y le permite preestablecer un estado inicial.

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

Aquí, para CandleSeries, definimos la herramienta que se especifica en PropertyGridEx. Luego cree una regla para procesar la vela terminada. En la regla, especifique el método que procesará cada vela terminada; en nuestro caso, este es el método ProcessCandle. Se describirá más adelante. Después de que todo esté configurado, nos suscribimos para que aparezcan velas en CandleSeries en el conector a través del método SubscribeCandles. En nuestro caso, el método ProcessCandle contiene la lógica principal de la estrategia:

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

En primer lugar, debemos determinar si la vela se está construyendo en tiempo real o si es histórica. Si la vela es histórica, la ignoramos. No todas las estrategias requieren esto, por ejemplo, las estrategias basadas en gafas no requieren esto, ya que las gafas siempre van en tiempo real. No existe una forma universal de determinar si una vela es "en tiempo real" o histórica, y en cada estrategia este problema deberá resolverse de forma independiente, según los requisitos. En este caso, simplemente compararemos el tiempo que la vela se cierra con el tiempo en el conector y si no excede un cierto retraso, entonces la vela tendrá un estado en tiempo real.

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

A continuación, observamos qué tipo de vela es y cuál es la posición actual de la estrategia. Si la vela está creciendo, entonces con una posición igual a 0, abriremos la posición con una orden de mercado para el volumen establecido por nosotros en PropertyGridEx. Si la vela está creciendo y la posición es inferior a 0, entonces "invertimos" la posición:

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


Hacemos lo contrario para una vela menguante:

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

Por el momento, nuestra estrategia está lista para funcionar. Se debe pasar al SimpleStrategyControl, que creamos en el párrafo anterior utilizando el método BindStraregy. Hacemos esto en el constructor MainWindow inmediatamente después de inicializar los componentes MainWindow.

 SimpleStrategyControl.BindStraregy(new SimpleStrategy()); 


Corre para verificar:





La estrategia funciona, se hacen tratos, pero hasta ahora no hay velas y tratos en el gráfico.

Agregar velas y ofertas al gráfico desde la estrategia


En la sección sobre el panel de estrategia que usa el método SetChart, traicionamos el gráfico de velas de gráficos en la estrategia. En el método OnStarted de la estrategia, verificamos si el Gráfico está configurado para la estrategia y, si está configurado, inicializamos el gráfico y también nos suscribimos a los eventos de aparición de una nueva transacción propia y un cambio de vela.

 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étodo de inicialización del gráfico 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); }); } 

Aquí guardamos el enlace al Gráfico en una variable local. Limpiamos el horario. También creamos y transferimos al gráfico elementos del gráfico para velas y ofertas. Construcción _chart.GuiSync (() => {...}); necesario para inicializar la programación en el hilo principal.

CandleSeries Gráfico de procesamiento para dibujar velas en un gráfico:

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

Aquí obtenemos una vela del evento CandleSeriesProcessing del conector, creamos un ChartDrawData para mostrarlo en el gráfico. Indicamos los datos de tiempo. Group (candle.OpenTime), indica que la vela debe agregarse al elemento de vela del gráfico .Add (_chartCandleElement, vela);. E indicamos que los gráficos necesitan dibujar nuevos datos.

Realizamos acciones similares para transacciones:

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

Corre para verificar:



Breve conclusión


Para crear una aplicación compleja y de aspecto profesional, no necesita pasar mucho tiempo. Durante varias horas, hemos creado una aplicación completa con la capacidad de configurar, mostrar el comercio directo y el comercio algorítmico.
No tenga miedo de intentar crear sus propios programas comerciales. Esperamos que este artículo lo ayude a sentirse cómodo en este asunto.

Autor : Ivan Zalutsky

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


All Articles