Przejdź do treści

Kontrolki

Kontrolki umożliwiają pewne interakcje z udziałem cBotów, wskaźników i wtyczek. Korzystając z poniższego przewodnika, możesz łatwo tworzyć podstawowe i zaawansowane kontrolki interfejsu użytkownika bezpośrednio na wykresie.

Istnieje kilka wbudowanych klas reprezentujących popularne kontrolki, takie jak przyciski, bloki tekstowe, pola tekstowe i kształty. Możesz jednak również tworzyć kontrolki niestandardowe.

Rozważmy następujący przykład:

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

Jeśli zbudujesz powyższy wskaźnik i utworzysz instancję, powinieneś zobaczyć szary przycisk Kliknij mnie dokładnie na środku wykresu.

Różnica między kontrolkami a obiektami wykresu

We wcześniejszej sekcji omówiliśmy już obiekty wykresu. Kontrolki umożliwiają użytkownikom interakcję z cBotami i wskaźnikami. Z kolei obiekty wykresu dają możliwość narysowania czegoś na wykresie handlowym lub w odłączonym oknie wyjściowym wskaźnika.

Kontrolki wykresu pochodzą z klasy ControlBase, podczas gdy obiekty wykresu pochodzą z klasy ChartObject.

Kontrolki wykresu są pozycjonowane statycznie przy użyciu różnych opcji wyrównania. Chociaż obiekty wykresu mogą być pozycjonowane dokładnie w ten sam sposób, ich pozycja może również zmieniać się dynamicznie w zależności od określonych współrzędnych X i Y.

Podobnie jak obiekty wykresu, kontrolki wykresu mogą być dodawane zarówno do głównego wykresu, jak i do dowolnych okien wyjściowych wskaźnika (jeśli istnieją). Przykład takiego pozycjonowania podano poniżej:

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

Po utworzeniu instancji wskaźnika powinieneś zobaczyć przycisk Kliknij mnie w oknie wyjściowym wskaźnika.

ColorPicker

Kontrolka ColorPicker umożliwia traderom wybór preferowanego koloru dla kluczowych elementów lub obiektów w cTrader. Na przykład programista może zintegrować kontrolkę ColorPicker z cBotem, który rysuje linie trendu, aby użytkownicy mogli wybrać preferowany kolor dla każdej linii trendu. Takie rozwiązanie ułatwia traderom rozróżnianie między różnymi typami linii trendu.

Wtyczka dodająca wskaźniki do wykresów może również implementować kontrolkę ColorPicker, ponieważ ta funkcja pozwala użytkownikom wybrać kolor dla różnych linii wskaźnika.

Gdy użytkownicy klikną kwadrat koloru, pojawia się selektor kolorów. Użytkownicy mogą następnie wybierać między kolorami standardowymi a niestandardowymi.

Przykład kodu:

 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

Kontrolka DropZone umożliwia traderom wykonywanie akcji typu „przeciągnij i upuść" z udziałem cBotów, wskaźników lub wtyczek. Aby zaimplementować tę kontrolkę w swoim algorytmie, użyj klasy DropZone. Kontrolką DropZone można manipulować jak każdą inną kontrolką.

Gdy użytkownik upuści kompatybilny plik lub folder w polu, generowane jest zdarzenie Dropped. Gdy użytkownik upuści folder lub wiele folderów w polu, przetwarzane i kopiowane są tylko kompatybilne pliki z określonymi rozszerzeniami w FilterExtensions.

Uwaga

Upuszczone pliki są zwykle kopiowane i zapisywane w tej lokalizacji: ..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected Files\

Lokalizacja dla instancji cBota różni się od powyższej: ..\Documents\cAlgo\Data\cBots\{cBotName}\{unique-instance-number}\Selected files\

Ten kod wtyczki pokazuje, jak dodać kontrolkę DropZone do Trade Watch:

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

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

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

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

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

            _dropzone.Dropped += Dropped_file;
        }

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

Image title

ProgressBar

Kontrolka ProgressBar wyświetla postęp trwającej operacji. Paski postępu sprawiają, że algorytmy są bardziej przyjazne dla użytkownika i pomagają zarządzać oczekiwaniami traderów dotyczącymi czasu oczekiwania na określone operacje.

cTrader Algo API pozwala programistom dodawać dwa typy kontrolek ProgressBar: kontrolkę nieskończoną i kontrolkę określoną.

Kontrolka nieskończona

Możesz chcieć użyć kontrolki nieskończonej w następujących sytuacjach:

  • Nie możesz określić czasu oczekiwania na operację.
  • Nie możesz wykryć postępu operacji.
  • Nie chcesz wskazywać, jak długo potrwa operacja.

Image title

Kontrolka określona

Możesz chcieć użyć tej kontrolki, gdy możesz określić czas oczekiwania na operację i chcesz, aby użytkownicy widzieli wskaźnik oparty na tym czasie.

Aby wyświetlić postęp operacji, użyj właściwości Value, aby ustawić wartość. Aby ustawić procent paska postępu, użyj właściwości Minimum i Maximum.

Image title

Poniższy kod wtyczki pokazuje, jak utworzyć pasek postępu przy użyciu zarówno kontrolek nieskończonych, jak i określonych (zielonych):

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

Okna dialogowe

OpenFileDialog i OpenFolderDialog

cTrader Algo API udostępnia interfejs OpenFileDialog, aby umożliwić użytkownikom wybór pliku dla algorytmu. Gdy użytkownik wybierze plik w wynikowym oknie, plik jest kopiowany do folderu Selected files algorytmu. Algorytm może pracować z plikami w swoim folderze Selected files bez ograniczeń.

Wskazówka

Użyj funkcjonalności OpenFileDialog, gdy musisz załadować ważne pliki danych, pliki kopii zapasowych lub konfiguracyjne, wskaźniki niestandardowe lub skrypty.

Poniższy kod pokazuje, jak użyć okna dialogowego OpenFileDialog we wskaźniku:

 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

cTrader Algo API udostępnia interfejs OpenFolderDialog, aby umożliwić użytkownikom określenie folderu dla algorytmu. Gdy użytkownik wybierze folder w wynikowym oknie, wszystkie pliki i foldery z plikami wewnątrz wybranego folderu są kopiowane do folderu Selected files algorytmu.

Wskazówka

Użyj funkcjonalności OpenFolderDialog, gdy musisz załadować folder zawierający krytyczne pliki danych, pliki kopii zapasowych lub konfiguracyjne, wskaźniki niestandardowe lub skrypty.

Wybrane pliki i foldery są zwykle kopiowane do folderu Selected files, ponieważ algorytm może pracować z elementami w tym folderze nawet wtedy, gdy jego AccessRights jest ustawione na None.

Uwaga

Folder Selected files algorytmu znajduje się zwykle w tej ścieżce: ..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected files\

Folder Selected files dla instancji cBota różni się od powyższego: ..\Documents\cAlgo\Data\cBots\{cBotName}\{Instance-Id}\Selected files\

Poniższy kod pokazuje, jak użyć okna dialogowego OpenFolderDialog we wskaźniku:

 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

cTrader Algo API udostępnia interfejs SaveFileDialog, aby umożliwić użytkownikom zapisywanie plików (lokalnie) na swoich komputerach. Gdy pojawi się odpowiednie okno, użytkownik wybiera folder, do którego chce zapisać plik, i wprowadza nazwę pliku. Plik jest następnie zapisywany w określonej lokalizacji.

Wskazówka

Użyj funkcjonalności SaveFileDialog, gdy musisz wykonać dowolną z następujących czynności:

  • Zapisać raporty wydajności, wyniki backtestingu, pliki konfiguracyjne lub dane optymalizacji.
  • Wyeksportować dzienniki handlowe, dzienniki operacji lub ogólne dane aktywności użytkownika.
  • Przechowywać wskaźniki niestandardowe, dane dla wykresów i wizualizacji lub parametry strategii.

Poniższy kod pokazuje, jak użyć okna dialogowego SaveFileDialog we wskaźniku:

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

Kontrolki przeciągalne

Kontrolka przeciągalna obszaru wykresu

Interfejsy ChartDraggable i ChartDraggables udostępniają typy, które pozwalają dodać do wykresu kontrolkę przeciągalną zdolną do hostowania innych kontrolek i różnych elementów. Te kontrolki przeciągalne ułatwiają użytkownikom interakcję z różnymi elementami wykresu.

Uwaga

Kontrolkę przeciągalną można przesuwać lub zmieniać jej pozycję tylko w obrębie wykresu, do którego została dodana.

Ten kod pokazuje, jak utworzyć wskaźnik, który dodaje dwa elementy sterujące, które można przemieszczać w obrębie wykresu:

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

Przeciągalny element sterujący okna aplikacji

Interfejsy ApplicationDraggable i ApplicationDraggables zapewniają typy używane do dodawania pływających elementów sterujących, które można przemieszczać indywidualnie w całym oknie aplikacji cTrader. Takie elementy sterujące umożliwiają tworzenie interaktywnych i dynamicznych interfejsów użytkownika.

Uwaga

Spośród trzech typów algorytmów tylko wtyczki mogą implementować przeciągalne elementy sterujące obejmujące całą aplikację.

Ten kod pokazuje, jak utworzyć wtyczkę, która dodaje komponent WebView i blok tekstu w dwóch oddzielnych oknach, które można przemieszczać w całym interfejsie użytkownika 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;
        }
    }
}

Kontrolka kart

Klasa TabControl zapewnia typy, które umożliwiają tworzenie wielu kart dla algorytmu. Te karty mogą być używane do grupowania powiązanych elementów lub prezentowania oddzielnych widoków dla funkcjonalności.

Ten kod pokazuje, jak używać kart we wtyczce dodanej do Panelu aktywnego symbolu:

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

Niestandardowe elementy sterujące

Niestandardowy element sterujący to element sterujący, który w istocie składa się z kilku wstępnie zdefiniowanych elementów sterujących. Innymi słowy, jest to element sterujący, dla którego inne elementy sterujące stanowią jego zawartość.

Niestandardowe elementy sterujące działają jako klasy wielokrotnego użytku podobnie do wbudowanych elementów sterujących.

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

Instancja tego wskaźnika powinna wyświetlać cztery pola tekstowe bezpośrednio w centrum głównego wykresu.

Organizuj elementy sterujące za pomocą paneli

Aby praca z elementami sterującymi była wygodniejsza, możesz umieścić kilka elementów sterujących w odrębnej grupie z własną pozycją w interfejsie użytkownika. Aby to zrobić, możesz użyć klasy Panels i jej pochodnych.

Pomyśl o panelu jako o elemencie sterującym z innymi elementami sterującymi jako jego zawartością. cTrader obsługuje pięć różnych klas dziedziczących z podstawowej klasy Panels (która sama dziedziczy z klasy Control):

  • Canvas
  • DockPanel
  • Grid
  • StackPanel
  • WrapPanel

Każda z powyższych klas używa różnych układów paneli i strategii pozycjonowania, jak omówiono poniżej.

Płótno

Płótno to panel, który umożliwia pozycjonowanie elementów sterujących na podstawie określonych współrzędnych X i Y.

Warto zauważyć, że osie X i Y różnią się od tych używanych przez obiekty wykresów lub rysunki. Współrzędne X i Y używane przez klasę Canvas reprezentują wartości liczbowe zaczynające się od (0, 0) od lewego górnego rogu wykresu.

Rozważmy następujący przykład:

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

Po utworzeniu instancji powyższego wskaźnika powinieneś zobaczyć przycisk Kliknij mnie w lewym górnym rogu wykresu.

Właściwość Top elementu sterującego określa jego pozycjonowanie na osi Y. Z kolei właściwość Left definiuje jego pozycjonowanie na osi X.

Powyższy kod używa również właściwości Padding i Margin. Padding odnosi się do odległości między zawartością elementu sterującego a jego zewnętrznymi krawędziami. Margin to odległość między elementem sterującym a krawędziami jego elementu nadrzędnego. Właściwości Padding i Margin mają zastosowanie do wszystkich paneli, nie tylko do klasy płótna. Są przydatne do zarządzania odstępami między elementami sterującymi.

W większości przypadków klasa Canvas jest używana do grupowania tylko niewielkiej liczby elementów sterujących.

Panel dokowania

Klasa DockPanel służy do dokowania (umieszczania) elementu sterującego w statycznej lokalizacji na wykresie. Istnieją cztery możliwe pozycje dokowania:

  • Góra
  • Dół
  • Lewo
  • Prawo

Każdy element sterujący ma właściwość Dock. Podczas używania klasy DockPanel możesz użyć tej właściwości do pozycjonowania elementu sterującego wewnątrz DockPanel. Ilustruje to poniższy przykład:

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

Podczas tworzenia instancji tego wskaźnika powinieneś zobaczyć panel dokowania w centrum wykresu zawierający pole tekstowe i klikalny przycisk.

Należy zauważyć, że panele dokowania mogą być wypełniane poziomo lub pionowo. Nie możesz używać obu tych wyrównań jednocześnie. Orientacja panelu dokowania jest ustawiana automatycznie podczas konfigurowania pierwszego elementu sterującego w DockPanel. Jeśli właściwość Dock pierwszego elementu sterującego jest ustawiona na Top lub Bottom, cały DockPanel będzie zorientowany pionowo i odwrotnie.

Panel stosu

Panele stosu są jednymi z najczęściej używanych elementów sterujących ze względu na ich prostotę i użyteczność. Panele stosu wyrównują elementy sterujące podrzędne poziomo lub pionowo jeden po drugim. Jak pokazano poniżej, wystarczy ustawić jego orientację, a klasa zajmie się resztą:

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

Po utworzeniu instancji wskaźnika powinieneś zobaczyć poziomy panel stosu z dwoma polami tekstowymi i przyciskiem Prześlij w prawym dolnym rogu głównego wykresu.

Panel zawijania

Panele zawijania są w większości identyczne z panelami stosu. Jednak gdy nie ma wystarczającej ilości miejsca, aby zmieścić wszystkie elementy panelu zawijania, automatycznie zawinie pozostałe elementy sterujące do następnej linii na osi Y.

Siatka

Pomyśl o siatkach jak o arkuszach kalkulacyjnych z ustaloną liczbą kolumn i wierszy. Podczas używania siatek możesz dodawać elementy sterujące do każdej oddzielnej komórki.

Jak pokazano poniżej, podczas tworzenia instancji klasy Grid przekazujesz liczbę jej wierszy i kolumn jako argumenty integer. Podczas dodawania nowych elementów podrzędnych lub elementów sterujących musisz podobnie określić liczbę wierszy i kolumn podrzędnych.

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

Podczas tworzenia instancji powyższego wskaźnika powinieneś zobaczyć siatkę 10x2 dokładnie w centrum wykresu.

Pozycjonuj elementy sterujące w obrębie współrzędnych ceny i czasu

Oprócz elementów sterujących panelu cTrader umożliwia określanie współrzędnych ceny i czasu dla elementów sterujących bezpośrednio w obszarze wykresu. Metody AddControl() i MoveControl() zapewniają programistom algorytmów tę funkcjonalność.

Użyj następujących przeciążeń metod, aby zarządzać współrzędnymi elementów sterujących wykresu w zależności od swoich preferencji.

Aby dodać element sterujący wykresu do obszaru wykresu lub wskaźnika na bezwzględnych współrzędnych indeksu słupka i ceny (x, y).

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

Aby przenieść element sterujący wykresu do obszaru wykresu lub wskaźnika na bezwzględnych współrzędnych indeksu słupka i ceny (x, y).

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

Aby dodać element sterujący wykresu do obszaru wykresu lub wskaźnika na bezwzględnych współrzędnych czasu i ceny (x, y).

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

Aby przenieść element sterujący wykresu do obszaru wykresu lub wskaźnika na bezwzględnych współrzędnych czasu i ceny (x, y).

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

Aby dodać element sterujący wykresu do obszaru wykresu lub wskaźnika na bezwzględnej współrzędnej czasu (x).

1
void AddControl(ControlBase control, DateTime time)

Aby przenieść element sterujący wykresu do obszaru wykresu lub wskaźnika na bezwzględnej współrzędnej czasu (x).

1
void MoveControl(ControlBase control, DateTime time)

Aby dodać element sterujący wykresu do obszaru wykresu lub wskaźnika na bezwzględnej współrzędnej indeksu słupka (x).

1
void AddControl(ControlBase control, int barIndex)

Aby przenieść element sterujący wykresu do obszaru wykresu lub wskaźnika na bezwzględnej współrzędnej indeksu słupka (x).

1
void MoveControl(ControlBase control, int barIndex)

Aby dodać element sterujący wykresu do obszaru wykresu lub wskaźnika na bezwzględnej współrzędnej ceny (y).

1
void AddControl(ControlBase control, double y)

Aby przenieść element sterujący wykresu do obszaru wykresu lub wskaźnika na bezwzględnej współrzędnej ceny (y).

1
void MoveControl(ControlBase control, double y)

Klasa parametrów ControlBase może zawierać dowolną inną klasę podrzędną (Control, Button itp.), aby metoda została wywołana zgodnie z powyższymi sygnaturami.

Poniższy przykład cBota dodaje przycisk Kliknij mnie! nad ostatnim słupkiem na wykresie. Przycisk jest przesuwany do przodu wraz z każdym nowym dodanym słupkiem. Po kliknięciu przycisku na ekranie pojawia się okno komunikatu.

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

Ostrzeżenie

Liczba głównych elementów sterujących, które można dodać na wykresie, jest ograniczona do 100 ze względu na możliwe problemy z wydajnością. To ograniczenie dotyczy tylko jednego wystąpienia algorytmu i kontrolek dołączonych do ceny i słupków.

Właściwości padding i margin

Właściwość Margin określa przestrzeń między obramowaniami obiektu Control a jego elementem nadrzędnym (wykresem, panelem, obramowaniem itp.).

Z kolei właściwość Padding określa przestrzeń między zawartością kontrolki a jej obramowaniami. Możesz zmieniać wartości właściwości tak, aby były różne dla różnych stron.

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

Wystąpienie tego wskaźnika utworzy szary przycisk Click me w lewym górnym rogu wykresu. Zmodyfikuj parametry w oknach Dodaj wystąpienie lub Modyfikuj parametry, aby zobaczyć, jak dokładnie różne wartości marginesu i paddingu zmieniają sposób wyświetlania kontrolki.

Style

Używając stylów, możesz nadać podobny wygląd kilku różnym typom kontrolek. Jest to szczególnie przydatne w przypadku dużej (pięciu lub więcej) liczby kontrolek.

Klasa Style umożliwia ustawianie wartości dla różnych właściwości kontrolek, takich jak Margin lub BackgroundColor. Następnie możesz ponownie wykorzystać te wartości jako szablon dla wielu innych kontrolek.

Możemy również stworzyć spójny wygląd dla wielu kontrolek bez użycia klasy 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)
        {
        }
    }
}

Oto jak użycie klasy Style może uprościć pracę z wieloma kontrolkami.

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

Oba powyższe fragmenty kodu powinny wyświetlać te same kontrolki, jeśli uruchomisz ich odpowiednie wystąpienia wskaźników.

Możesz również użyć klasy Style, aby zmienić wygląd kontrolki w zależności od jej stanu.

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

Obraz

Kontrolka Image może być używana do wyświetlania lokalnie przechowywanego obrazu. Kontrolka Image używa klasy .NET Bitmap, co oznacza, że obsługuje większość popularnych formatów obrazów, takich jak następujące:

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

Zapoznaj się z dokumentacją klasy .NET Bitmap, aby dowiedzieć się więcej na jej temat.

Aby użyć kontrolki Image, ustaw jej właściwość Source na dane pliku obrazu w tablicy bajtów (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)
        {
        }
    }
}

Po uruchomieniu wystąpienia powyższego wskaźnika nie powinieneś zobaczyć nic nowego na głównym wykresie. Jednak wprowadź prawidłową ścieżkę pliku jako wartość parametru (Image File Path), a powinieneś zobaczyć wybrany obraz wyświetlony na środku ekranu.

Możesz również użyć zasobów swojego projektu do przechowywania obrazów i wyświetlania ich za pomocą kontrolki Image. Aby to zrobić, otwórz zasoby projektu w Visual Studio i przełącz się na kartę Resources. W niej utwórz nowy zasób i dodaj istniejący obraz. Następnie będziesz mógł użyć tego obrazu jako źródła w dowolnej kontrolce Image za pomocą właściwości Project_Name_Space.Properties.Resources._Image_Name.

Jako przykład skopiuj poniższy obraz i zapisz go jako „image.png" w swoim systemie:

Image title

Utwórz nowy wskaźnik w cTrader, ustaw jego nazwę na „Image Sample" i otwórz go za pomocą Visual Studio. Następnie dodaj projekt wskaźnika logo jako zasób. Aby to zrobić, kliknij prawym przyciskiem myszy swój projekt, wybierz Properties i kliknij Resources, a następnie kliknij Create and manage assembly resources. Skopiuj plik logo.png do nowo otwartej karty.

Skopiuj poniższy kod do głównego pliku kodu źródłowego wskaźnika:

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

Po utworzeniu wystąpienia tego wskaźnika powinieneś zobaczyć następujące dane wyjściowe.

Image title

Uwaga

Maksymalny rozmiar obrazów to 10 MB.