Saltar a contenido

Controles

Los controles permiten ciertas interacciones con cBots, indicadores y plugins. Utilizando la guía a continuación, puede crear fácilmente controles de interfaz de usuario básicos y avanzados directamente en un gráfico.

Hay varias clases integradas que representan controles populares como botones, bloques de texto, cuadros de texto y formas. Sin embargo, también puede crear controles personalizados.

Considere el siguiente ejemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using cAlgo.API;

namespace ChartControlsTest
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ChartControls : Indicator
    {
        [Parameter(DefaultValue = "Click Me")]
        public string Text { get; set; }

        [Parameter(DefaultValue = HorizontalAlignment.Center)]
        public HorizontalAlignment HorizontalAlignment { get; set; }

        [Parameter(DefaultValue = VerticalAlignment.Center)]
        public VerticalAlignment VerticalAlignment { get; set; }

        protected override void Initialize()
        {
            var button = new Button
            {
                Text = Text,
                HorizontalAlignment = HorizontalAlignment,
                VerticalAlignment = VerticalAlignment
            };

            button.Click += Button_Click;

            Chart.AddControl(button);
        }

        private void Button_Click(ButtonClickEventArgs obj)
        {
            obj.Button.Text = "You clicked me, thanks";
        }

        public override void Calculate(int index)
        {
        }
    }
}

Si crea el indicador anterior y crea una instancia, debería ver un botón gris Haz clic aquí justo en el centro del gráfico.

Diferencia entre controles y objetos de gráfico

En una sección anterior, ya hemos cubierto los objetos de gráfico. Los controles permiten a los usuarios interactuar con cBots e indicadores. Por el contrario, los objetos de gráfico dan la oportunidad de dibujar algo en el gráfico de operaciones o en una ventana de salida de indicador separada.

Los controles de gráfico derivan de la clase ControlBase mientras que los objetos de gráfico se derivan de la clase ChartObject.

Los controles de gráfico se posicionan estáticamente utilizando diferentes opciones de alineación. Aunque los objetos de gráfico pueden posicionarse exactamente de la misma manera, su posición también puede cambiar dinámicamente dependiendo de ciertas coordenadas X e Y.

De manera similar a los objetos de gráfico, los controles de gráfico se pueden agregar tanto al gráfico principal como a cualquier ventana de salida de indicador (si existen). A continuación se muestra un ejemplo de dicho posicionamiento:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using cAlgo.API;

namespace ChartControlsTest
{
    [Indicator(IsOverlay = false, AccessRights = AccessRights.None)]
    public class ChartControls : Indicator
    {
        [Parameter(DefaultValue = "Click Me")]
        public string Text { get; set; }

        [Parameter(DefaultValue = HorizontalAlignment.Center)]
        public HorizontalAlignment HorizontalAlignment { get; set; }

        [Parameter(DefaultValue = VerticalAlignment.Center)]
        public VerticalAlignment VerticalAlignment { get; set; }

        protected override void Initialize()
        {
            var button = new Button
            {
                Text = Text,
                HorizontalAlignment = HorizontalAlignment,
                VerticalAlignment = VerticalAlignment
            };

            button.Click += Button_Click;

            IndicatorArea.AddControl(button);
        }

        private void Button_Click(ButtonClickEventArgs obj)
        {
            obj.Button.Text = "You clicked me, thanks";
        }

        public override void Calculate(int index)
        {
        }
    }
}

Después de crear una instancia de indicador, debería ver un botón Haz clic aquí en la ventana de salida del indicador.

ColorPicker

El control ColorPicker permite a los operadores seleccionar su color preferido para elementos u objetos clave en cTrader. Por ejemplo, un desarrollador puede integrar el control ColorPicker en un cBot que dibuja líneas de tendencia para que los usuarios puedan seleccionar su color preferido para cada línea de tendencia. Esta configuración facilita a los operadores distinguir entre varios tipos de líneas de tendencia.

Un plugin que agrega indicadores a los gráficos también puede implementar el control ColorPicker, ya que esta función permite a los usuarios elegir un color para diferentes líneas de indicadores.

Cuando los usuarios hacen clic en el cuadrado de color, aparece el selector de color. Los usuarios pueden entonces elegir entre colores estándar y personalizados.

Ejemplo de código:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.None)]
    public class ColorPickerTest : Plugin
    {
        protected override void OnStart()
        {
            var aspBlock = Asp.SymbolTab.AddBlock("Color Picker");

            var colorPicker = new ColorPicker {IsStretched = true, SelectedColor = Color.Red, Height = 20, Width = 20, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center};

            aspBlock.Child = colorPicker;

            colorPicker.SelectedColorChanged += colorPicker_SelectedColorChanged;

        }

        private void colorPicker_SelectedColorChanged(ColorPickerSelectedColorChangedEventArgs obj)
        {
            Print($"colorPicker_SelectedColorChanged, NewSelectedColor: {obj.NewSelectedColor} | PreviousSelectedColor: {obj.PreviousSelectedColor}");
        }

        protected override void OnStop()
        {
            // Handle Plugin stop here
        }
    }        
}

Image title

DropZone

El control DropZone permite a los operadores realizar acciones de arrastrar y soltar con cBots, indicadores o plugins. Para implementar este control en su algoritmo, utilice la clase DropZone. El control DropZone se puede manipular como cualquier otro control.

Cuando un usuario suelta un archivo o carpeta compatible en el cuadro, se genera el evento Dropped. Cuando un usuario suelta una carpeta o varias carpetas en el cuadro, solo se procesan y copian los archivos compatibles con las extensiones especificadas en FilterExtensions.

Nota

Los archivos soltados generalmente se copian y guardan en esta ubicación: ..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected Files\

La ubicación para las instancias de cBot difiere de la anterior: ..\Documents\cAlgo\Data\cBots\{cBotName}\{unique-instance-number}\Selected files\

Este código de plugin le muestra cómo agregar un control DropZone a Trade Watch:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using System.Drawing;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.None)]
    public class TradeWatchTabSample : Plugin
    {
        protected override void OnStart()
        {
            var tab = TradeWatch.AddTab("DropZone");

            var _border = new Border
            {
                BorderThickness = 3,
                BorderColor = Color.DarkGray,
                Opacity = 0.7,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                Height = 200,
                Width = 350,
                BackgroundColor = Color.LightGray
            };

            var _textBlock = new TextBlock
            {
                Text = "Drag your files here",
                Opacity = 1,
                ForegroundColor = Color.DarkGray,
                FontSize = 16,
                VerticalAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };

            var _dropzone = new DropZone
            {
                FilterExtensions = new string[] { "txt", "algo", "csv" },
                IsDirectoryDropAllowed = true,
                IsVisible = true,
                IsEnabled = true
            };
            _border.Child = _textBlock;
            _dropzone.Child = _border;
            //   _dropzone.Child = _textBlock;
            tab.Child = _dropzone;

            _dropzone.Dropped += Dropped_file;
        }

        private void Dropped_file(DroppedEventArgs obj)
        {
            Print("File has been added!");
        }
    }
}

Image title

ProgressBar

El control ProgressBar muestra la progresión de una operación en curso. Las barras de progreso hacen que los algoritmos sean más fáciles de usar y ayudan a gestionar las expectativas de los operadores con respecto al tiempo de espera de ciertas operaciones.

La API de cTrader Algo permite a los desarrolladores agregar dos tipos de controles ProgressBar: control infinito y control determinado.

Control infinito

Es posible que desee utilizar el control infinito en las siguientes situaciones:

  • No puede determinar el tiempo de espera de una operación.
  • No puede detectar la progresión de una operación.
  • No desea indicar cuánto tiempo tardará una operación.

Image title

Control determinado

Es posible que desee utilizar este control cuando pueda determinar el tiempo de espera de una operación y desee que los usuarios vean un indicador basado en ese tiempo.

Para mostrar el progreso de la operación, utilice la propiedad Value para establecer una cifra. Para establecer el porcentaje de la barra de progreso, utilice las propiedades Minimum y Maximum.

Image title

El código de plugin a continuación le muestra cómo crear una barra de progreso utilizando controles infinitos y determinados (verde):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using System;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.None)]
    public class ProgressBarTest : Plugin
    {
        private ProgressBar _infiniteProgressBar;
        private ProgressBar _determinateProgressBar;

        protected override void OnStart()
        {
            var aspBlock = Asp.SymbolTab.AddBlock("Progress bar");

            var panel = new StackPanel() {Height = 200, Width = 200, Orientation = Orientation.Vertical};

            _infiniteProgressBar = new ProgressBar {IsIndeterminate = true, Height = 20};

            panel.AddChild(_infiniteProgressBar);

            _determinateProgressBar = new ProgressBar {IsIndeterminate = false, Height = 20};

            panel.AddChild(_determinateProgressBar);

            var autoProgressButton = new Button {Text = "Start"};

            autoProgressButton.Click += AutoProgressButton_Click;

            panel.AddChild(autoProgressButton);

            aspBlock.Child = panel;

        }

        private void AutoProgressButton_Click(ButtonClickEventArgs obj)
        {
            Timer.Start(1);
        }

        protected override void OnTimer()
        {
            _determinateProgressBar.Value++;

            Print($"Value: {_determinateProgressBar.Value}");
        }

        protected override void OnStop()
        {
            // Handle Plugin stop here
        }
    }        
}

Diálogos

OpenFileDialog y OpenFolderDialog

La API de cTrader Algo proporciona la interfaz OpenFileDialog para permitir a los usuarios seleccionar un archivo para un algoritmo. Cuando un usuario selecciona un archivo en la ventana resultante, el archivo se copia a la carpeta Selected files del algoritmo. Un algoritmo puede trabajar con archivos dentro de su carpeta Selected files sin restricciones.

Consejo

Utilice la funcionalidad OpenFileDialog cuando necesite cargar archivos de datos importantes, archivos de respaldo o configuración, indicadores personalizados o scripts.

El código a continuación le muestra cómo utilizar el diálogo OpenFileDialog en un indicador:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using System;
using cAlgo.API;
using System.Text;

namespace cAlgo
{
    [Indicator(AccessRights = AccessRights.None, IsOverlay = true)]
    public class OpenFileDialogExample : Indicator
    {
        private OpenFileDialog _openFileDialog;

        protected override void Initialize()
        {
            _openFileDialog = new OpenFileDialog()
            {
                InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                Multiselect = true,
                Title = "My Open File Dialog Title"
            };

            var showOpenFileDialog = new Button { Text = "Show Open File Dialog" };
            showOpenFileDialog.Click += showOpenFileDialog_Click;

            var panel = new StackPanel
            {
                Orientation = Orientation.Vertical,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };

            panel.AddChild(showOpenFileDialog);
            Chart.AddControl(panel);
        }

        private void showOpenFileDialog_Click(ButtonClickEventArgs obj)
        {
            var result = _openFileDialog.ShowDialog();
            Print($"Result: {result} | FileName: {_openFileDialog.FileName} | FileNames: {string.Join(',', _openFileDialog.FileNames)}");
        }

        public override void Calculate(int index)
        {
        }
    }
}

Image title

La API de cTrader Algo proporciona la interfaz OpenFolderDialog para permitir a los usuarios especificar una carpeta para un algoritmo. Cuando un usuario selecciona una carpeta en la ventana resultante, todos los archivos y carpetas con archivos dentro de la carpeta seleccionada se copian a la carpeta Selected files del algoritmo.

Consejo

Utilice la funcionalidad OpenFolderDialog cuando necesite cargar una carpeta que contenga archivos de datos críticos, archivos de respaldo o configuración, indicadores personalizados o scripts.

Los archivos y carpetas seleccionados generalmente se copian a la carpeta Selected files porque un algoritmo puede trabajar con elementos dentro de esa carpeta incluso cuando su AccessRights está configurado como None.

Nota

La carpeta Selected files de un algoritmo generalmente se encuentra en esta ruta: ..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected files\

La carpeta Selected files para una instancia de cBot difiere de la anterior: ..\Documents\cAlgo\Data\cBots\{cBotName}\{Instance-Id}\Selected files\

El código a continuación le muestra cómo utilizar el diálogo OpenFolderDialog en un indicador:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
using cAlgo.API;

namespace cAlgo
{
    [Indicator(AccessRights = AccessRights.None, IsOverlay = true)]
    public class OpenFolderDialogExample : Indicator
    {
        private OpenFolderDialog _openFolderDialog;

        protected override void Initialize()
        {
            _openFolderDialog = new OpenFolderDialog()
            {
                InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                Title = "My Open Folder Dialog Title"
            };

            var showOpenFolderDialog = new Button { Text = "Show Open Folder Dialog" };
            showOpenFolderDialog.Click += showOpenFolderDialog_Click;

            var panel = new StackPanel
            {
                Orientation = Orientation.Vertical,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };

            panel.AddChild(showOpenFolderDialog);
            Chart.AddControl(panel);
        }

        private void showOpenFolderDialog_Click(ButtonClickEventArgs obj)
        {
            var result = _openFolderDialog.ShowDialog();
            Print($"Result: {result} | FolderName: {_openFolderDialog.FolderName}");
        }

        public override void Calculate(int index)
        {
        }
    }
}

Image title

SaveFileDialog

La API de cTrader Algo proporciona la interfaz SaveFileDialog para permitir a los usuarios guardar archivos (localmente) en sus computadoras. Cuando aparece la ventana correspondiente, un usuario selecciona la carpeta en la que desea guardar el archivo e ingresa un nombre para el archivo. Luego, el archivo se guarda en la ubicación especificada.

Consejo

Utilice la funcionalidad SaveFileDialog cuando necesite hacer cualquiera de las siguientes acciones:

  • Guardar informes de rendimiento, resultados de backtesting, archivos de configuración o datos de optimización.
  • Exportar registros de operaciones, diarios de operaciones o datos de actividad general del usuario.
  • Almacenar indicadores personalizados, datos para gráficos y visualizaciones o parámetros para una estrategia.

El código a continuación le muestra cómo utilizar el diálogo SaveFileDialog en un indicador:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using System;
using cAlgo.API;
using System.Text;

namespace cAlgo
{
    [Indicator(AccessRights = AccessRights.None, IsOverlay = true)]
    public class SaveFileDialogExample : Indicator
    {
        private SaveFileDialog _saveFileDialog;

        protected override void Initialize()
        {
            _saveFileDialog = new SaveFileDialog()
            {
                InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                Title = "My Save File Dialog Title"
            };

            var showSaveFileDialogText = new Button { Text = "Show Save File Dialog (Set Content as text)" };
            var showSaveFileDialogBytes = new Button { Text = "Show Save File Dialog (Set Content as bytes)" };

            showSaveFileDialogText.Click += showSaveFileDialogText_Click;
            showSaveFileDialogBytes.Click += showSaveFileDialogBytes_Click;

            var panel = new StackPanel
            {
                Orientation = Orientation.Vertical,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };
            panel.AddChild(showSaveFileDialogText);
            panel.AddChild(showSaveFileDialogBytes);
            Chart.AddControl(panel);
        }

        private void showSaveFileDialogText_Click(ButtonClickEventArgs obj)
        {
            var result = _saveFileDialog.ShowDialog();
            Print($"Result: {result}");
            if (result != FileDialogResult.Cancel)
            {
                _saveFileDialog.WriteToFile("Test in text");
            }
        }

        private void showSaveFileDialogBytes_Click(ButtonClickEventArgs obj)
        {
            var result = _saveFileDialog.ShowDialog();
            Print($"Result: {result}");
            if (result != FileDialogResult.Cancel)
            {
                _saveFileDialog.WriteToFile(Encoding.UTF8.GetBytes("Test in bytes"));
            }
        }

        public override void Calculate(int index)
        {
        }
    }
}

Controles arrastrables

Control arrastrable del área del gráfico

Las interfaces ChartDraggable y ChartDraggables proporcionan tipos que le permiten agregar un control arrastrable capaz de alojar otros controles y diferentes elementos a un gráfico. Estos controles arrastrables facilitan a los usuarios la interacción con varios elementos del gráfico.

Nota

Un control arrastrable solo se puede mover o reposicionar dentro del gráfico donde se ha agregado.

Este código le muestra cómo crear un indicador que agrega dos controles que se pueden mover dentro de un gráfico:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using System;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(AccessRights = AccessRights.None)]
    public class DragControl : Indicator
    {
        protected override void Initialize()
        {
            var draggable = Chart.Draggables.Add();
            var draggable2 = IndicatorArea.Draggables.Add();

            draggable.Child = GetDraggableChildWebView();
            draggable2.Child = GetDraggableChildText();

            draggable.LocationChanged += draggable_LocationChanged;
            draggable2.LocationChanged += draggable2_LocationChanged;
        }

        public override void Calculate(int index)
        {
            // Calculate value at specified index
            // Result[index] = 
        }

        private StackPanel GetDraggableChildWebView()
        {
            var stackPanel = new StackPanel
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                BackgroundColor = Color.Gold
            };

            var webView = new WebView() {Height = 500, Width = 300};

            webView.Loaded += webView_Loaded;

            stackPanel.AddChild(webView);

            return stackPanel;
        }

        private StackPanel GetDraggableChildText()
        {
            var stackPanel = new StackPanel
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                BackgroundColor = Color.Gold
            };
            var text_block = new TextBlock
                 {
                     Text = "Testing draggable controls",
                     Margin = 5,
                     ForegroundColor = Color.Black,
                     FontWeight = FontWeight.ExtraBold
                 };

            stackPanel.AddChild(text_block);

            return stackPanel;
        }


        private void webView_Loaded(WebViewLoadedEventArgs obj)
        {
            obj.WebView.NavigateAsync("https://www.youtube.com/");
        }

        private void draggable_LocationChanged(ChartDraggableLocationChangedEventArgs obj)
        {
            Print($"Draggable '{obj.Draggable.Id}' location changed to: ({obj.Draggable.X}, {obj.Draggable.Y})");
        }

        private void draggable2_LocationChanged(ChartDraggableLocationChangedEventArgs obj)
        {
            Print($"Draggable '{obj.Draggable.Id}' location changed to: ({obj.Draggable.X}, {obj.Draggable.Y})");
        }
    }
}

Control arrastrable de la ventana de la aplicación

Las interfaces ApplicationDraggable y ApplicationDraggables proporcionan los tipos utilizados para agregar controles flotantes que se pueden mover individualmente por toda la ventana de la aplicación cTrader. Estos controles le permiten crear interfaces de usuario interactivas y dinámicas.

Nota

De los tres tipos de algoritmos, solo los plugins pueden implementar controles arrastrables en toda la aplicación.

Este código le muestra cómo crear un plugin que agrega un componente WebView y un bloque de texto en dos ventanas separadas, que se pueden mover por toda la interfaz de usuario de cTrader:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
using System;
using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.None)]
    public class ApplicationLevelDraggables : Plugin
    {
        private ApplicationDraggable _webDraggable;
        private ApplicationDraggable _textDraggable;

        protected override void OnStart()
        {
            _webDraggable = Application.Draggables.Add();
            _webDraggable.Child = GetDraggableChildWebView();
            _webDraggable.LocationChanged += OnDraggableLocationChanged;

            _textDraggable = Application.Draggables.Add();
            _textDraggable.Child = GetDraggableChildText();
            _textDraggable.LocationChanged += OnDraggableLocationChanged;
        }

        private void OnDraggableLocationChanged(ApplicationDraggableLocationChangedEventArgs args)
        {
            Print($"Draggable '{args.Draggable.Id}' location changed to: ({args.Draggable.X}, {args.Draggable.Y})");
        }

        private StackPanel GetDraggableChildWebView()
        {
            var stackPanel = new StackPanel
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                BackgroundColor = Color.Gold
            };

            var webView = new WebView { Width = 300, Height = 200 };
            webView.Loaded += (args) => args.WebView.NavigateAsync("https://www.youtube.com/");

            stackPanel.AddChild(webView);

            return stackPanel;
        }

        private StackPanel GetDraggableChildText()
        {
            var stackPanel = new StackPanel
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                BackgroundColor = Color.Gold
            };

            var textBlock = new TextBlock
            {
                Text = "Testing Application-level draggable",
                Margin = 5,
                ForegroundColor = Color.Black,
                FontWeight = FontWeight.ExtraBold
            };

            stackPanel.AddChild(textBlock);

            return stackPanel;
        }
    }
}

Control de pestañas

La clase TabControl proporciona tipos que le permiten crear múltiples pestañas para un algoritmo. Estas pestañas se pueden utilizar para mantener juntos elementos relacionados o presentar vistas separadas para funcionalidades.

Este código le muestra cómo usar pestañas en un plugin agregado al Panel de símbolo activo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.FullAccess)]
    public class TabControlSimple : Plugin
    {
        private TabControl _tabControl;

        protected override void OnStart()
        {
            _tabControl = new TabControl
            {
                Height = 200,
                TabStripPlacement = Dock.Left 
            };

            var firstTab = new TabItem
            {
                Header = new TextBlock { Text = "First Tab" },
                Content = new TextBlock { Text = "First Tab Content", BackgroundColor = Color.Red }
            };

            var secondTab = new TabItem
            {
                Header = new TextBlock { Text = "Second Tab" },
                Content = new TextBlock { Text = "Second Tab Content" }
            };

            _tabControl.AddTab(firstTab);
            _tabControl.AddTab(secondTab);

            _tabControl.SelectedTabChanged += TabControl_SelectedTabChanged;

            _tabControl.SelectedTab = secondTab;

            var panel = new StackPanel { Orientation = Orientation.Vertical };
            panel.AddChild(_tabControl);

            var asp = Asp.SymbolTab.AddBlock("Simple Tab Control");
            asp.Child = panel;
            asp.Height = 300;
        }

        private void TabControl_SelectedTabChanged(TabControlSelectedTabChangedEventArgs obj)
        {
            Print($"Selected tab changed to: {obj.SelectedTab?.UniqueId}");
        }

        protected override void OnStop()
        {
        }
    }
}

Controles personalizados

Un control personalizado es un control que, en esencia, está construido por varios controles predefinidos. En otras palabras, es un control para el cual otros controles constituyen su contenido.

Los controles personalizados actúan como clases reutilizables de manera similar a los controles integrados.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using cAlgo.API;

namespace ChartControlsTest
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ChartControls : Indicator
    {
        [Parameter("# Of Text Areas", DefaultValue = 4)]
        public int NumberOfTextAreas { get; set; }

        protected override void Initialize()
        {
            var panel = new WrapPanel
            {
                Orientation = Orientation.Horizontal,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };

            for (int i = 0; i < NumberOfTextAreas; i++)
            {
                var textArea = new TextArea
                {
                    HorizontalAlignment = HorizontalAlignment.Right,
                    VerticalAlignment = VerticalAlignment.Stretch,
                    Margin = 5,
                };

                panel.AddChild(textArea);
            }

            Chart.AddControl(panel);
        }

        public override void Calculate(int index)
        {
        }
    }

    public class TextArea : CustomControl
    {
        private readonly TextBox _textBox;

        public TextArea()
        {
            _textBox = new TextBox
            {
                TextAlignment = TextAlignment.Left,
                TextWrapping = TextWrapping.Wrap,
                AcceptsReturn = true,
                AcceptsTab = true,
                Width = 300,
                Height = 200,
            };

            AddChild(_textBox);
        }
    }
}

Una instancia de este indicador debería mostrar cuatro cuadros de texto directamente en el centro del gráfico principal.

Organizar controles con paneles

Para hacer que el trabajo con controles sea más conveniente, es posible que desee colocar varios controles en un grupo distinto con su propia posición en la interfaz de usuario. Para hacer esto, puede usar la clase Panels y sus derivados.

Piense en un panel como un control con otros controles como su contenido. cTrader admite cinco clases diferentes que heredan de la clase base Panels (que a su vez hereda de la clase Control):

  • Canvas
  • DockPanel
  • Grid
  • StackPanel
  • WrapPanel

Cada una de las clases anteriores utiliza diferentes diseños de panel y estrategias de posicionamiento, como se explica a continuación.

Canvas

El canvas es un panel que permite posicionar controles basándose en ciertas coordenadas X e Y.

Cabe destacar que los ejes X e Y son diferentes de los utilizados por los objetos o trazados del gráfico. Las coordenadas X e Y utilizadas por la clase Canvas representan valores numéricos que comienzan en (0, 0) desde la esquina superior izquierda del gráfico.

Considere el siguiente ejemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
using cAlgo.API;

namespace ChartControlsTest
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ChartControls : Indicator
    {
        [Parameter(DefaultValue = "Click Me")]
        public string Text { get; set; }

        [Parameter(DefaultValue = 0)]
        public double Left { get; set; }

        [Parameter(DefaultValue = 0)]
        public double Top { get; set; }

        [Parameter(DefaultValue = 0)]
        public double Margin { get; set; }

        [Parameter(DefaultValue = 10)]
        public double Padding { get; set; }

        protected override void Initialize()
        {
            var button = new Button
            {
                Text = Text,
                Left = Left,
                Top = Top,
                Margin = Margin,
                Padding = Padding
            };

            button.Click += Button_Click;

            var canvas = new Canvas();

            /* We add our button control to the canvas
            panel. */
            canvas.AddChild(button);

            // We add our canvas panel to the chart.
            Chart.AddControl(canvas);
        }

        private void Button_Click(ButtonClickEventArgs obj)
        {
            obj.Button.Text = "You clicked me, thanks";
        }

        public override void Calculate(int index)
        {
        }
    }
}

Al crear una instancia del indicador anterior, debería ver el botón Haz clic aquí en la esquina superior izquierda del gráfico.

La propiedad Top de un control determina su posición en el eje Y. A su vez, la propiedad Left define su posición en el eje X.

El código anterior también utiliza las propiedades Padding y Margin. Padding se refiere a la distancia entre el contenido del control y sus bordes externos. Margin es la distancia entre el control y los bordes de su padre. Las propiedades Padding y Margin son aplicables a todos los paneles, no solo a la clase canvas. Son útiles para gestionar el espaciado entre sus controles.

En la mayoría de los casos, la clase Canvas se utiliza para agrupar solo un pequeño número de controles.

Panel de acoplamiento

La clase DockPanel se utiliza para acoplar (colocar) un control en una ubicación estática en el gráfico. Hay cuatro posiciones de acoplamiento posibles:

  • Arriba
  • Abajo
  • Izquierda
  • Derecha

Cada control tiene una propiedad Dock. Al utilizar la clase DockPanel, puede usar esta propiedad para posicionar un control dentro de un DockPanel. Esto se ilustra en el siguiente ejemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using cAlgo.API;

namespace ChartControlsTest
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ChartControls : Indicator
    {
        [Parameter(DefaultValue = Dock.Top)]
        public Dock TextBoxDock { get; set; }

        [Parameter(DefaultValue = Dock.Bottom)]
        public Dock ButtonDock { get; set; }

        private TextBox _textBox;

        protected override void Initialize()
        {
            _textBox = new TextBox
            {
                Margin = 5,
                Text = "Write here...",
                ForegroundColor = Color.Yellow,
                Dock = TextBoxDock,
                Width = 200
            };

            var button = new Button
            {
                Text = "Tell what I wrote?",
                Dock = ButtonDock,
                Width = 200
            };

            button.Click += Button_Click;

            var dockPanel = new DockPanel
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
            };

            dockPanel.AddChild(_textBox);
            dockPanel.AddChild(button);

            Chart.AddControl(dockPanel);
        }

        private void Button_Click(ButtonClickEventArgs obj)
        {
            obj.Button.Text = $"You wrote: {_textBox.Text}";
        }

        public override void Calculate(int index)
        {
        }
    }
}

Al crear una instancia de este indicador, debería ver un panel de acoplamiento en el centro del gráfico que contiene un campo de texto y un botón en el que se puede hacer clic.

Tenga en cuenta que los paneles de acoplamiento pueden poblarse horizontal o verticalmente. No puede utilizar ambas alineaciones al mismo tiempo. La orientación del panel de acoplamiento se establece automáticamente al configurar el primer control en un DockPanel. Si la propiedad Dock del primer control se establece en Top o Bottom, todo el DockPanel se orientará verticalmente, y viceversa.

Panel de pila

Los paneles de pila son uno de los controles más utilizados debido a su simplicidad y usabilidad. Los paneles de pila alinean los controles secundarios horizontal o verticalmente uno por uno. Como se muestra a continuación, solo tiene que configurar su orientación y la clase gestionará el resto:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
using cAlgo.API;

namespace ChartControlsTest
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ChartControls : Indicator
    {
        [Parameter(DefaultValue = Orientation.Vertical)]
        public Orientation Orientation { get; set; }

        protected override void Initialize()
        {
            var firstNameTextBox = new TextBox
            {
                Margin = 5,
                Text = "First Name...",
                Width = 200
            };

            var lastNameTextBox = new TextBox
            {
                Margin = 5,
                Text = "Last Name...",
                Width = 200
            };

            var isMarriedCheckBox = new CheckBox
            {
                Text = "Is Married?",
                Margin = 5,
            };

            var submitButton = new Button
            {
                Text = "Submit",
                Margin = 5
            };

            var stackPanel = new StackPanel
            {
                Orientation = Orientation,
                HorizontalAlignment = HorizontalAlignment.Right,
                VerticalAlignment = VerticalAlignment.Bottom,
                BackgroundColor = Color.FromArgb(80, Color.Gold),
                Margin = 20
            };

            stackPanel.AddChild(firstNameTextBox);
            stackPanel.AddChild(lastNameTextBox);
            stackPanel.AddChild(isMarriedCheckBox);
            stackPanel.AddChild(submitButton);

            Chart.AddControl(stackPanel);
        }

        public override void Calculate(int index)
        {
        }
    }
}

Después de crear una instancia del indicador, debería ver un panel de pila horizontal con dos campos de texto y un botón Enviar en la esquina inferior derecha del gráfico principal.

Panel de envoltura

Los paneles de envoltura son prácticamente idénticos a los paneles de pila. Sin embargo, cuando no hay suficiente espacio para ajustar todos los elementos de un panel de envoltura, automáticamente envolverá los controles restantes a la siguiente línea en el eje Y.

Cuadrícula

Piense en las cuadrículas como hojas de cálculo con un número determinado de columnas y filas. Al utilizar cuadrículas, puede añadir controles a cada celda separada.

Como se demuestra a continuación, cuando crea una instancia de la clase Grid, pasa el número de sus filas y columnas como argumentos integer. Al añadir nuevos hijos o controles, de manera similar tiene que especificar el número de filas y columnas secundarias.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using cAlgo.API;

namespace ChartControlsTest
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ChartControls : Indicator
    {
        [Parameter("Grid Rows #", DefaultValue = 10)]
        public int GridRowsNumber { get; set; }

        [Parameter("Grid Columns #", DefaultValue = 2)]
        public int GridColumnsNumber { get; set; }

        protected override void Initialize()
        {
            var grid = new Grid(GridRowsNumber, GridColumnsNumber)
            {
                BackgroundColor = Color.Gold,
                Opacity = 0.6,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                ShowGridLines = true
            };

            for (int iRow = 0; iRow < GridRowsNumber; iRow++)
            {
                for (int iColumn = 0; iColumn < GridColumnsNumber; iColumn++)
                {
                    grid.AddChild(new TextBlock
                    {
                        Text = string.Format("Row {0} and Column {1}", iRow, iColumn),
                        Margin = 5,
                        ForegroundColor = Color.Black,
                        FontWeight = FontWeight.ExtraBold
                    }, iRow, iColumn);
                }
            }

            Chart.AddControl(grid);
        }

        public override void Calculate(int index)
        {
        }
    }
}

Al crear una instancia del indicador anterior, debería ver una cuadrícula de 10x2 justo en el centro del gráfico.

Posicionar controles dentro de coordenadas de precio y tiempo

Además de los controles de panel, cTrader permite especificar coordenadas de precio y tiempo para los controles directamente en el área del gráfico. Los métodos AddControl() y MoveControl() proporcionan esta funcionalidad a los desarrolladores de algoritmos.

Utilice las siguientes sobrecargas de método para gestionar las coordenadas de sus controles de gráfico según sus preferencias.

Para añadir un control de gráfico al área del gráfico o indicador en coordenadas absolutas de índice de barra y precio (x, y).

1
void AddControl(ControlBase control, int barIndex, double y)

Para mover un control de gráfico al área del gráfico o indicador en coordenadas absolutas de índice de barra y precio (x, y).

1
void MoveControl(ControlBase control, int barIndex, double y)

Para añadir un control de gráfico al área del gráfico o indicador en coordenadas absolutas de tiempo y precio (x, y).

1
void AddControl(ControlBase control, DateTime time, double y)

Para mover un control de gráfico al área del gráfico o indicador en coordenadas absolutas de tiempo y precio (x, y).

1
void MoveControl(ControlBase control, DateTime time, double y)

Para añadir un control de gráfico al área del gráfico o indicador en coordenada absoluta de tiempo (x).

1
void AddControl(ControlBase control, DateTime time)

Para mover un control de gráfico al área del gráfico o indicador en coordenada absoluta de tiempo (x).

1
void MoveControl(ControlBase control, DateTime time)

Para añadir un control de gráfico al área del gráfico o indicador en coordenada absoluta de índice de barra (x).

1
void AddControl(ControlBase control, int barIndex)

Para mover un control de gráfico al área del gráfico o indicador en coordenada absoluta de índice de barra (x).

1
void MoveControl(ControlBase control, int barIndex)

Para añadir un control de gráfico al área del gráfico o indicador en coordenada absoluta de precio (y).

1
void AddControl(ControlBase control, double y)

Para mover un control de gráfico al área del gráfico o indicador en coordenada absoluta de precio (y).

1
void MoveControl(ControlBase control, double y)

La clase de parámetro ControlBase puede incluir cualquier otra clase subordinada (Control, Button, etc.) para que el método se llame de acuerdo con las firmas anteriores.

El siguiente ejemplo de cBot añade el botón ¡Haz clic aquí! encima de la última barra del gráfico. El botón se mueve hacia adelante junto con cada nueva barra añadida. Después de hacer clic en el botón, aparece un cuadro de mensaje en la pantalla.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class ButtonTest : Robot
    {
        [Parameter(DefaultValue = "Hello world!")]
        public string Message { get; set; }

        Button button;

        protected override void OnStart() 
        {
            button = new Button
            {
                Text = "Click me!"
            };

            button.Click += Button_Click;

            Chart.AddControl(button, Bars.Count - 1);
        }

        protected override void OnBar() 
        {
            Chart.MoveControl(button, Bars.Count - 1);
        }

        private void Button_Click(ButtonClickEventArgs obj)
        {
            MessageBox.Show(Message, "Title/Caption");
        }
    }
}

Advertencia

El número de controles raíz que se pueden añadir en un gráfico está limitado a 100 debido a posibles problemas de rendimiento. Esta limitación se aplica solo a una instancia de algoritmo y a los controles adjuntos a precios y barras.

Propiedades de relleno y margen

La propiedad Margin define el espacio entre los bordes de un objeto Control y su padre (un gráfico, un panel, un borde, etc.).

A su vez, la propiedad Padding determina el espacio entre el contenido del control y sus bordes. Puede variar los valores de la propiedad para que sean todos diferentes para diferentes lados.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using cAlgo.API;

namespace ChartControlsTest
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ChartControls : Indicator
    {
        [Parameter(DefaultValue = "Click Me")]
        public string Text { get; set; }

        [Parameter(DefaultValue = 0)]
        public double Left { get; set; }

        [Parameter(DefaultValue = 0)]
        public double Top { get; set; }

        [Parameter(DefaultValue = 0, Group = "Margin")]
        public double LeftMargin { get; set; }

        [Parameter(DefaultValue = 0, Group = "Margin")]
        public double TopMargin { get; set; }

        [Parameter(DefaultValue = 0, Group = "Margin")]
        public double RightMargin { get; set; }

        [Parameter(DefaultValue = 0, Group = "Margin")]
        public double BottomMargin { get; set; }

        [Parameter(DefaultValue = 5, Group = "Padding")]
        public double LeftPadding { get; set; }

        [Parameter(DefaultValue = 5, Group = "Padding")]
        public double TopPadding { get; set; }

        [Parameter(DefaultValue = 5, Group = "Padding")]
        public double RightPadding { get; set; }

        [Parameter(DefaultValue = 5, Group = "Padding")]
        public double BottomPadding { get; set; }

        protected override void Initialize()
        {
            var button = new Button
            {
                Text = Text,
                Left = Left,
                Top = Top,
                Margin = new Thickness(LeftMargin, TopMargin, RightMargin, BottomMargin),
                Padding = new Thickness(LeftPadding, TopPadding, RightPadding, BottomPadding)
            };

            button.Click += Button_Click;

            var canvas = new Canvas();

            canvas.AddChild(button);

            Chart.AddControl(canvas);
        }

        private void Button_Click(ButtonClickEventArgs obj)
        {
            obj.Button.Text = "You clicked me, thanks";
        }

        public override void Calculate(int index)
        {
        }
    }
}

Una instancia de este indicador creará un botón gris Haz clic aquí en la esquina superior izquierda del gráfico. Modifique los parámetros en las ventanas Añadir instancia o Modificar parámetros para ver exactamente cómo diferentes valores de margen y relleno cambian la forma en que se muestra el control.

Estilos

Al utilizar estilos, puede dar un aspecto similar a varios tipos diferentes de controles. Esto es particularmente útil cuando se trata de un gran número (cinco o más) de controles.

La clase Style permite establecer valores para diferentes propiedades de controles como Margin o BackgroundColor. Posteriormente, puede reutilizar estos valores como una plantilla para múltiples otros controles.

También podemos crear un aspecto consistente para múltiples controles sin utilizar la clase Style en absoluto.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using cAlgo.API;

namespace ChartControlsTest
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ChartControls : Indicator
    {
        protected override void Initialize()
        {
            var firstTextBox = new TextBox
            {
                ForegroundColor = Color.Red,
                Margin = 5,
                FontFamily = "Cambria",
                FontSize = 12,
                Text = "Type...",
                Width = 150
            };

            var secondTextBox = new TextBox
            {
                ForegroundColor = Color.Red,
                Margin = 5,
                FontFamily = "Cambria",
                FontSize = 12,
                Text = "Type...",
                Width = 150
            };

            var thirdTextBox = new TextBox
            {
                ForegroundColor = Color.Red,
                Margin = 5,
                FontFamily = "Cambria",
                FontSize = 12,
                Text = "Type...",
                Width = 150
            };

            var panel = new StackPanel
            {
                Orientation = Orientation.Vertical,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };

            panel.AddChild(firstTextBox);
            panel.AddChild(secondTextBox);
            panel.AddChild(thirdTextBox);

            Chart.AddControl(panel);
        }

        public override void Calculate(int index)
        {
        }
    }
}

Así es como el uso de la clase Style puede simplificar el trabajo con múltiples controles.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
using cAlgo.API;

namespace ChartControlsTest
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ChartControls : Indicator
    {
        protected override void Initialize()
        {
            var textBoxStyle = new Style();

            textBoxStyle.Set(ControlProperty.ForegroundColor, Color.Red);
            textBoxStyle.Set(ControlProperty.Margin, 5);
            textBoxStyle.Set(ControlProperty.FontFamily, "Cambria");
            textBoxStyle.Set(ControlProperty.FontSize, 12);
            textBoxStyle.Set(ControlProperty.Width, 150);

            var firstTextBox = new TextBox
            {
                Text = "Type...",
                Style = textBoxStyle
            };

            var secondTextBox = new TextBox
            {
                Text = "Type...",
                Style = textBoxStyle
            };

            var thirdTextBox = new TextBox
            {
                Text = "Type...",
                Style = textBoxStyle
            };

            var panel = new StackPanel
            {
                Orientation = Orientation.Vertical,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };

            panel.AddChild(firstTextBox);
            panel.AddChild(secondTextBox);
            panel.AddChild(thirdTextBox);

            Chart.AddControl(panel);
        }

        public override void Calculate(int index)
        {
        }
    }
}

Ambos fragmentos de código anteriores deberían mostrar los mismos controles si lanza sus respectivas instancias de indicador.

También puede utilizar la clase Style para cambiar la apariencia de un control basándose en su estado.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using cAlgo.API;

namespace ChartControlsTest
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ChartControls : Indicator
    {
        protected override void Initialize()
        {
            var textBoxStyle = new Style();

            textBoxStyle.Set(ControlProperty.ForegroundColor, Color.Red);
            textBoxStyle.Set(ControlProperty.Margin, 5);
            textBoxStyle.Set(ControlProperty.FontFamily, "Cambria");
            textBoxStyle.Set(ControlProperty.FontSize, 12);
            textBoxStyle.Set(ControlProperty.Width, 150);
            // Here we change the foreground color to Yellow if mouse hover over the textbox
            textBoxStyle.Set(ControlProperty.ForegroundColor, Color.Yellow, ControlState.Hover);

            var firstTextBox = new TextBox
            {
                Text = "Type...",
                Style = textBoxStyle
            };

            var secondTextBox = new TextBox
            {
                Text = "Type...",
                Style = textBoxStyle
            };

            var thirdTextBox = new TextBox
            {
                Text = "Type...",
                Style = textBoxStyle
            };

            var panel = new StackPanel
            {
                Orientation = Orientation.Vertical,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };

            panel.AddChild(firstTextBox);
            panel.AddChild(secondTextBox);
            panel.AddChild(thirdTextBox);

            Chart.AddControl(panel);
        }

        public override void Calculate(int index)
        {
        }
    }
}

Imagen

El control Image puede utilizarse para mostrar una imagen almacenada localmente. El control Image utiliza la clase Bitmap de .NET, lo que significa que admite la mayoría de los formatos de imagen populares, como los siguientes:

  • .PNG
  • .JPG
  • .BMP
  • .GIF
  • .TIFF

Consulte la documentación de la clase Bitmap de .NET para obtener más información al respecto.

Para utilizar un control Image, establezca su propiedad Source en los datos de archivo de imagen en una matriz de bytes (byte[]).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using cAlgo.API;
using System.IO;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
    public class ImageSample : Indicator
    {
        [Parameter("Image File Path")]
        public string ImageFilePath { get; set; }

        protected override void Initialize()
        {
            if (File.Exists(ImageFilePath) is false)
            {
                Print($"Image not found: {ImageFilePath}");

                return;
            }

            var imageBytes = File.ReadAllBytes(ImageFilePath);

            var image = new Image
            {
                Source = imageBytes,
                Width = 200,
                Height = 200,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };

            Chart.AddControl(image);
        }

        public override void Calculate(int index)
        {
        }
    }
}

Después de lanzar una instancia del indicador anterior, no debería ver nada nuevo en el gráfico principal. Sin embargo, introduzca una ruta de archivo válida como valor del parámetro (Ruta del archivo de imagen), y debería ver la imagen elegida mostrada en el centro de la pantalla.

También puede utilizar los recursos de su proyecto para almacenar imágenes y mostrarlas a través del control Image. Para hacerlo, abra los recursos del proyecto en Visual Studio y cambie a la pestaña Resources. En ella, cree un nuevo recurso y añada una imagen existente. Posteriormente, podrá utilizar esta imagen como fuente en cualquier control Image a través de la propiedad Project_Name_Space.Properties.Resources._Image_Name.

Como ejemplo, copie la imagen de abajo y guárdela como "image.png" en su sistema:

Image title

Cree un nuevo indicador en cTrader, establezca su nombre como "Image Sample", y ábralo a través de Visual Studio. Posteriormente, añada el indicador de logo del proyecto como un recurso. Para hacerlo, haga clic derecho en su proyecto, seleccione Properties y haga clic en Resources, luego haga clic en Create and manage assembly resources. Copie el archivo logo.png en la pestaña recién abierta.

Copie el siguiente código en el archivo de código fuente principal de su indicador:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ImageSample : Indicator
    {
        protected override void Initialize()
        {
            var image = new Image
            {
                Source = Image_Sample.Properties.Resources.logo,
                Width = 200,
                Height = 200,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };

            Chart.AddControl(image);
        }

        public override void Calculate(int index)
        {
        }
    }
}

Después de crear una instancia de este indicador, debería ver la siguiente salida.

Image title

Nota

El tamaño máximo para las imágenes es de 10 MB.