Ein Expert Advisor mit GUI: Erstellen des Panels (Teil I)
Inhalt
- Einführung
- GUI Elemente
- Zusammenstellen des GUI
- Aussehen der Kontrollelemente
- Statusleiste
- Gruppen von Karteireitern
- Eingabefeld
- Tasten
- Kombinationsfeld mit einer Auswahlliste
- Kontrollkästchen
- Tabelle
- Standardchart
- Fortschrittsanzeige
- Aktualisierte Bibliothek EasyAndFast
- Schlussfolgerung
Einführung
Trotz der aktiven Entwicklung des algorithmischen Handels bevorzugen viele Händler immer noch den manuellen Handel. Die Automatisierung von Routineaufgaben lässt sich jedoch kaum ganz vermeiden.
Der Artikel zeigt die Entwicklung eines Expert Advisor mit Signalen von mehreren Symbolen für den manuellen Handel. Als Beispiel verwenden wir die Signale der Stochastic aus der Standardauslieferung des Terminals. Sie können diesen Code verwenden, um eigene EAs mit grafischer Oberfläche (GUI) zu entwickeln: Jeder andere Indikator kann darin enthalten sein, ebenso wie die Ergebnisse bestimmter Berechnungen, um Entscheidungen zu treffen.
Für diejenigen, die Aufträge anderer Händler ausführen, kann der Artikel als Beispiel für eine technische Aufgabe dienen, die dem Kunden demonstriert werden soll. Dieses Beispiel kann Ihnen Zeit sparen, wenn Sie ein verständliches Pflichtenheft für die Entwicklung eines Programms mit GUI erstellen.
Hier sind die Themen, die in diesem Artikel ausführlich diskutiert werden.
- Erstellen eines GUI.
- Abrufen einer Liste von Symbolen mit bestimmten Eigenschaften.
- Steuerung des Handelsbetriebs.
- Schnelles Umschalten von Symbolen und Zeitrahmen auf Charts ohne die EA-Neuinitialisierung.
- Verwaltung der Chart-Eigenschaften über die Benutzeroberfläche.
- Empfang von Indikatorsignalen von mehreren Symbolen mit Farbanzeige.
- Arbeiten mit offenen Positionen.
- EasyAndFast Aktualisierung der Bibliothek.
Der Artikel soll in zwei Teilen veröffentlicht werden. In diesem Artikel betrachten wir die Entwicklung des Panels, während der nächste beschreibt, wie man es mit Funktionen füllt.
GUI Elemente
Wir beginnen die Entwicklung des EAs mit dem Aufbau einer GUI, die es den Benutzern ermöglicht, mit dem Programm zu interagieren und Daten zu visualisieren. Es ist möglich, ein GUI mit den Möglichkeiten der Standardbibliothek zu erstellen, aber in meinem Beispiel ist es auf Basis der EasyAndFast-Bibliothek implementiert. Seine reichhaltigen Funktionen ermöglichen es, sich auf die Funktionalität des Programms selbst zu konzentrieren, ohne durch die Verfeinerung seines grafischen Teils abgelenkt zu werden.
Lassen Sie uns zunächst die allgemeine GUI-Struktur skizzieren. Das folgende Diagramm zeigt das GUI-Fenster, das aus zwei Registerkarten besteht. Die Listen zeigen die Funktionen an, die darauf platziert werden sollen. Dies ist ein vereinfachtes Beispiel. Ein Kunde und ein Entwickler könnten dies im Gespräch näher ausarbeiten.
Abb. 1. Ansicht des General GUI mit Anmerkungen
Das GUI könnte viele Steuerelement haben. Daher listen wir sie in einer hierarchischen Ordnung, zu Anfang:
- Aussehen der Kontrollelemente
- Statusleiste für die Anzeige zusätzlicher Übersichtsinformationen
- Die Gruppe der Karteireiter:
- Handel:
- Eingabefeld mit Ankreuzkästchen zum Filtern der Symbolliste
- Taste "Anfordern", um mit der Erstellung der Liste der Symbole zu beginnen.
- Taste für VERKAUFEN
- Taste für KAUFEN
- Eingabefeld für das Handelsvolumen
- Taste zum Schließen aller offenen Positionen
- Eingabefeld zur Einstellung eines Verkaufssignals
- Eingabefeld zur Einstellung eines Kaufsignals
- Tabelle der Symbole für den Handel
- Diagramm zur Visualisierung von Symboldaten. Für mehr Komfort, ermöglichen wir die Verwaltung einiger Chart-Eigenschaften mit der folgenden Gruppe von Elementen:
- Kombinationsfeld mit einer Auswahlliste zum Umschalten der Zeitrahmen
- Kontrollkästchen zum Aktivieren/Deaktivieren der Zeitmaßstabes
- Ankreuzkästchen zum Aktivieren/Deaktivieren der Preisstaffel
- Eingabefeld für den Maßstab
- Taste zum Aktivieren einer Einrückung
- Ankreuzfeld zur Anzeige des Indikators
- Positionen:
- Tabelle der Positionen
- Indikator für die Wiedergabe von Rahmen
Wir Deklarieren in der Hauptprogrammklasse (CProgram) die Methoden und Klasseninstanzen der oben genannten Elemente. Der Code der Methoden zum Erzeugen von Elementen wird in einer separaten Datei bereitgestellt und in die Datei mit einer MQL-Programmklasse eingebunden:
//+------------------------------------------------------------------+ //| Klasse der Entwicklungsanwendung | //+------------------------------------------------------------------+ class CProgram : public CWndEvents { private: //--- Fenster CWindow m_window1; //--- Statusleiste CStatusBar m_status_bar; //--- Karteireiter CTabs m_tabs1; //--- Eingabefelder CTextEdit m_symb_filter; CTextEdit m_lot; CTextEdit m_up_level; CTextEdit m_down_level; CTextEdit m_chart_scale; //--- Tasten CButton m_request; CButton m_chart_shift; CButton m_buy; CButton m_sell; CButton m_close_all; //--- Kombinationsfeld CComboBox m_timeframes; //--- Ankreuzfeld CCheckBox m_date_scale; CCheckBox m_price_scale; CCheckBox m_show_indicator; //--- Tabellen CTable m_table_positions; CTable m_table_symb; //--- Standardchart CStandardChart m_sub_chart1; //--- Fortschrittsanzeige CProgressBar m_progress_bar; //--- public: //--- Erstellen des GUI bool CreateGUI(void); //--- private: //--- Formular bool CreateWindow(const string text); //--- Statusleiste bool CreateStatusBar(const int x_gap,const int y_gap); //--- Karteireiter bool CreateTabs1(const int x_gap,const int y_gap); //--- Eingabefelder bool CreateSymbFilter(const int x_gap,const int y_gap,const string text); bool CreateLot(const int x_gap,const int y_gap,const string text); bool CreateUpLevel(const int x_gap,const int y_gap,const string text); bool CreateDownLevel(const int x_gap,const int y_gap,const string text); bool CreateChartScale(const int x_gap,const int y_gap,const string text); //--- Tasten bool CreateRequest(const int x_gap,const int y_gap,const string text); bool CreateChartShift(const int x_gap,const int y_gap,const string text); bool CreateBuy(const int x_gap,const int y_gap,const string text); bool CreateSell(const int x_gap,const int y_gap,const string text); bool CreateCloseAll(const int x_gap,const int y_gap,const string text); //--- Kombinationsfeld bool CreateComboBoxTF(const int x_gap,const int y_gap,const string text); //--- Ankreuzfeld bool CreateDateScale(const int x_gap,const int y_gap,const string text); bool CreatePriceScale(const int x_gap,const int y_gap,const string text); bool CreateShowIndicator(const int x_gap,const int y_gap,const string text); //--- Tabellen bool CreatePositionsTable(const int x_gap,const int y_gap); bool CreateSymbolsTable(const int x_gap,const int y_gap); //--- Standardchart bool CreateSubChart1(const int x_gap,const int y_gap); //--- Fortschrittsanzeige bool CreateProgressBar(const int x_gap,const int y_gap,const string text); }; //+------------------------------------------------------------------+ //| Methoden zum Erstellen der Steuerelemente | //+------------------------------------------------------------------+ #include "CreateGUI.mqh" //+------------------------------------------------------------------+
Als nächstes betrachten wir die Zusammenstellung des GUI, die Methoden zum Erstellen ihrer Elemente und Eigenschaften.
Zusammenstellen des GUI
Wir werden die Elemente von zehn Typen in der GUI der entwickelten Anwendung verwenden.
- Formular für Steuerungen (CWindow)
- Statusleiste (CStatusBar)
- Gruppe von Karteireiter (CTabs)
- Eingabefeld (CTextEdit)
- Taste (CButton)
- Combobox mit Auswahlliste (CComboBox)
- Ankreuzfeld (CCheckBox)
- Tabelle (CTable)
- Standardtabelle (CStandardChart)
- Fortschrittsbalken (CProgressBar)
Wir werden mehr als ein Element in einigen Kategorien aus dieser Liste benötigen, also werden wir nur ein Element pro Gruppe berücksichtigen. Betrachten wir die Methoden ihrer Erstellung in der gleichen Reihenfolge.
Aussehen der Kontrollelemente
Unten ist der Code der Methode zur Erstellung eines Formulars, auf dem sich alle anderen Elemente befinden sollen. Zuerst müssen wir das Formular in die Liste der Programm-GUI-Elemente aufnehmen. Dazu rufen wir die Methode CWndContainer::AddWindow() auf, indem Sie ihr das Elementobjekt vom Typ CWindow übergeben. Wir bestimmen dann seine Eigenschaften, bevor wir das Formular erstellen. Wir stellen die folgenden Eigenschaften ein (in der gleichen Reihenfolge wie in der Liste unten):
- Formulargröße (Breite und Höhe)
- Schriftgröße der Kopfzeile
- Bewegungsmodus des Formulars (innerhalb des Charts)
- Modus der manuellen Größenanpassung des Formulars (durch Ziehen der Ränder)
- Tasten des Formulars. Die Sichtbarkeit der einzelnen Tasten ist anpassbar. In diesem Fall werden die folgenden verwendet:
- Schließen des Formulars. Wenn Sie auf die Schaltfläche klicken, erscheint im Hauptformular des Programms das Bestätigungsfenster für das Schließen des Programms.
- Maximieren/Minimieren des Formulars.
- Tooltips Elemente. Diese Taste hat auch zwei Zustände. Wenn aktiviert, werden die angegebenen Tooltips in den Steuerelementen angezeigt.
- Erweitern des Formulars auf den gesamten Chart. Dies kann durch erneutes Anklicken der Schaltfläche rückgängig gemacht werden.
- Für jede Taste kann ein Tooltip gesetzt werden.
Nach dem Setzen der Eigenschaften rufen Sie die Formularerstellungsmethode - CWindow::CreateWindow() auf und übergeben diese:
- Chart-ID,
- Index der Unterfenster des Charts,
- Text der Kopfzeile,
- Anfangskoordinaten des Formulars.
//+------------------------------------------------------------------+ //| Erstellen des Formulars des Steuerelements | //+------------------------------------------------------------------+ bool CProgram::CreateWindow(const string caption_text) { //--- Hinzufügen des Pointers auf das Fenster zum Array der Fenster CWndContainer::AddWindow(m_window1); //--- Eigenschaften m_window1.XSize(750); m_window1.YSize(450); m_window1.FontSize(9); m_window1.IsMovable(true); m_window1.ResizeMode(true); m_window1.CloseButtonIsUsed(true); m_window1.CollapseButtonIsUsed(true); m_window1.TooltipsButtonIsUsed(true); m_window1.FullscreenButtonIsUsed(true); //--- Festlegen der Tooltips m_window1.GetCloseButtonPointer().Tooltip("Close"); m_window1.GetTooltipButtonPointer().Tooltip("Tooltips"); m_window1.GetFullscreenButtonPointer().Tooltip("Fullscreen"); m_window1.GetCollapseButtonPointer().Tooltip("Collapse/Expand"); //--- Erstellen der Formulars if(!m_window1.CreateWindow(m_chart_id,m_subwin,caption_text,1,1)) return(false); //--- return(true); }
Es wird empfohlen, das Programm zu kompilieren und das Ergebnis jedes Mal zu überprüfen, wen ein neuen Element dem GIU hinzugefügt wurde.
Abb. 2. Aussehen der Kontrollelemente
Bildschirmfotos aller Zwischenschritte werden unten angezeigt.
Statusleiste
Der Code der Methode zur Erstellung einer Statusleiste beginnt mit der Angabe des Hauptelements, mit dem die daran gebundenen Elemente berechnet und in ihrer Größe ausgerichtet werden. Das spart Zeit bei der Entwicklung einer Anwendung: Eine ganze Gruppe von verwandten Elementen kann verschoben werden, indem nur die Koordinaten des Hauptelements geändert werden. Um das Element zu binden, wird sein Pointer an die Methode CElement::MainPointer() übergeben. In diesem Beispiel binden wir die Statusleiste an das Formular, daher wird das Formularobjekt der Methode übergeben.
Dann setzen wir die Eigenschaften der Statusleiste. Sie soll drei Abschnitte mit Informationen für Benutzer anzeigen.
- Um keine Maße relativ zum Formular anzugeben, stellen wir sicher, dass sich die Breite automatisch ändert, wenn die Breite des Formulars geändert wird.
- Die Abstand des rechten Randes des Elements beträgt 1 Pixel.
- Wir binden die Statusleiste an den unteren Rand des Formulars, so dass sie automatisch an den unteren Rand angepasst wird, wenn sich die Formularhöhe ändert.
- Wenn wir dann Punkte hinzufügen, stellen wir die Breite für jeden von ihnen ein.
Nachdem die Eigenschaften gesetzt sind, legen wir das Element an. Jetzt ist es bereit für die Arbeit, und wir können den Text in seinen Abschnitten während der Laufzeit ändern. In unserem Beispiel, setzen wir den Text "Für Hilfe, drücken Sie F1" im ersten Abschnitt .
Wir stellen am Ende der Methode sicher, dass der Pointer des erzeugten Elements in der allgemeinen Liste der GUI-Elemente gespeichert wird. Wir rufen dazu die Methode CWndContainer::AddToElementsArray() auf und übergeben ihr den Formularindex und das Elementobjekt. Da wir nur ein einziges Formular haben, ist sein Index 0.
//+------------------------------------------------------------------+ //| Erstellen einer Statusleiste | //+------------------------------------------------------------------+ bool CProgram::CreateStatusBar(const int x_gap,const int y_gap) { #define STATUS_LABELS_TOTAL 3 //--- Sichern des Pointers zum Fenster m_status_bar.MainPointer(m_window1); //--- Eigenschaften m_status_bar.AutoXResizeMode(true); m_status_bar.AutoXResizeRightOffset(1); m_status_bar.AnchorBottomWindowSide(true); //--- Setzen der Anzahl der Zeile und ihrer Eigenschaften int width[STATUS_LABELS_TOTAL]={0,200,110}; for(int i=0; i<STATUS_LABELS_TOTAL; i++) m_status_bar.AddItem(width[i]); //--- Erstellen des Kontrollelements if(!m_status_bar.CreateStatusBar(x_gap,y_gap)) return(false); //--- Setzen des Textes in der Statusleiste m_status_bar.SetValue(0,"For Help, press F1"); //--- Hinzufügen des Objekts zum allg. Array der Objektgruppe CWndContainer::AddToElementsArray(0,m_status_bar); return(true); }
Die verbleibende Elemente der Bibliothek EasyAndFast werden nach demselben Prinzip erstellt. Daher betrachten wir nur die anpassbaren Eigenschaften, die in unserem EA verwendet werden.
Fig. 3. Hinzufügen der Statusleiste
Gruppen von Karteireitern
Bestimmen wir in der Methode zum Anlegen der Gruppen von Karteireitern die folgenden Element-Eigenschaften:
- Zentrieren der Texte auf dem Karteireiter.
- Lokalisieren der Karteireiter im oberen Teil des Arbeitsbereiches.
- Die Größe wird automatisch an den Bereich des Hauptelements (Formulars) angepasst. In diesem Fall ist es nicht notwendig, die Größe der Gruppen von Karteireitern anzugeben.
- Wir stellen die Einzüge der rechten und unteren Kante des Hauptelements ein. Wenn das Formular seine Größe ändert, bleiben diese Abstände erhalten.
- Beim Hinzufügen der folgenden Registerkarten werden auch der Name der Karteireiter und die Breite in die Methode übernommen.
Unten ist der Code der Methode:
//+------------------------------------------------------------------+ //| Erstellen eines Karteireiters in Gruppe 1 | //+------------------------------------------------------------------+ bool CProgram::CreateTabs1(const int x_gap,const int y_gap) { #define TABS1_TOTAL 2 //--- Sichern des Pointers auf das Hauptelement m_tabs1.MainPointer(m_window1); //--- Eigenschaften m_tabs1.IsCenterText(true); m_tabs1.PositionMode(TABS_TOP); m_tabs1.AutoXResizeMode(true); m_tabs1.AutoYResizeMode(true); m_tabs1.AutoXResizeRightOffset(3); m_tabs1.AutoYResizeBottomOffset(25); //--- Hinzufügen von Karteireitern mit den angegebenen Eigenschaften string tabs_names[TABS1_TOTAL]={"Trade","Positions"}; for(int i=0; i<TABS1_TOTAL; i++) m_tabs1.AddTab(tabs_names[i],100); //--- Erstelle des Steuerelements if(!m_tabs1.CreateTabs(x_gap,y_gap)) return(false); //--- Hinzufügen des Objekts zum allg. Array der Objektgruppe CWndContainer::AddToElementsArray(0,m_tabs1); return(true); }
Abb. 4. Hinzufügen der Gruppe von Karteireiter
Eingabefeld
Betrachten wir beispielsweise ein Eingabefeld, in dem ein Benutzer Währungen und/oder Währungspaare angeben kann, um die Symbolen in einer Tabelle aufzulisten. Sein Hauptelement ist eine Gruppe von Karteireiter. Hier müssen wir die Karteireiter angeben, auf der das Eingabefeld angezeigt werden soll. Dazu rufen wir die Methode CTabs::AddToElementsArray() auf und übergeben ihr den Registerindex und das angehängte Elementobjekt.
Betrachten wir nun die Eigenschaften für dieses Eingabefeld.
- Standardmäßig ist im Eingabefeld "USD" eingetragen: Das Programm sammelt Symbole mit USD in der Tabelle. Währungen und/oder Symbole in diesem Eingabefeld sind durch Komma getrennt. Im Folgenden werde ich die Methode zur Bildung einer Liste von Symbolen durch kommagetrennte Zeilen in diesem Eingabefeld zeigen.
- Das Eingabefeld enthält ein Ankreuzfeld. Nach dem Deaktivieren des Ankreuzfelds wird der Text im Eingabefeld ignoriert. Alle erkannten Währungspaare werden in die Symbolliste aufgenommen.
- Die Breite des Eingabefelds ist gleich der gesamten Breite des Hauptelements und wird angepasst, wenn sich die Breite des Karteireiters ändert.
- Die Taste Request befindet sich rechts neben dem Eingabefeld. Während das Programm läuft, können im Eingabefeld weitere Währungen und/oder Symbole angeben werden. Ein Klick auf diese Taste erstellt die Liste. Da die Breite des Eingabefelds sich automatisch ändern soll, während die Taste Request immer rechts davon stehen soll, ist darauf zu achten, dass die rechte Seite des Eingabefeldes einen Abstand vom rechten Rand des Hauptelements hat.
Das Element vom Typ CTextEdit besteht aus mehreren anderen Elementen. Deshalb, wenn ihre Eigenschaften geändert werden müssen, können die Zeiger abgefragt werden. Wir mussten einige Eigenschaften des Texteingabefeldes ändern (CTextBox). Betrachten wir sie in der gleichen Reihenfolge wie in der folgenden Codeliste.
- Eingabefeld Einrückung vom linken Rand des Hauptelements (CTextEdit).
- Automatische Änderung der Breite relativ zum Hauptelement.
- Beim Aktivieren des Eingabefeldes (durch Linksklick auf das Eingabefeld) wird der Text für einen schnellen Änderung vollautomatisch hervorgehoben.
- Befindet sich überhaupt kein Text im Eingabefeld, wird Folgendes angezeigt: "Beispiel EURUSD, GBP, NOK".
Das Ankreuzfeld des Eingabefeldes ist standardmäßig aktiviert. Wir aktivieren sie dazu direkt nach dem Anlegen des Elements.
//+------------------------------------------------------------------+ //| Erstzellen eines Ankreuzfelds mit Eingabefeld "Symbols filter" | //+------------------------------------------------------------------+ bool CProgram::CreateSymbolsFilter(const int x_gap,const int y_gap,const string text) { //--- Sichern des Pointers auf das Hauptelement m_symb_filter.MainPointer(m_tabs1); //--- Reserviert für den letzten Karteireiter m_tabs1.AddToElementsArray(0,m_symb_filter); //--- Eigenschaften m_symb_filter.SetValue("USD"); // "EUR,USD" "EURUSD,GBPUSD" "EURUSD,GBPUSD,AUDUSD,NZDUSD,USDCHF" m_symb_filter.CheckBoxMode(true); m_symb_filter.AutoXResizeMode(true); m_symb_filter.AutoXResizeRightOffset(90); m_symb_filter.GetTextBoxPointer().XGap(100); m_symb_filter.GetTextBoxPointer().AutoXResizeMode(true); m_symb_filter.GetTextBoxPointer().AutoSelectionMode(true); m_symb_filter.GetTextBoxPointer().DefaultText("Example: EURUSD,GBP,NOK"); //--- Erstellen des Kontrollelements if(!m_symb_filter.CreateTextEdit(text,x_gap,y_gap)) return(false); //--- Aktivieren des Ankreuzfelds m_symb_filter.IsPressed(true); //--- Hinzufügen eines Objekts zum gemeinsamen Array der Objektgruppen CWndContainer::AddToElementsArray(0,m_symb_filter); return(true); }
Zusätzlich zum Text des Eingabefelds gibt es ein numerisches in dem GUI. Zum Beispiel das Eingabefeld Lot (Volumen für Öffnungspositionen). Andere Eigenschaften dieses Typs sollten für Eingabefelder angegeben werden.
- Gesamtbreite des Elements.
- Maximaler einzugebender Wert.
- Minimaler einzugebender Wert.
- Schrittweite beim Umschalten mit den Tasten Inkrement und Dekrement.
- Anzahl der Nachkommastellen.
- Damit das Eingabefeld numerisch wird, sollten wir dies mit der Methode CTextEdit::SpinEditMode() spezifizieren.
- Standardwert nach dem Laden des Programms auf dem Chart.
- Eingabefeldbreite.
- Automatische Texthervorhebung im Eingabefeld beim Anklicken.
- Verankerung des Eingabefeldes am rechten Rand des Elements.
Hier ist der Code dieser Methode:
//+------------------------------------------------------------------+ //| Erstellen des Eingabefelds "Lot" | //+------------------------------------------------------------------+ bool CProgram::CreateLot(const int x_gap,const int y_gap,const string text) { //--- Sichern des Pointers auf das Hauptelement m_lot.MainPointer(m_tabs1); //--- Reserviert für den letzten Karteireiter m_tabs1.AddToElementsArray(0,m_lot); //--- Eigenschaften m_lot.XSize(80); m_lot.MaxValue(1000); m_lot.MinValue(0.01); m_lot.StepValue(0.01); m_lot.SetDigits(2); m_lot.SpinEditMode(true); m_lot.SetValue((string)0.1); m_lot.GetTextBoxPointer().XSize(50); m_lot.GetTextBoxPointer().AutoSelectionMode(true); m_lot.GetTextBoxPointer().AnchorRightWindowSide(true); //--- Erstellen des Kontrollelements if(!m_lot.CreateTextEdit(text,x_gap,y_gap)) return(false); //--- Hinzufügen eines Objekts zum gemeinsamen Array der Objektgruppen CWndContainer::AddToElementsArray(0,m_lot); return(true); }
Abb. 5. Ergänzen der Eingabefelder
Das Bild sieht nicht sehr logisch aus, aber wenn man andere Elemente hinzufügt, stellt sich heraus, dass alles an seinem Platz ist.
Tasten
Fügen wir dem GUI des EAs ein paar Tasten hinzu. Wir betrachten die mit den meisten Eigenschaften: die Taste zum Öffnen von VERKAUFSPOSITION.
- Tastenbreite.
- Der Text der Taste ist sowohl vertikal als auch horizontal exakt zentriert.
- Hintergrundfarbe der Schaltfläche.
- Hintergrundfarbe beim Bewegen des Cursors.
- Hintergrundfarbe bei Linksklick.
- Textfarbe der Schaltfläche.
- Textfarbe beim Bewegen des Cursors.
- Textfarbe bei Linksklick.
- Farbe des Tastenrahmens.
- Rahmenfarbe beim Bewegen des Cursors.
- Rahmenfarbe bei Linksklick.
Die gleichen Eigenschaften werden für die Schaltfläche KAUFEN mit Ausnahme der angegebenen Hintergrundfarben geändert.
//+------------------------------------------------------------------+ //| Erstellen der Verkaufstaste | //+------------------------------------------------------------------+ bool CProgram::CreateSell(const int x_gap,const int y_gap,const string text) { //--- Sichern des Pointers auf das Hauptelement m_sell.MainPointer(m_tabs1); //--- Reserviert für den letzten Karteireiter m_tabs1.AddToElementsArray(0,m_sell); //--- Eigenschaften m_sell.XSize(80); m_sell.IsCenterText(true); m_sell.BackColor(C'255,51,51'); m_sell.BackColorHover(C'255,100,100'); m_sell.BackColorPressed(C'195,0,0'); m_sell.LabelColor(clrWhite); m_sell.LabelColorHover(clrWhite); m_sell.LabelColorPressed(clrWhite); m_sell.BorderColor(clrBlack); m_sell.BorderColorHover(clrBlack); m_sell.BorderColorPressed(clrBlack); //--- Erstellen des Kontrollelements if(!m_sell.CreateButton(text,x_gap,y_gap)) return(false); //--- Hinzufügen des Element-Pointers auf die Datenbasis CWndContainer::AddToElementsArray(0,m_sell); return(true); }
Abb. 6. Ergänzen von Tasten
Kombinationsfeld mit einer Auswahlliste
Um den Zeitrahmen zu ändern, erstellen wir ein Kombinationsfeld mit einer Auswahlliste. Wir definieren die Eigenschaften seiner Konfiguration.
- Gesamtbreite des Elements.
- Anzahl der Listenelemente (in unserem Fall sind es 21, es ist die Anzahl der Zeitfenster des Terminals).
- Das Element soll an den rechten Teil des Registerkartenbereichs gebunden werden.
- Breite der Taste des Kombinationsfelds.
- Die Taste wird an den rechten Teil des Elements gebunden.
Jedem Listenelement werden Werte zugewiesen, und einige Eigenschaften werden danach über den Zeiger für die Liste gesetzt.
- Hervorheben von Elementen beim Bewegen des Mauszeigers.
- Hervorgehobenes Element. In unserem Fall ist dies der Punkt mit dem Index 18 (Zeitrahmen D1).
Im Folgenden finden Sie den Code der Methode zur Erstellung des Kombinationsfelds:
//+------------------------------------------------------------------+ //| Erstellen eines Kombinationsfelds für die Zeitrahmen | //+------------------------------------------------------------------+ bool CProgram::CreateComboBoxTF(const int x_gap,const int y_gap,const string text) { //--- Gesamtzahl der Elemente der Liste #define ITEMS_TOTAL2 21 //--- Übergabe des Panel-Objektes m_timeframes.MainPointer(m_tabs1); //--- Anker auf den Karteireiter m_tabs1.AddToElementsArray(0,m_timeframes); //--- Eigenschaften m_timeframes.XSize(115); m_timeframes.ItemsTotal(ITEMS_TOTAL2); m_timeframes.AnchorRightWindowSide(true); m_timeframes.GetButtonPointer().XSize(50); m_timeframes.GetButtonPointer().AnchorRightWindowSide(true); //--- Sichern der Werte des Elements in der Liste des Kombinationsfelds string items_text[ITEMS_TOTAL2]={"M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30","H1","H2","H3","H4","H6","H8","H12","D1","W1","MN"}; for(int i=0; i<ITEMS_TOTAL2; i++) m_timeframes.SetValue(i,items_text[i]); //--- Abfrage des Pointers auf die Liste CListView *lv=m_timeframes.GetListViewPointer(); //--- Setzen der Eigenschaften der Liste lv.LightsHover(true); lv.SelectItem(18); //--- Erstelle des Steuerelements if(!m_timeframes.CreateComboBox(text,x_gap,y_gap)) return(false); //--- Hinzufügen des Element-Pointers auf die Datenbasis CWndContainer::AddToElementsArray(0,m_timeframes); return(true); }
Abb. 7. Ergänzen des Kombinationsfelds
Kontrollkästchen
Ein Ankreuzfeld ist das einfachste Element. Es müssen nur zwei Eigenschaften angegeben werden.
- Die Breite.
- Lage des rechten Teils des Hauptelements.
Nach dem Erzeugen des Elements können wir das Ankreuzfeld programmtechnisch aktivieren.
//+------------------------------------------------------------------+ //| Erstellen des Ankreuzfelds "Date scale" | //+------------------------------------------------------------------+ bool CProgram::CreateDateScale(const int x_gap,const int y_gap,const string text) { //--- Sichern des Fensterpointers m_date_scale.MainPointer(m_tabs1); //--- Reserviert für den letzten Karteireiter m_tabs1.AddToElementsArray(0,m_date_scale); //--- Eigenschaften m_date_scale.XSize(70); m_date_scale.AnchorRightWindowSide(true); //--- Erstellen des Kontrollelements if(!m_date_scale.CreateCheckBox(text,x_gap,y_gap)) return(false); //--- Aktivieren des Ankreuzfelds m_date_scale.IsPressed(true); //--- Hinzufügen eines Objekts zum gemeinsamen Array der Objektgruppen CWndContainer::AddToElementsArray(0,m_date_scale); return(true); }
Abb. 8. Ergänzen des Ankreuzfelds
Tabelle
Das GUI soll zwei Tabellen erhalten. Betrachten wir diejenige, die die gebildete Liste von Symbolen und Signalen für Eröffnungspositionen enthält. Sie ist Teil des ersten Karteireiters. Deklarieren und initialisieren wir zunächst die Arrays für die Platzierung der Tabelleneigenschaften. Wir stellen die folgenden Eigenschaften ein.
- Elementbreite.
- Abmessungen der Tabelle (Anzahl der Spalten und Zeilen).
- Spaltenbreite (Werte werden im Array übergeben).
- Textausrichtung (Werte werden im Array übergeben).
- Abstand des Textes von den Zellrändern.
- Anzeige der Kopfzeile.
- Möglichkeit, Zeilen zu markieren.
- Möglichkeit der manuellen Größenanpassung von Spalten durch Ziehen im Kopfbereich.
- Anzeige der Formatierung im Zebra-Stil.
- Automatische Änderung der vertikalen Größe relativ zum Hauptelement.
- Einrückung von der Unterkante des Hauptelements.
Die Texte der Überschriften sind nach dem Anlegen der Tabelle anzugeben:
//+------------------------------------------------------------------+ //| Erstellen der Symboltabelle | //+------------------------------------------------------------------+ bool CProgram::CreateSymbolsTable(const int x_gap,const int y_gap) { #define COLUMNS1_TOTAL 2 #define ROWS1_TOTAL 1 //--- Sichern des Pointers auf das Hauptelement m_table_symb.MainPointer(m_tabs1); //--- Reserviert für den letzten Karteireiter m_tabs1.AddToElementsArray(0,m_table_symb); //--- Array der Spaltenbreite int width[COLUMNS1_TOTAL]={95,58}; //--- Array der Textausrichtung der Spalte ENUM_ALIGN_MODE align[COLUMNS1_TOTAL]={ALIGN_LEFT,ALIGN_RIGHT}; //--- Array der Textabstände der Spalten von X int text_x_offset[COLUMNS1_TOTAL]={5,5}; //--- Eigenschaften m_table_symb.XSize(168); m_table_symb.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL); m_table_symb.ColumnsWidth(width); m_table_symb.TextAlign(align); m_table_symb.TextXOffset(text_x_offset); m_table_symb.ShowHeaders(true); m_table_symb.SelectableRow(true); m_table_symb.ColumnResizeMode(true); m_table_symb.IsZebraFormatRows(clrWhiteSmoke); m_table_symb.AutoYResizeMode(true); m_table_symb.AutoYResizeBottomOffset(2); //--- Erstellen des Kontrollelements if(!m_table_symb.CreateTable(x_gap,y_gap)) return(false); //--- Setzen der Namen der Kopfzeile m_table_symb.SetHeaderText(0,"Symbol"); m_table_symb.SetHeaderText(1,"Values"); //--- Hinzufügen eines Objekts zum gemeinsamen Array der Objektgruppen CWndContainer::AddToElementsArray(0,m_table_symb); return(true); }
Die zweite Tabelle zeigt einige Eigenschaften der offenen Positionen. Zehn Spalten zeigen die folgenden Daten an.
- Symbol der Position.
- Anzahl der Positionen.
- Gesamtvolumen aller offenen Positionen.
- Volumen der KAUFPOSITIONEN.
- Volumen der VERKAUFSPOSITIONEN.
- Das aktuelle Gesamtergebnis aller offenen Positionen.
- Das aktuelle Ergebnis aller offenen KAUFPOSITIONEN.
- Das aktuelle Ergebnis aller offenen VERKAUFSPOSITIONEN.
- Kontobelastung jedes einzelnen Symbols.
- Medianpreis
Die folgenden Eigenschaften sollten zusätzlich in der zweiten Tabelle konfiguriert werden.
- Bildabstände vom rechten und oberen Zellrand.
- Fähigkeit, Werte zu sortieren.
- Automatische Änderung der horizontalen Größe relativ zum Hauptelement.
- Einrückung vom rechten Rand des Hauptelements.
Bilder in den Zellen der ersten Spalte symbolisieren die Taste, mit denen man eine Position oder alle schließen kann, wenn es sich um ein Hedge-Konto auf einem bestimmten Symbol handelt.
//+------------------------------------------------------------------+ //| Erstellen der Positionentabelle | //+------------------------------------------------------------------+ bool CProgram::CreatePositionsTable(const int x_gap,const int y_gap) { ... //--- Eigenschaften m_table_positions.TableSize(COLUMNS2_TOTAL,ROWS2_TOTAL); m_table_positions.ColumnsWidth(width); m_table_positions.TextAlign(align); m_table_positions.TextXOffset(text_x_offset); m_table_positions.ImageXOffset(image_x_offset); m_table_positions.ImageYOffset(image_y_offset); m_table_positions.ShowHeaders(true); m_table_positions.IsSortMode(true); m_table_positions.SelectableRow(true); m_table_positions.ColumnResizeMode(true); m_table_positions.IsZebraFormatRows(clrWhiteSmoke); m_table_positions.AutoXResizeMode(true); m_table_positions.AutoYResizeMode(true); m_table_positions.AutoXResizeRightOffset(2); m_table_positions.AutoYResizeBottomOffset(2); ... return(true); }
Abb. 9. Hinzufügen einer Tabelle zum ersten Karteireiter
Abb. 10. Hinzufügen einer Tabelle zum zweitem Karteireiter
Details zum Arbeiten mit den Tabellen in der Hauptprogrammdatei (CProgram) sind in einem der folgenden Artikelabschnitte zu erläutert.
Standardchart
Das Element vom Typ CStandardChart dient zur Visualisierung von Daten durch Symbole. Standardmäßig wird EURUSD D1 angezeigt. Es zeichnet sich durch folgende Eigenschaften aus.
- Horizontales Blättern.
- Automatische Breitenanpassung.
- Automatische Höhenanpassung.
- Einrückung vom rechten Rand des Hauptelements.
- Einrückung von der Unterkante des Hauptelements.
Bei Bedarf ist es möglich, ein Array von Charts in einer horizontalen Zeile zu erstellen. Wir verwenden dazu die Methode CStandardChart::AddSubChart(), indem wir das Symbol und den Zeitrahmen als Argumente übergeben. In diesem Fall benötigen wir jedoch ein einziges Chart, während Symbole und Zeitrahmen über andere Steuerelemente umgeschaltet werden.
//+------------------------------------------------------------------+ //| Erstellendes Standardcharts 1 | //+------------------------------------------------------------------+ bool CProgram::CreateSubChart1(const int x_gap,const int y_gap) { //--- Sichern des Pointers zum Fenster m_sub_chart1.MainPointer(m_tabs1); //--- Reserviert für den ersten Karteireiter m_tabs1.AddToElementsArray(0,m_sub_chart1); //--- Eigenschaften m_sub_chart1.XScrollMode(true); m_sub_chart1.AutoXResizeMode(true); m_sub_chart1.AutoYResizeMode(true); m_sub_chart1.AutoXResizeRightOffset(125); m_sub_chart1.AutoYResizeBottomOffset(2); //--- Hinzufügen von Charts m_sub_chart1.AddSubChart("EURUSD",PERIOD_D1); //--- Erstellen des Kontrollelements if(!m_sub_chart1.CreateStandardChart(x_gap,y_gap)) return(false); //--- Hinzufügen des Objekts in den allg. Array der Objektgruppen CWndContainer::AddToElementsArray(0,m_sub_chart1); return(true); }
Abb. 11. Hinzufügen eines Charts
Fortschrittsanzeige
Der Fortschrittsbalken ermöglicht es dem Benutzer zu verstehen, was das Programm jetzt macht. Also, fügen wir ihn dem GUI hinzu. Nachfolgend die Eigenschaften für unser Beispiel (in der gleichen Reihenfolge wie im Code).
- Gesamthöhe des Elements.
- Die Anzeigehöhe (Fortschrittsbalkenlinie).
- Balkenabstand von X.
- Balkenabstand von Y.
- Abstand des Haupttextbezeichnung von X.
- Abstand des Haupttextbezeichnung von Y.
- Abstand der prozentualen Textbeschriftung von X.
- Abstand der prozentualen Textbeschriftung von Y.
- Anzeige eines Dropdown-Steuerelements (zum automatischen Ausblenden).
- Schriftart
- Rahmenfarbe des Indikators.
- Hintergrundfarbe des Indikators.
- Anzeige der Zeile des Fortschrittsbalkens.
- Automatische Breitenanpassung.
- Einrückung vom rechten Rand des Hauptelements.
Die Beispiele von Fortschrittsanzeigen sind unten aufgeführt:
//+------------------------------------------------------------------+ //| Erstellen der Fortschrittsanzeige | //+------------------------------------------------------------------+ bool CProgram::CreateProgressBar(const int x_gap,const int y_gap,const string text) { //--- Sichern des Pointers auf das Hauptelement m_progress_bar.MainPointer(m_status_bar); //--- Eigenschaften m_progress_bar.YSize(17); m_progress_bar.BarYSize(14); m_progress_bar.BarXGap(0); m_progress_bar.BarYGap(1); m_progress_bar.LabelXGap(5); m_progress_bar.LabelYGap(2); m_progress_bar.PercentXGap(5); m_progress_bar.PercentYGap(2); m_progress_bar.IsDropdown(true); m_progress_bar.Font("Consolas"); m_progress_bar.BorderColor(clrSilver); m_progress_bar.IndicatorBackColor(clrWhiteSmoke); m_progress_bar.IndicatorColor(clrLightGreen); m_progress_bar.AutoXResizeMode(true); m_progress_bar.AutoXResizeRightOffset(2); //--- Erstellen des Elements if(!m_progress_bar.CreateProgressBar(text,x_gap,y_gap)) return(false); //--- Hinzufügen des Element-Pointers auf die Datenbasis CWndContainer::AddToElementsArray(0,m_progress_bar); return(true); }
Wir haben alle Steuerelemente beschrieben, die in unserem GUI des EAs verwendet werden sollen. Im Moment ist dies nur eine grafische Oberfläche. Im Weiteren werden wir alle notwendigen Methoden entwickeln, um die ursprünglichen Idee zu verwirklichen.
Aktualisierte Bibliothek EasyAndFast
In der Bibliothek EasyAndFast wurde die 'public' Methode CTable::SortData() in der CTable Klasse überarbeitet. Als zweites Argument können wir nun die Sortierrichtung der Tabelle (optionaler Parameter) angeben. Bisher hat der Aufruf der Methode CTable::SortData() die Sortierung in die entgegengesetzte Richtung gestartet. Außerdem wurden die Methoden zum Empfang von der aktuellen Sortierrichtung und dem sortierten Spaltenindex hinzugefügt. Wenn die Tabelle von einem Benutzer manuell sortiert wurde (durch Klicken auf einen Spaltenkopf) und die Daten in der Tabelle nicht in der gleichen Reihenfolge aktualisiert wurden, ist es möglich, sie wiederherzustellen, nachdem die aktuelle Sortierrichtung gefunden wurde.
//+------------------------------------------------------------------+ //| Klasse zum Erstellen der zu zeichnenden Tabelle | //+------------------------------------------------------------------+ class CTable : public CElement { public: ... //--- Sortieren der Daten nach einer Spalte void SortData(const uint column_index=0,const int direction=WRONG_VALUE); //--- (1) Aktuelle Sortierrichtung, (2) indes des Sortierarrays int IsSortDirection(void) const { return(m_last_sort_direction); } int IsSortedColumnIndex(void) const { return(m_is_sorted_column_index); } ... }; //+------------------------------------------------------------------+ //| Daten entspr. der angegebenen Spalte sortieren | //+------------------------------------------------------------------+ void CTable::SortData(const uint column_index=0,const int direction=WRONG_VALUE) { //--- Exit wenn die Tabellengrenzen überschritten werden if(column_index>=m_columns_total) return; //--- Index des Sortierens, von uint first_index=0; //--- Letzter Index uint last_index=m_rows_total-1; //--- Richtung ist nicht vom Nutzer bestimmt if(direction==WRONG_VALUE) { //--- Erstes Sortieren ist aufsteigend Danach wird in der Gegenrichtung sortiert if(m_is_sorted_column_index==WRONG_VALUE || column_index!=m_is_sorted_column_index || m_last_sort_direction==SORT_DESCEND) m_last_sort_direction=SORT_ASCEND; else m_last_sort_direction=SORT_DESCEND; } else { m_last_sort_direction=(ENUM_SORT_MODE)direction; } //--- Sichern des Index der letzten sortierten Datenspalte m_is_sorted_column_index=(int)column_index; //--- Sortieren QuickSort(first_index,last_index,column_index,m_last_sort_direction); }
Ein weiterer kleiner Zusatz wurde gemacht zur CKeysKlasse der CKeys::KeySymbol() Methode. Der Ziffernblock (ein separater Tastenblock auf der rechten Seite der Tastatur) wurde bisher nicht unterstützt. Jetzt können Sie auch Zahlen und Sonderzeichen aus diesem Bereich der Tastatur verwenden.
//+------------------------------------------------------------------+ //| Rückgabe des Symbols der gedrückten Taste | //+------------------------------------------------------------------+ string CKeys::KeySymbol(const long key_code) { string key_symbol=""; //--- Falls ein Leerzeichen benötigt wird if(key_code==KEY_SPACE) { key_symbol=" "; } //--- Wenn (1) ein Buchstabe, (2) eine Zahl oder (3) ein spezielles Zeichen benötigt wird else if((key_code>=KEY_A && key_code<=KEY_Z) || (key_code>=KEY_0 && key_code<=KEY_9) || (key_code>=KEY_NUMLOCK_0 && key_code<=KEY_NUMLOCK_SLASH) || (key_code>=KEY_SEMICOLON && key_code<=KEY_SINGLE_QUOTE)) { key_symbol=::ShortToString(::TranslateKey((int)key_code)); } //--- Rückgabe eines Symbols return(key_symbol); }
Neue Versionen der Klassen CTable und CKeys können am Ende des Artikels heruntergeladen werden.
Schlussfolgerung
Dies war der erste Teil des Artikels. Wir haben diskutiert, wie man GUIs für Programme beliebiger Komplexität ohne großen Aufwand entwickelt. Sie können dieses Programm weiter entwickeln und für Ihre eigenen Zwecke nutzen. Im zweiten Teil des Artikels werde ich zeigen, wie man mit dem GUI arbeitet, und vor allem - wie man es mit Funktionalität füllt.
Nachfolgend können Sie die Dateien zum Testen und detaillierten Studium des im Artikel enthaltenen Codes herunterladen.
Dateiname | Kommentar |
---|---|
Nachfolgend können die Dateien zum Testen und detaillierten Studium des im Artikel enthaltenen Codes heruntergeladen werden. | Der EA für eine manuelles Handeln mit dem GUI |
MQL5\Experts\TradePanel\Program.mqh | Datei mit den Klassen des Programms |
MQL5\Experts\TradePanel\CreateGUI.mqh | Datei mit den implementierte Methoden für die Entwicklung des GUI aus der Programmklasse aus Program.mqh |
MQL5\Include\EasyAndFastGUI\Controls\Table.mqh | Aktualisierte Klasse CTable |
MQL5\Include\EasyAndFastGUI\Keys.mqh | Aktualisierte Klasse CKeys |
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/4715
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.