Ir para o conteúdo

Controlos

Os controlos permitem certas interações envolvendo cBots, indicadores e plugins. Usando o guia abaixo, pode criar facilmente controlos de UI básicos e avançados diretamente num gráfico.

Existem várias classes incorporadas que representam controlos populares, como botões, blocos de texto, caixas de texto e formas. No entanto, também pode criar controlos personalizados.

Considere o seguinte exemplo:

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

Se criar o indicador acima e criar uma instância, deverá ver um botão cinzento Click me no centro do gráfico.

Diferença entre controlos e objetos do gráfico

Numa secção anterior, já abordámos os objetos do gráfico. Os controlos permitem que os utilizadores interajam com cBots e indicadores. Por outro lado, os objetos do gráfico dão a oportunidade de desenhar algo no gráfico de negociação ou numa janela de saída de indicador separada.

Os controlos do gráfico derivam da classe ControlBase, enquanto os objetos do gráfico são derivados da classe ChartObject.

Os controlos do gráfico são posicionados estaticamente usando diferentes opções de alinhamento. Embora os objetos do gráfico possam ser posicionados exatamente da mesma forma, a sua posição também pode mudar dinamicamente dependendo de certas coordenadas X e Y.

De forma semelhante aos objetos do gráfico, os controlos do gráfico podem ser adicionados tanto ao gráfico principal como a quaisquer janelas de saída de indicadores (se existirem). Um exemplo desse posicionamento é dado abaixo:

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

Após criar uma instância do indicador, deverá ver um botão Click me na janela de saída do indicador.

ColorPicker

O controlo ColorPicker permite aos traders selecionar a sua cor preferida para elementos ou objetos-chave no cTrader. Por exemplo, um desenvolvedor pode integrar o controlo ColorPicker num cBot que desenha linhas de tendência para que os utilizadores possam selecionar a sua cor preferida para cada linha de tendência. Esta configuração facilita aos traders a distinção entre vários tipos de linhas de tendência.

Um plugin que adiciona indicadores aos gráficos também pode implementar o controlo ColorPicker, pois esta funcionalidade permite aos utilizadores escolher uma cor para diferentes linhas de indicadores.

Quando os utilizadores clicam no quadrado de cor, o seletor de cores aparece. Os utilizadores podem então escolher entre cores padrão e personalizadas.

Exemplo 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

O controlo DropZone permite aos traders realizar ações de arrastar e largar envolvendo cBots, indicadores ou plugins. Para implementar este controlo no seu algoritmo, utilize a classe DropZone. O controlo DropZone pode ser manipulado como qualquer outro controlo.

Quando um utilizador larga um ficheiro ou pasta compatível na caixa, o evento Dropped é gerado. Quando um utilizador larga uma pasta ou várias pastas na caixa, apenas os ficheiros compatíveis com as extensões especificadas em FilterExtensions são processados e copiados.

Nota

Os ficheiros largados são geralmente copiados e guardados nesta localização: ..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected Files\

A localização para instâncias de cBot difere da acima: ..\Documents\cAlgo\Data\cBots\{cBotName}\{unique-instance-number}\Selected files\

Este código de plugin mostra-lhe como adicionar um controlo DropZone à Observação da Negociação:

 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

O controlo ProgressBar apresenta a progressão de uma operação em curso. As barras de progresso tornam os algoritmos mais fáceis de utilizar e ajudam a gerir as expectativas dos traders em relação ao tempo de espera de certas operações.

A API cTrader Algo permite aos programadores adicionar dois tipos de controlos ProgressBar: controlo infinito e controlo determinado.

Controlo infinito

Pode querer utilizar o controlo infinito nas seguintes situações:

  • Não consegue determinar o tempo de espera de uma operação.
  • Não consegue detetar a progressão de uma operação.
  • Não quer indicar quanto tempo uma operação irá demorar.

Image title

Controlo determinado

Pode querer utilizar este controlo quando consegue determinar o tempo de espera de uma operação e quer que os utilizadores vejam um indicador baseado nesse tempo.

Para apresentar o progresso da operação, utilize a propriedade Value para definir um número. Para definir a percentagem da barra de progresso, utilize as propriedades Minimum e Maximum.

Image title

O código de plugin abaixo mostra-lhe como criar uma barra de progresso utilizando controlos infinitos e 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 e OpenFolderDialog

A API cTrader Algo fornece a interface OpenFileDialog para permitir que os utilizadores selecionem um ficheiro para um algoritmo. Quando um utilizador seleciona um ficheiro na janela resultante, o ficheiro é copiado para a pasta Selected files do algoritmo. Um algoritmo pode trabalhar com ficheiros dentro da sua pasta Selected files sem restrições.

Dica

Utilize a funcionalidade OpenFileDialog quando precisar de carregar ficheiros de dados importantes, ficheiros de backup ou configuração, indicadores personalizados ou scripts.

O código abaixo mostra-lhe como utilizar o diálogo OpenFileDialog num 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

A API cTrader Algo fornece a interface OpenFolderDialog para permitir que os utilizadores especifiquem uma pasta para um algoritmo. Quando um utilizador seleciona uma pasta na janela resultante, todos os ficheiros e pastas com ficheiros dentro da pasta selecionada são copiados para a pasta Selected files do algoritmo.

Dica

Utilize a funcionalidade OpenFolderDialog quando precisar de carregar uma pasta contendo ficheiros de dados críticos, ficheiros de backup ou configuração, indicadores personalizados ou scripts.

Os ficheiros e pastas selecionados são geralmente copiados para a pasta Selected files porque um algoritmo pode trabalhar com itens dentro dessa pasta mesmo quando o seu AccessRights está definido como None.

Nota

A pasta Selected files de um algoritmo está geralmente neste caminho: ..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected files\

A pasta Selected files para uma instância de cBot difere da acima: ..\Documents\cAlgo\Data\cBots\{cBotName}\{Instance-Id}\Selected files\

O código abaixo mostra-lhe como utilizar o diálogo OpenFolderDialog num 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

A API cTrader Algo fornece a interface SaveFileDialog para permitir que os utilizadores guardem ficheiros (localmente) nos seus computadores. Quando a janela relevante aparece, um utilizador seleciona a pasta onde quer guardar o ficheiro e introduz um nome para o ficheiro. O ficheiro é então guardado na localização especificada.

Dica

Utilize a funcionalidade SaveFileDialog quando precisar de fazer qualquer uma das seguintes ações:

  • Guardar relatórios de desempenho, resultados de testes de verificação, ficheiros de configuração ou dados de otimização.
  • Exportar registos de negociação, diários de operações ou dados gerais de atividade do utilizador.
  • Armazenar indicadores personalizados, dados para gráficos e visualizações ou parâmetros para uma estratégia.

O código abaixo mostra-lhe como utilizar o diálogo SaveFileDialog num 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)
        {
        }
    }
}

Controlos arrastáveis

Controlo arrastável da área do gráfico

As interfaces ChartDraggable e ChartDraggables fornecem tipos que permitem adicionar um controlo arrastável capaz de alojar outros controlos e diferentes elementos a um gráfico. Estes controlos arrastáveis facilitam a interação dos utilizadores com vários elementos do gráfico.

Nota

Um controlo arrastável só pode ser movido ou reposicionado dentro do gráfico onde foi adicionado.

Este código mostra-lhe como criar um indicador que adiciona dois controlos que podem ser movidos dentro de um 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})");
        }
    }
}

Controlo arrastável da janela da aplicação

As interfaces ApplicationDraggable e ApplicationDraggables fornecem os tipos utilizados para adicionar controlos flutuantes que podem ser movidos individualmente por toda a janela da aplicação cTrader. Tais controlos permitem-lhe criar interfaces de utilizador interativas e dinâmicas.

Nota

Dos três tipos de algoritmos, apenas os plugins têm permissão para implementar controlos arrastáveis em toda a aplicação.

Este código mostra-lhe como criar um plugin que adiciona um componente WebView e um bloco de texto em duas janelas separadas, que podem ser movidas por toda a interface do 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;
        }
    }
}

Controlo de separadores

A classe TabControl fornece tipos que permitem criar vários separadores para um algoritmo. Estes separadores podem ser utilizados para manter elementos relacionados juntos ou apresentar vistas separadas para funcionalidades.

Este código mostra-lhe como utilizar separadores num plugin adicionado ao Painel de símbolo ativo:

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

Controlos personalizados

Um controlo personalizado é um controlo que é, essencialmente, construído a partir de vários controlos pré-definidos. Por outras palavras, é um controlo para o qual outros controlos constituem o seu conteúdo.

Os controlos personalizados atuam como classes reutilizáveis, de forma semelhante aos controlos 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);
        }
    }
}

Uma instância deste indicador deve apresentar quatro caixas de texto diretamente no centro do gráfico principal.

Organizar controlos com painéis

Para tornar o trabalho com controlos mais conveniente, poderá querer colocar vários controlos num grupo distinto com a sua própria posição na interface do utilizador. Para fazer isto, pode utilizar a classe Panels e os seus derivados.

Pense num painel como um controlo com outros controlos como o seu conteúdo. O cTrader suporta cinco classes diferentes que herdam da classe base Panels (que por sua vez herda da classe Control):

  • Canvas
  • DockPanel
  • Grid
  • StackPanel
  • WrapPanel

Cada uma das classes acima utiliza diferentes layouts de painel e estratégias de posicionamento, como discutido abaixo.

Canvas

O canvas é um painel que permite o posicionamento de controlos com base em determinadas coordenadas X e Y.

Notavelmente, os eixos X e Y são diferentes dos utilizados por objetos de gráfico ou desenhos. As coordenadas X e Y utilizadas pela classe Canvas representam valores numéricos começando em (0, 0) a partir do canto superior esquerdo do gráfico.

Considere o seguinte exemplo:

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

Ao criar uma instância do indicador acima, deverá ver o botão Click me no canto superior esquerdo do gráfico.

A propriedade Top de um controlo determina o seu posicionamento no eixo Y. Por sua vez, a propriedade Left define o seu posicionamento no eixo X.

O código acima também utiliza as propriedades Padding e Margin. Padding refere-se à distância entre o conteúdo do controlo e as suas bordas exteriores. Margin é a distância entre o controlo e as bordas do seu pai. As propriedades Padding e Margin são aplicáveis a todos os painéis, não apenas à classe canvas. São úteis para gerir o espaçamento entre os seus controlos.

Na maioria dos casos, a classe Canvas é utilizada para agrupar apenas um pequeno número de controlos.

Painel de ancoragem

A classe DockPanel é utilizada para ancorar (colocar) um controlo numa localização estática no gráfico. Existem quatro posições de ancoragem possíveis:

  • Topo
  • Fundo
  • Esquerda
  • Direita

Cada controlo tem uma propriedade Dock. Ao utilizar a classe DockPanel, pode usar esta propriedade para posicionar um controlo dentro de um DockPanel. Isto é ilustrado no seguinte exemplo:

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

Ao criar uma instância deste indicador, deverá ver um painel de ancoragem no centro do gráfico contendo um campo de texto e um botão clicável.

Note que os painéis de ancoragem podem ser preenchidos horizontal ou verticalmente. Não pode utilizar ambos estes alinhamentos ao mesmo tempo. A orientação do painel de ancoragem é definida automaticamente ao configurar o primeiro controlo num DockPanel. Se a propriedade Dock do primeiro controlo for definida como Top ou Bottom, todo o DockPanel será orientado verticalmente, e vice-versa.

Painel de pilha

Os painéis de pilha são um dos controlos mais frequentemente utilizados devido à sua simplicidade e usabilidade. Os painéis de pilha alinham os controlos filhos horizontal ou verticalmente, um a um. Como mostrado abaixo, só tem de definir a sua orientação e a classe irá gerir o 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)
        {
        }
    }
}

Após criar uma instância do indicador, deverá ver um painel de pilha horizontal com dois campos de texto e um botão 'Submit' no canto inferior direito do gráfico principal.

Painel de envolvimento

Os painéis de envolvimento são maioritariamente idênticos aos painéis de pilha. No entanto, quando não há espaço suficiente para acomodar todos os elementos de um painel de envolvimento, este irá automaticamente envolver os controlos restantes para a linha seguinte no eixo Y.

Grelha

Pense nas grelhas como folhas de cálculo com um número definido de colunas e linhas. Ao utilizar grelhas, pode adicionar controlos a cada célula separada.

Como demonstrado abaixo, quando cria uma instância da classe Grid, passa o número das suas linhas e colunas como argumentos integer. Ao adicionar novos filhos ou controlos, tem de especificar de forma semelhante o número de linhas e colunas filhas.

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

Ao criar uma instância do indicador acima, deverá ver uma grelha 10x2 mesmo no centro do gráfico.

Controlos de posição dentro das coordenadas de preço e tempo

Além dos controlos do painel, o cTrader permite especificar coordenadas de preço e tempo para controlos diretamente na área do gráfico. Os métodos AddControl() e MoveControl() fornecem aos desenvolvedores de algoritmos esta funcionalidade.

Utilize as seguintes sobrecargas de método para gerir as coordenadas dos seus controlos de gráfico de acordo com as suas preferências.

Para adicionar um controlo de gráfico à área do gráfico ou do indicador em coordenadas absolutas de índice de barra e preço (x, y).

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

Para mover um controlo de gráfico para a área do gráfico ou do indicador em coordenadas absolutas de índice de barra e preço (x, y).

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

Para adicionar um controlo de gráfico à área do gráfico ou do indicador em coordenadas absolutas de tempo e preço (x, y).

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

Para mover um controlo de gráfico para a área do gráfico ou do indicador em coordenadas absolutas de tempo e preço (x, y).

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

Para adicionar um controlo de gráfico à área do gráfico ou do indicador na coordenada absoluta de tempo (x).

1
void AddControl(ControlBase control, DateTime time)

Para mover um controlo de gráfico para a área do gráfico ou do indicador na coordenada absoluta de tempo (x).

1
void MoveControl(ControlBase control, DateTime time)

Para adicionar um controlo de gráfico à área do gráfico ou do indicador na coordenada absoluta de índice de barra (x).

1
void AddControl(ControlBase control, int barIndex)

Para mover um controlo de gráfico para a área do gráfico ou do indicador na coordenada absoluta de índice de barra (x).

1
void MoveControl(ControlBase control, int barIndex)

Para adicionar um controlo de gráfico à área do gráfico ou do indicador na coordenada absoluta de preço (y).

1
void AddControl(ControlBase control, double y)

Para mover um controlo de gráfico para a área do gráfico ou do indicador na coordenada absoluta de preço (y).

1
void MoveControl(ControlBase control, double y)

O parâmetro da classe ControlBase pode incluir qualquer outra classe subordinada (Control, Button, etc.) para que o método seja chamado de acordo com as assinaturas acima.

O seguinte exemplo de cBot adiciona o botão Clique-me! acima da última barra no gráfico. O botão é movido para a frente juntamente com cada nova barra adicionada. Após clicar no botão, aparece uma caixa de mensagem no ecrã.

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

Aviso

O número de controlos raiz a serem adicionados num gráfico é limitado a 100 devido a possíveis problemas de desempenho. Esta limitação aplica-se apenas a uma instância de algoritmo e controlos anexados ao preço e barras.

Propriedades de preenchimento e margem

A propriedade Margin define o espaço entre as bordas de um objeto Control e o seu pai (um gráfico, um painel, uma borda, etc.).

Por sua vez, a propriedade Padding determina o espaço entre o conteúdo do controlo e as suas bordas. Pode variar os valores da propriedade para que sejam todos diferentes para lados diferentes.

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

Uma instância deste indicador irá criar um botão cinzento Clique-me no canto superior esquerdo do gráfico. Modifique os parâmetros nas janelas Adicionar instância ou Modificar parâmetros para ver exatamente como diferentes valores de margem e preenchimento alteram a forma como o controlo é exibido.

Estilos

Ao usar estilos, pode dar uma aparência semelhante a vários tipos diferentes de controlos. Isto é particularmente útil quando se lida com um grande número (cinco ou mais) de controlos.

A classe Style permite definir valores para diferentes propriedades de controlos, como Margin ou BackgroundColor. Posteriormente, pode reutilizar estes valores como um modelo para vários outros controlos.

Também podemos criar uma aparência consistente para vários controlos sem usar a classe Style de todo.

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

Aqui está como usar a classe Style pode simplificar o trabalho com vários controlos.

 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 os trechos de código acima devem exibir os mesmos controlos se lançar as suas respetivas instâncias de indicador.

Também pode usar a classe Style para alterar a aparência de um controlo com base no seu 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)
        {
        }
    }
}

Imagem

O controlo Image pode ser usado para exibir uma imagem armazenada localmente. O controlo Image usa a classe Bitmap .NET, o que significa que suporta a maioria dos formatos de imagem populares, tais como os seguintes:

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

Consulte a documentação da classe Bitmap .NET para saber mais sobre ela.

Para usar um controlo Image, defina a sua propriedade Source para os dados do ficheiro de imagem num array 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)
        {
        }
    }
}

Após lançar uma instância do indicador acima, não deverá ver nada de novo no gráfico principal. No entanto, insira um caminho de ficheiro válido como valor do parâmetro (Caminho do Ficheiro de Imagem), e deverá ver a imagem escolhida exibida no centro do ecrã.

Também pode usar os recursos do seu projeto para armazenar imagens e exibi-las através do controlo Image. Para fazer isso, abra os recursos do projeto no Visual Studio e mude para a aba Resources. Nela, crie um novo recurso e adicione uma imagem existente. Depois, poderá usar esta imagem como fonte em qualquer controlo Image através da propriedade Project_Name_Space.Properties.Resources._Image_Name.

Como exemplo, copie a imagem abaixo e guarde-a como "image.png" no seu sistema:

Image title

Crie um novo indicador no cTrader, defina o seu nome como "Image Sample", e abra-o através do Visual Studio. Depois, adicione o indicador de logótipo ao projeto como um recurso. Para fazer isso, clique com o botão direito no seu projeto, selecione Properties e clique em Resources, depois clique em Create and manage assembly resources. Copie o ficheiro logo.png para a aba recém-aberta.

Copie o código abaixo para o ficheiro de código-fonte principal do seu 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)
        {
        }
    }
}

Após criar uma instância deste indicador, deverá ver o seguinte resultado.

Image title

Nota

O tamanho máximo para imagens é de 10 MB.