Aller au contenu

Contrôles

Les contrôles permettent certaines interactions impliquant des cBots, des indicateurs et des plug-ins. En utilisant le guide ci-dessous, vous pouvez facilement créer des contrôles d'interface utilisateur de base et avancés directement sur un graphique.

Il existe plusieurs classes intégrées qui représentent des contrôles populaires tels que des boutons, des blocs de texte, des zones de texte et des formes. Cependant, vous pouvez également créer des contrôles personnalisés.

Considérez l'exemple suivant:

 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 vous créez l'indicateur ci-dessus et créez une instance, vous devriez voir un bouton gris Cliquez-moi au centre du graphique.

Différence entre les contrôles et les objets graphiques

Dans une section précédente, nous avons déjà couvert les objets graphiques. Les contrôles permettent aux utilisateurs d'interagir avec les cBots et les indicateurs. À l'inverse, les objets graphiques donnent la possibilité de dessiner quelque chose sur le graphique de trading ou dans une fenêtre de sortie d'indicateur détachée.

Les contrôles graphiques dérivent de la classe ControlBase tandis que les objets graphiques sont dérivés de la classe ChartObject.

Les contrôles graphiques sont positionnés de manière statique en utilisant différentes options d'alignement. Bien que les objets graphiques puissent être positionnés exactement de la même manière, leur position peut également changer dynamiquement en fonction de certaines coordonnées X et Y.

De même que les objets graphiques, les contrôles graphiques peuvent être ajoutés à la fois au graphique principal et à toutes les fenêtres de sortie d'indicateur (si elles existent). Un exemple d'un tel positionnement est donné ci-dessous :

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

Après avoir créé une instance d'indicateur, vous devriez voir un bouton Cliquez-moi dans la fenêtre de sortie de l'indicateur.

ColorPicker

Le contrôle ColorPicker permet aux traders de sélectionner leur couleur préférée pour les éléments ou objets clés dans cTrader. Par exemple, un développeur peut intégrer le contrôle ColorPicker dans un cBot qui dessine des lignes de tendance afin que les utilisateurs puissent sélectionner leur couleur préférée pour chaque ligne de tendance. Cette configuration permet aux traders de distinguer plus facilement les différents types de lignes de tendance.

Un plug-in qui ajoute des indicateurs aux graphiques peut également implémenter le contrôle ColorPicker car cette fonctionnalité permet aux utilisateurs de choisir une couleur pour différentes lignes d'indicateur.

Lorsque les utilisateurs cliquent sur le carré de couleur, le sélecteur de couleur apparaît. Les utilisateurs peuvent ensuite choisir entre des couleurs standard et des couleurs personnalisées.

Exemple de code :

 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

Le contrôle DropZone permet aux traders d'effectuer des actions de glisser-déposer impliquant des cBots, des indicateurs ou des plug-ins. Pour implémenter ce contrôle dans votre algorithme, utilisez la classe DropZone. Le contrôle DropZone peut être manipulé comme n'importe quel autre contrôle.

Lorsqu'un utilisateur dépose un fichier ou un dossier compatible dans la zone, l'événement Dropped est généré. Lorsqu'un utilisateur dépose un dossier ou plusieurs dossiers dans la zone, seuls les fichiers compatibles avec les extensions spécifiées dans FilterExtensions sont traités et copiés.

Remarque

Les fichiers déposés sont généralement copiés et enregistrés à cet emplacement : ..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected Files\

L'emplacement pour les instances de cBot diffère de ce qui précède : ..\Documents\cAlgo\Data\cBots\{cBotName}\{unique-instance-number}\Selected files\

Ce code de plug-in vous montre comment ajouter un contrôle DropZone à Visualisation des trades :

 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

Le contrôle ProgressBar affiche la progression d'une opération en cours. Les barres de progression rendent les algorithmes plus conviviaux et aident à gérer les attentes des traders concernant le temps d'attente pour certaines opérations.

L'API cTrader Algo permet aux développeurs d'ajouter deux types de contrôles ProgressBar : le contrôle infini et le contrôle déterminé.

Contrôle infini

Vous pouvez utiliser le contrôle infini dans les situations suivantes :

  • Vous ne pouvez pas déterminer le temps d'attente pour une opération.
  • Vous ne pouvez pas détecter la progression d'une opération.
  • Vous ne souhaitez pas indiquer combien de temps durera une opération.

Image title

Contrôle déterminé

Vous pouvez utiliser ce contrôle lorsque vous pouvez déterminer le temps d'attente pour une opération et que vous souhaitez que les utilisateurs voient un indicateur basé sur ce temps.

Pour afficher la progression de l'opération, utilisez la propriété Value pour définir une valeur. Pour définir le pourcentage de la barre de progression, utilisez les propriétés Minimum et Maximum.

Image title

Le code de plug-in ci-dessous vous montre comment créer une barre de progression en utilisant à la fois des contrôles infinis et déterminés (verts) :

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

Dialogues

OpenFileDialog et OpenFolderDialog

L'API cTrader Algo fournit l'interface OpenFileDialog pour permettre aux utilisateurs de sélectionner un fichier pour un algorithme. Lorsqu'un utilisateur sélectionne un fichier dans la fenêtre résultante, le fichier est copié dans le dossier Selected files de l'algorithme. Un algorithme peut travailler avec des fichiers à l'intérieur de son dossier Selected files sans restrictions.

Astuce

Utilisez la fonctionnalité OpenFileDialog lorsque vous devez charger des fichiers de données importants, des fichiers de sauvegarde ou de configuration, des indicateurs personnalisés ou des scripts.

Le code ci-dessous vous montre comment utiliser le dialogue OpenFileDialog dans un indicateur :

 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

L'API cTrader Algo fournit l'interface OpenFolderDialog pour permettre aux utilisateurs de spécifier un dossier pour un algorithme. Lorsqu'un utilisateur sélectionne un dossier dans la fenêtre résultante, tous les fichiers et dossiers contenant des fichiers à l'intérieur du dossier sélectionné sont copiés dans le dossier Selected files de l'algorithme.

Astuce

Utilisez la fonctionnalité OpenFolderDialog lorsque vous devez charger un dossier contenant des fichiers de données critiques, des fichiers de sauvegarde ou de configuration, des indicateurs personnalisés ou des scripts.

Les fichiers et dossiers sélectionnés sont généralement copiés dans le dossier Selected files car un algorithme peut travailler avec des éléments à l'intérieur de ce dossier même lorsque son AccessRights est défini sur None.

Remarque

Le dossier Selected files d'un algorithme se trouve généralement sur ce chemin : ..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected files\

Le dossier Selected files pour une instance de cBot diffère de ce qui précède : ..\Documents\cAlgo\Data\cBots\{cBotName}\{Instance-Id}\Selected files\

Le code ci-dessous vous montre comment utiliser le dialogue OpenFolderDialog dans un indicateur :

 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

L'API cTrader Algo fournit l'interface SaveFileDialog pour permettre aux utilisateurs d'enregistrer des fichiers (localement) sur leurs ordinateurs. Lorsque la fenêtre correspondante apparaît, un utilisateur sélectionne le dossier dans lequel il souhaite enregistrer le fichier et saisit un nom pour le fichier. Le fichier est ensuite enregistré à l'emplacement spécifié.

Astuce

Utilisez la fonctionnalité SaveFileDialog lorsque vous devez effectuer l'une des opérations suivantes :

  • Enregistrer des rapports de performance, des résultats de backtesting, des fichiers de configuration ou des données d'optimisation.
  • Exporter des journaux de trading, des journaux d'opérations ou des données générales d'activité utilisateur.
  • Stocker des indicateurs personnalisés, des données pour les graphiques et les visualisations ou des paramètres pour une stratégie.

Le code ci-dessous vous montre comment utiliser le dialogue SaveFileDialog dans un indicateur :

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

Contrôles déplaçables

Contrôle déplaçable de la zone graphique

Les interfaces ChartDraggable et ChartDraggables fournissent des types qui vous permettent d'ajouter un contrôle déplaçable capable d'héberger d'autres contrôles et différents éléments à un graphique. Ces contrôles déplaçables facilitent l'interaction des utilisateurs avec divers éléments du graphique.

Remarque

Un contrôle déplaçable ne peut être déplacé ou repositionné que dans le graphique où il a été ajouté.

Ce code vous montre comment créer un indicateur qui ajoute deux contrôles pouvant être déplacés dans un graphique :

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

Contrôle déplaçable de la fenêtre d'application

Les interfaces ApplicationDraggable et ApplicationDraggables fournissent les types utilisés pour ajouter des contrôles flottants qui peuvent être déplacés individuellement dans toute la fenêtre d'application cTrader. Ces contrôles vous permettent de créer des interfaces utilisateur interactives et dynamiques.

Remarque

Parmi les trois types d'algorithmes, seuls les plug-ins sont autorisés à implémenter des contrôles déplaçables à l'échelle de l'application.

Ce code vous montre comment créer un plug-in qui ajoute un composant WebView et un bloc de texte dans deux fenêtres distinctes, qui peuvent être déplacées dans toute l'interface utilisateur 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;
        }
    }
}

Contrôle d'onglet

La classe TabControl fournit des types qui vous permettent de créer plusieurs onglets pour un algorithme. Ces onglets peuvent être utilisés pour regrouper des éléments connexes ou présenter des vues distinctes pour les fonctionnalités.

Ce code vous montre comment utiliser des onglets dans un plug-in ajouté au Panneau de symbole actif :

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

Contrôles personnalisés

Un contrôle personnalisé est un contrôle qui est, en substance, construit à partir de plusieurs contrôles prédéfinis. En d'autres termes, c'est un contrôle pour lequel d'autres contrôles constituent son contenu.

Les contrôles personnalisés agissent comme des classes réutilisables de la même manière que les contrôles intégrés.

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

Une instance de cet indicateur devrait afficher quatre zones de texte directement au centre du graphique principal.

Organisez les contrôles avec des panneaux

Pour rendre le travail avec les contrôles plus pratique, vous pouvez placer plusieurs contrôles dans un groupe distinct avec sa propre position dans l'interface utilisateur. Pour ce faire, vous pouvez utiliser la classe Panels et ses dérivés.

Considérez un panneau comme un contrôle avec d'autres contrôles comme contenu. cTrader prend en charge cinq classes différentes héritant de la classe de base Panels (qui elle-même hérite de la classe Control) :

  • Canvas
  • DockPanel
  • Grid
  • StackPanel
  • WrapPanel

Chacune des classes ci-dessus utilise différentes mises en page de panneaux et stratégies de positionnement comme discuté ci-dessous.

Canvas

Le canvas est un panneau qui permet de positionner les contrôles en fonction de certaines coordonnées X et Y.

Notamment, les axes X et Y sont différents de ceux utilisés par les objets graphiques ou les dessins. Les coordonnées X et Y utilisées par la classe Canvas représentent des valeurs numériques commençant à partir de (0, 0) depuis le coin supérieur gauche du graphique.

Considérez l'exemple suivant:

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

Lors de la création d'une instance de l'indicateur ci-dessus, vous devriez voir le bouton Cliquez-moi dans le coin supérieur gauche du graphique.

La propriété Top d'un contrôle détermine son positionnement sur l'axe Y. À son tour, la propriété Left définit son positionnement sur l'axe X.

Le code ci-dessus utilise également les propriétés Padding et Margin. Padding fait référence à la distance entre le contenu du contrôle et ses bordures extérieures. Margin est la distance entre le contrôle et les bordures de son parent. Les propriétés Padding et Margin sont applicables à tous les panneaux, pas seulement à la classe canvas. Elles sont utiles pour gérer l'espacement entre vos contrôles.

Dans la majorité des cas, la classe Canvas est utilisée pour regrouper seulement un petit nombre de contrôles.

Panneau d'ancrage

La classe DockPanel est utilisée pour ancrer (placer) une commande dans un emplacement statique sur le graphique. Il existe quatre positions d'ancrage possibles :

  • En haut
  • En bas
  • Gauche
  • Droite

Chaque commande possède une propriété Dock. Lorsque vous utilisez la classe DockPanel, vous pouvez utiliser cette propriété pour positionner une commande à l'intérieur d'un DockPanel. Ceci est illustré dans l'exemple suivant :

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

Lors de la création d'une instance de cet indicateur, vous devriez voir un panneau d'ancrage au centre du graphique contenant un champ de texte et un bouton cliquable.

Notez que les panneaux d'ancrage peuvent être remplis horizontalement ou verticalement. Vous ne pouvez pas utiliser ces deux alignements en même temps. L'orientation du panneau d'ancrage est définie automatiquement lors de la configuration de la première commande dans un DockPanel. Si la propriété Dock de la première commande est définie sur Top ou Bottom, l'ensemble du DockPanel sera orienté verticalement, et vice versa.

Panneau de pile

Les panneaux de pile sont l'une des commandes les plus fréquemment utilisées en raison de leur simplicité et de leur facilité d'utilisation. Les panneaux de pile alignent les commandes enfants horizontalement ou verticalement une par une. Comme indiqué ci-dessous, il vous suffit de définir son orientation et la classe gérera le reste :

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

Après avoir créé une instance d'indicateur, vous devriez voir un panneau de pile horizontal avec deux champs de texte et un bouton Soumettre dans le coin inférieur droit du graphique principal.

Panneau d'habillage

Les panneaux d'habillage sont pour la plupart identiques aux panneaux de pile. Cependant, lorsqu'il n'y a pas assez d'espace pour contenir tous les éléments d'un panneau d'habillage, il enveloppera automatiquement les commandes restantes à la ligne suivante sur l'axe Y.

Grille

Considérez les grilles comme des feuilles de calcul avec un nombre défini de colonnes et de lignes. Lorsque vous utilisez des grilles, vous pouvez ajouter des commandes à chaque cellule séparée.

Comme démontré ci-dessous, lorsque vous créez une instance de la classe Grid, vous transmettez le nombre de ses lignes et colonnes en tant qu'arguments integer. Lors de l'ajout de nouveaux enfants ou commandes, vous devez également spécifier le nombre de lignes et de colonnes enfants.

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

Lors de la création d'une instance de l'indicateur ci-dessus, vous devriez voir une grille 10x2 en plein centre du graphique.

Positionner les commandes dans les coordonnées de prix et de temps

En plus des commandes de panneau, cTrader permet de spécifier les coordonnées de prix et de temps pour les commandes directement dans la zone graphique. Les méthodes AddControl() et MoveControl() offrent cette fonctionnalité aux développeurs d'algorithmes.

Utilisez les surcharges de méthode suivantes pour gérer les coordonnées de vos commandes graphiques en fonction de vos préférences.

Pour ajouter une commande graphique à la zone graphique ou d'indicateur sur les coordonnées (x, y) d'index de barre absolu et de prix.

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

Pour déplacer une commande graphique vers la zone graphique ou d'indicateur sur les coordonnées (x, y) d'index de barre absolu et de prix.

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

Pour ajouter une commande graphique à la zone graphique ou d'indicateur sur les coordonnées (x, y) de temps absolu et de prix.

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

Pour déplacer une commande graphique vers la zone graphique ou d'indicateur sur les coordonnées (x, y) de temps absolu et de prix.

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

Pour ajouter une commande graphique à la zone graphique ou d'indicateur sur la coordonnée de temps absolu (x).

1
void AddControl(ControlBase control, DateTime time)

Pour déplacer une commande graphique vers la zone graphique ou d'indicateur sur la coordonnée de temps absolu (x).

1
void MoveControl(ControlBase control, DateTime time)

Pour ajouter une commande graphique à la zone graphique ou d'indicateur sur la coordonnée d'index de barre absolu (x).

1
void AddControl(ControlBase control, int barIndex)

Pour déplacer une commande graphique vers la zone graphique ou d'indicateur sur la coordonnée d'index de barre absolu (x).

1
void MoveControl(ControlBase control, int barIndex)

Pour ajouter une commande graphique à la zone graphique ou d'indicateur sur la coordonnée de prix absolu (y).

1
void AddControl(ControlBase control, double y)

Pour déplacer une commande graphique vers la zone graphique ou d'indicateur sur la coordonnée de prix absolu (y).

1
void MoveControl(ControlBase control, double y)

La classe de paramètre ControlBase peut inclure toute autre classe subordonnée (Control, Button, etc.) pour que la méthode soit appelée conformément aux signatures ci-dessus.

L'exemple de cBot suivant ajoute le bouton Cliquez-moi ! au-dessus de la dernière barre sur le graphique. Le bouton est déplacé en avant avec chaque nouvelle barre ajoutée. Après avoir cliqué sur le bouton, une boîte de message apparaît à l'écran.

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

Avertissement

Le nombre de commandes racines à ajouter sur un graphique est limité à 100 en raison de problèmes de performances possibles. Cette limitation s'applique uniquement à une instance d'algorithme et aux commandes attachées au prix et aux barres.

Propriétés de remplissage et de marge

La propriété Margin définit l'espace entre les bordures d'un objet Control et son parent (un graphique, un panneau, une bordure, etc.).

À son tour, la propriété Padding détermine l'espace entre le contenu de la commande et ses bordures. Vous pouvez faire varier les valeurs de propriété afin qu'elles soient toutes différentes pour différents côtés.

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

Une instance de cet indicateur créera un bouton gris Cliquez-moi dans le coin supérieur gauche du graphique. Modifiez les paramètres dans les fenêtres Ajouter une instance ou Modifier les paramètres pour voir exactement comment différentes valeurs de marge et de remplissage modifient l'affichage de la commande.

Styles

Lorsque vous utilisez des styles, vous pouvez donner un aspect similaire à plusieurs types de commandes différents. Ceci est particulièrement utile lorsque vous traitez un grand nombre (cinq ou plus) de commandes.

La classe Style permet de définir des valeurs pour différentes propriétés de commandes telles que Margin ou BackgroundColor. Par la suite, vous pouvez réutiliser ces valeurs comme modèle pour plusieurs autres commandes.

Nous pouvons également créer un aspect cohérent pour plusieurs commandes sans utiliser du tout la classe Style.

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

Voici comment l'utilisation de la classe Style peut simplifier le travail avec plusieurs commandes.

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

Les deux extraits de code ci-dessus devraient afficher les mêmes commandes si vous lancez leurs instances d'indicateur respectives.

Vous pouvez également utiliser la classe Style pour modifier l'apparence d'une commande en fonction de son état.

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

Image

La commande Image peut être utilisée pour afficher une image stockée localement. La commande Image utilise la classe .NET Bitmap, ce qui signifie qu'elle prend en charge la majorité des formats d'image populaires tels que les suivants :

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

Consultez la documentation de la classe .NET Bitmap pour en savoir plus à ce sujet.

Pour utiliser une commande Image, définissez sa propriété Source sur les données d'un fichier image dans un tableau d'octets (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)
        {
        }
    }
}

Après avoir lancé une instance de l'indicateur ci-dessus, vous ne devriez rien voir de nouveau sur le graphique principal. Cependant, saisissez un chemin de fichier valide comme valeur du paramètre (Chemin du fichier image), et vous devriez voir l'image choisie affichée au centre de l'écran.

Vous pouvez également utiliser les ressources de votre projet pour stocker des images et les afficher via la commande Image. Pour ce faire, ouvrez les ressources du projet dans Visual Studio et basculez vers l'onglet Ressources. Dans celui-ci, créez une nouvelle ressource et ajoutez une image existante. Ensuite, vous pourrez utiliser cette image comme source dans n'importe quel contrôle Image via la propriété Project_Name_Space.Properties.Resources._Image_Name.

À titre d'exemple, copiez l'image ci-dessous et enregistrez-la sous le nom "image.png" sur votre système :

Image title

Créez un nouvel indicateur dans cTrader, définissez son nom sur "Image Sample" et ouvrez-le via Visual Studio. Ensuite, ajoutez le projet d'indicateur de logo en tant que ressource. Pour ce faire, faites un clic droit sur votre projet, sélectionnez Propriétés et cliquez sur Ressources, puis cliquez sur Créer et gérer les ressources d'assembly. Copiez le fichier logo.png dans l'onglet nouvellement ouvert.

Copiez le code ci-dessous dans le fichier de code source principal de votre indicateur :

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

Après avoir créé une instance de cet indicateur, vous devriez voir le résultat suivant.

Image title

Remarque

La taille maximale des images est de 10 Mo.