Rezepte MQL5 - Programmierung der gleitenden Kanäle
Einführung
Es ist bekannt, dass die Richtung des Marktpreises deutlich sein kann, und dann gibt einen Trend im Chart, aber es kann anderseits auch nicht da sein, dann gibt es im Chart flat. Es wird angenommen, dass beim Flat die technischen Indikatoren gut funktionieren, die zu der Oszillatoren-Familie gehören. Jedoch kann ein bestimmter Bereich beim Trend sein, in dem Preisschwankungen geben.
In diesem Artikel werde ich versuchen, eine dynamische Art und Weise des Aufbaus von gleich entfernten Kanälen zu erleuchten, die man häufig als gleitende Kanäle nennt. Es sollte beachtet werden, dass eine der beliebtesten Strategien für solche Kanäle - eine Strategie von Victor Barishpolts ist. Wir werden auf jene Aspekte seiner Strategie berühren, die mit den Erstellungsregeln der gleitenden Kanäle verbunden sind. Außerdem werden wir versuchen, diese Regeln zu erweitern, was nach der Meinung des Autors, die Flexibilität des Kanalsystems erhöht.
1. Die Grundlagen des Zeichnens der gleich entfernten Kanäle
Zuerst werden wir mit Schemen arbeiten, die als Grundlage für die Programmierung der gleich entfernten Kanäle sein werden. Hier würde ich empfehlen, Hilfe für die technische Tool-Analyse zu suchen "Gleich entfernter Kanal".
Wie bekannt ist, wird der Kanal auf drei Punkten basiert, von denen jede einen Preis und eine Zeit von Koordination hat. Zuerst geben Wir Acht auf Zeit-Koordinaten der Punkte, denn deren Reihenfolge beeinflusst die Art des Kanals. Nehmen wir zum Beispiel den Kanal, deren Hauptlinie auf zwei lokalen Minima gebaut wird. Der dritte Punkt wird für das lokale Maximum verantwortlich. Der Stand der Punkte kann als Kriterium für die Eingabe des Kanals dienen.
Beim Zeichen des Kanals werden keine Strahlen nach links, auch keine Strahlen nach rechts verwendet, wenn nichts anders angegeben ist.
Der erste Typ bezieht sich auf den Fall, wenn es erstmal ein Minimum erscheint, dann ein Maximum, und dann noch einmal Minimum. Schematisch kann diese Situation wie in Abb. 1 dargestellt werden.
Abb.1 Der erste Typ der Reihe von Punkten, das Schema
Auf dem Preischart sieht der erste Typ folgendermaßen aus (Abbildung 2).
Abb.2 Der erste Typ der Reihe von Punkten, das Preischart
Der zweite Typ - der Fall, wenn auf dem Chart nacheinander ein Maximum erscheint, ein Minimum, und wieder Minimum (Abbildung 3).
Abb.3 Der zweite Typ der Reihe von Punkten, das Schema
Das lokale Maximum, das am Anfang erscheint, wird am Ende der dritte Punkt sein. Als nächstes folgende ein paar Minimums bilden die Hauptlinie.
Der dritte Typ wird auf der Grundlage "Minimum-Minimum-Maximum" gebaut. In diesem Fall wird die Hauptlinie warten, wann ein lokales Maximum (Abbildung 4) gebildet wird.
Abb.1 Der dritte Typ der Reihe von Punkten, das Schema
Die letzten beiden Typen - eher Sonderfälle.
Die vierte Variante ergibt sich, wenn der erste und der dritte Punkte mit ihrer Erstellungszeit zusammenfallen. (in Abb.5).
Abb.5 Der vierte Typ der Reihe von Punkten, das Schema
Und der fünfte Typ - der Fall, wenn die Zeit-Koordinaten der zweiten und dritten Punkte zusammenfallen (Abbildung 6).
Abb.6 Der fünfte Typ der Reihe von Punkten, das Schema
Mit fünf Arten solcher gleich entfernten Kanäle werden wir arbeiten. Der nächste Abschnitt wird versuchen, einen Punkt zu programmieren, auf dem die Kanallinien gebaut werden.
2. Zusätzliche Typen der Daten
Die am häufigsten verwendeten Punkte, die die Trend-Linien des Kanals zeigen, — sind Fraktale. Dann ist dieser Punkt zugleich sowohl ein Fraktal, und die Basis für eine gerade Linie.
Lassen Sie uns versuchen, zusammenzufassen und fraktale Punkte mit OOP-Werkzeug zu kodieren.
2.1 Die Klasse des fraktalen Punktes
Die Funktional dieser Klasse - muss für den Punkt verantwortlich sein, der zu deren gehört, von den der gleich entfernte Kanal gebaut wird.
Wir nennen diese Klasse CFractalPoint und, in den besten Traditionen der MQL5 Sprache binden wir es auf die Interface-Klasse CObject mit einer Beziehung der Vererbung.
//+------------------------------------------------------------------+ //| Klasse Fractal Point | //+------------------------------------------------------------------+ class CFractalPoint : public CObject { //--- === Data members === --- private: datetime m_date; // Datum und Zeit double m_value; // Der Wert ENUM_EXTREMUM_TYPE m_extreme_type; // Der Typ des Extremums int m_idx; // Das Index (von 0 bis 2) //--- === Methoden === --- public: //--- Konstruktor / Destruktor void CFractalPoint(void); void CFractalPoint(datetime _date,double _value, ENUM_EXTREMUM_TYPE _extreme_type,int _idx); void ~CFractalPoint(void){}; //--- get-Methoden datetime Date(void) const {return m_date;}; double Value(void) const {return m_value;}; ENUM_EXTREMUM_TYPE FractalType(void) const {return m_extreme_type;}; int Index(void) const {return m_idx;}; //--- set-Methoden void Date(const datetime _date) {m_date=_date;}; void Value(const double _value) {m_value=_value;}; void FractalType(const ENUM_EXTREMUM_TYPE extreme_type) {m_extreme_type=extreme_type;}; void Index(const int _bar_idx){m_idx=_bar_idx;}; //--- Service void Copy(const CFractalPoint &_source_frac); void Print(void); }; //+------------------------------------------------------------------+
Die Klasse hat vier Mitglieder für die Datenübertragung:
- m_date — die Zeit-Koordinate des Punktes auf dem Chart;
- m_value — die Preis-Koordinate des Punktes auf dem Chart;
- m_extreme_type – Der Typ des Extremums;
- m_idx – Das Index.
Für den Typ des Extremums wird die Aufzählung ENUM_EXTREMUM_TYPE verantwortlich sein:
//+------------------------------------------------------------------+ //| Der Typ des Extremums | //+------------------------------------------------------------------+ enum ENUM_EXTREMUM_TYPE { EXTREMUM_TYPE_MIN=0, // das Minimum EXTREMUM_TYPE_MAX=1, // das Maximum };
Das Hauptziel der Klasse-Methoden CFractalPoint ist, sicherzustellen, dass Werte der oben aufgeführten privaten Mitglieder empfangen oder aktualisiert werden.
Zum Beispiel, lassen Sie uns einen fraktalen Punkt auf dem EURUSD, H4-Chart für die Kerze datiert von 2016.01.26 08.00 Uhr in Abb. 7 programmatisch erstellen. Das Fraktal wurde auf dem Maximum der Kerze an dem Preis 1,08742 gebildet.
Abb.7 Das Beispiel des Fraktals
Dies ist, wie der Code für die Verarbeitung der gestellten Aufgabe aussehen kann.
//--- Die Daten für den fraktalen Punkt datetime pnt_date=D'26.01.2016 08:00'; double pnt_val=1.08742; ENUM_EXTREMUM_TYPE pnt_type=EXTREMUM_TYPE_MAX; int pnt_idx=0; //--- Die Erstellung des fraktalen Punktes CFractalPoint myFracPoint(pnt_date,pnt_val,pnt_type,pnt_idx); myFracPoint.Print();
Im Journal erscheint die folgende Anzeige:
---=== Die Daten des fraktalen Punktes ===--- Datum: 2016.01.26 08:00 Preis: 1.08742 Typ: EXTREMUM_TYPE_MAX Index: 0
Dieser Eintrag zeigt an, dass der fraktale Punkt auf dem Bar vom 26. Januar 2016 vom Preis 1,08742 gefunden wurde. Dieses Fraktal ist ein lokales Maximum. Das Null-Index zeigt an, dass eine Reihe von ähnlichen Punkten der erste sein wird.
2.2 Die Klasse der Reihe der fraktalen Punkte
Jetzt können Sie zur Erstellung der fraktalen Punkte gehen, auf deren Grundlage wir den gleich entfernten Kanal bauen. Erstellen wir dafür diese Klasse CFractalSet, die diese Punkte in der Reihe sammelt und identifiziert.
Diese Klasse wird zum Berater hinzugefügt, und nicht zum Indikator, deshalb werden Kanäle nicht zu Puffern des Indikators gehören, sondern zu grafischen Objekten des Typs CChartObjectChannel.
Die Klasse CFractalSet — ein Nachkommen der standarten Bibliothek-Klasse CArrayObj. Ich entschied mich für einen sicheren Typ der Vererbung, um die Interface-Klasse hochspezialisierten zu machen.
//+------------------------------------------------------------------+ //| Die Klasse der Reihe Fractal Points | //+------------------------------------------------------------------+ class CFractalSet : protected CArrayObj { //--- === Data members === --- private: ENUM_SET_TYPE m_set_type; // Der Typ der Reihe von Punkten int m_fractal_num; // Die feste Anzahl von Punkten int m_fractals_ha; // Die Handle des fraktalen Indikators CisNewBar m_new_bar; // Das Objekt des neuen Bars CArrayObj m_channels_arr; // Das Objekt der Arrays von Zeigern color m_channel_colors[4]; // Die Farben der Kanäle bool m_is_init; // Die Initialisierungs-Flagge //--- Die Einstellungen des Kanals int m_prev_frac_num; // der vorherigen Fraktalen int m_bars_beside; // Bars links / rechts von dem Fraktal int m_bars_between; // Die Anzahl der Zwischenbars bool m_to_delete_prev; // Löschung der vorherigen Kanäle? bool m_is_alt; // Der alternative Indikator der Fraktalen? ENUM_RELEVANT_EXTREMUM m_rel_frac; // Der aktuelle Punkt bool m_is_array; // Einen Strahl zeichnen? int m_line_wid; // die Linienbreite bool m_to_log; // Ein Journal führen? //--- === Methoden === --- public: //--- Konstruktor / Destruktor void CFractalSet(void); void CFractalSet(const CFractalSet &_src_frac_set); void ~CFractalSet(void){}; //--- void operator=(const CFractalSet &_src_frac_set); //--- Handlers bool Init( int _prev_frac_num, int _bars_beside, int _bars_between=0, bool _to_delete_prev=true, bool _is_alt=false, ENUM_RELEVANT_EXTREMUM _rel_frac=RELEVANT_EXTREMUM_PREV, bool _is_arr=false, int _line_wid=3, bool _to_log=true ); void Deinit(void); void Process(void); //--- Service CChartObjectChannel *GetChannelByIdx(const int _ch_idx); int ChannelsTotal(void) const {return m_channels_arr.Total();}; private: int AddFrac(const int _buff_len); int CheckSet(const SFracData &_fractals[]); ENUM_SET_TYPE GetTypeOfSet(void) const {return m_set_type;}; void SetTypeOfSet(const ENUM_SET_TYPE _set_type) {m_set_type=_set_type;}; bool PlotChannel(void); bool Crop(const uint _num_to_crop); void BubbleSort(void); }; //+------------------------------------------------------------------+
Wir zählen die Mitglieder dieser Klasse auf.
- m_set_type – Der Typ der Reihe von Punkten. Im Folgenden betrachten wir die Aufzählung, die für die Klassifizierung der Reihen verantwortlich ist;
- m_fractal_num – Die feste Anzahl von Punkten, die in einer Reihe sind;
- m_fractals_ha – Die Handle des fraktalen Indikators;
- m_new_bar – Das Objekt des neuen Bars;
- m_channels_arr – Das Objekt der Arrays von Zeigern;
- m_channel_colors[4] — das Array der Farben für die Anzeige der Kanäle;
- m_is_init — Die Initialisierungs-Flagge.
Dann gibt es einen Block von Elementen, die für Einstellungen des Kanals verantwortlich sind. - m_prev_frac_num — die Zahl der vorherigen Fraktalen, die für den Bau des ersten Kanals verwendet werden. Wenn der Punkt 3 ist, wird der Kanal unmittelbar nach der Initialisierung gebaut;
- m_bars_beside — Die Anzahl der Bars links / rechts von dem Fraktal. Wenn zum Beispiel 5 angegeben wird, dann werden für die Suche nach dem Fraktal 11 Bars verwendet;
- m_bars_between — Die Anzahl der Zwischenbars. Das heißt, es ist eine Art von Low-Bars, die sich zwischen den benachbarten Fraktalen-Punkten vorhanden sein müssen;
- m_to_delete_prev — Die Erlaubnis für die Löschung der vorherigen Kanäle;
- m_is_alt — Die Flagge eines alternativen Indikators von Fraktalen wird verwendet;
- m_rel_frac — Die Auswahl des aktuellen Punktes. Wenn die Zwischenbars nicht genug waren, wird die Art dieses Punktes angeben, welchen Bar man überspringen muss;
- m_is_array — Die Flagge des Zeichens des Strahls;
- m_line_wid — Die Linienbreite;
- m_to_log — Die Protokollierung-Flagge.
Die Aufzählung, welche die Reihen von Punkten bearbeitet, ist unten dargestellt:
//+------------------------------------------------------------------+ //| Der Typ der Reihe von Extrempunkten | //+------------------------------------------------------------------+ enum ENUM_SET_TYPE { SET_TYPE_NONE=0, // nicht gesetzt SET_TYPE_MINMAX=1, // min-max-min SET_TYPE_MAXMIN=2, // max-min-max };
In diesem Beispiel entspricht der Wert SET_TYPE_MAXMIN auf einer Sequenz der fraktalen Punkte: das Maximum ist, dann das Minimum und wieder das Maximum (Abb.8).
Abb.8 Die Reihe des Typs «max-min-max»
Ich sage sofort, dass die Reihenfolge der Punkte nicht immer gehalten wird. Manchmal kommt es so, dass nach einem Minimum das zweite Minimum kommt. Als Beispiel können wir uns an den dritten Typ der Reihe von Punkten erinnern, der im ersten Abschnitt beschrieben wurde (Abb.4). Auf jeden Fall gehen wir davon aus, dass die volle Reihe, wenn die entweder ein Paar von Minimums und Maximums enthält, oder ein Paar von Maximums und Minimums.
Die Aufzählung, welche die Typen von aktuellen Punkten bearbeitet, ist unten dargestellt:
//+------------------------------------------------------------------+ //| Der Typ des aktuellen Punktes | //+------------------------------------------------------------------+ enum ENUM_RELEVANT_EXTREMUM { RELEVANT_EXTREMUM_PREV=0, // vorherige RELEVANT_EXTREMUM_LAST=1, // letzte };
Betrachten wir die Methoden. Zunächst werden wir die Handler auflisten.
- Init() – Führt die Initialisierung der Reihe aus. Die Methode ist für die korrekte Inbetriebnahme des Objekts verantwortlich, das eine Reihe von fraktalen Punkten darstellt.
- Deinit() - Führt die Deinitialisierung der Reihe aus.
- Process() – kontrolliert den Preis-Context. In der Tat identifiziert diese Methode einen Punkt und zeigt den Kanal.
Utility-Methoden:
- AddFrac() — fügt eine Reihe von fraktalen Punkten hinzu.
- CheckSet() – prüft den aktuellen eingestellten Zustand der Reihe.
- PlotChannel() – zeichnet den gleich entfernten Kanal.
- Crop() – Schneidet die Reihe.
- BubbleSort() — sortiert die Punkte in der Reihe nach dem Zeitpunkt ihres Auftretens.
2.3 Zusätzliche Möglichkeiten des Baus vom Kanal
Wieder einmal erinnere ich Sie daran, dass beim Bau des Kanals und beim Aufruf zu seinen Eigenschaften die Standardbibliothek-Klasse CChartObjectChannel verwendet wurde. Lassen Sie uns ein paar Punkte beachten, deren algorithmische Realisierung das System flexibler zum automatischen Bau der Kanäle machen kann.
2.3.1 Synchronisationslinien
Der bequemste Weg, das Chart mit Kanälen zu einem Zeitpunkt visuell zu bewerten, wenn beide Kanallinien im gleichen Bar beginnen. Formal gesehen, entspricht dieser Ansatz dem vierten Kanaltyp (Abb.5). Selbstverständlich können die Kanäle auch andere Arten sein. Deshalb ist in der Methode CFractalSet::PlotChannel() Preis und Zeitkoordinaten der fraktalen Punkte modifizieren sich, um vierte Kanal-Typ zu werden. Es ist wichtig (es wird realisiert), um die Steigung und die Kanalbreite zu halten.
Betrachten Sie den folgenden gleich entfernten Kanal auf dem Chart (Abb.9).
Abb.9 Der gleich entfernte Kanal auf der Basis der Ausgangspunkte
Ich sage sofort, dass er manuell gebaut wurde. Es gibt hier solche fraktale Punkte:
- $1.05189 vom 2015.12.03 (Minimum);
- $1.07106 vom 2016.01.05 (Minimum);
- $1.10594 vom 2016.01.05 (Maximum).
Wenn wir einen ähnlichen Kanal mit der Klasse CFractalSet anzeigen, erhalten wir das folgende Bild (Abb. 10).
Abb.10 Der gleich entfernte Kanal auf der Basis der Berechnungsspunkte
Die Unterschiede, wenn sie auch klein sind, bestehen darin, dass der Bau des Kanals in Abb.10 durch die Berechnungsspunkte geht. Berechnen Sie den Preis- und Zeit-Wert der zweiten und dritten Punkte. Der letzte Punkt muss nach der Zeit-Koordinate mit dem ersten Punkt zusammenfallen.
Ich werde die Aufgabe für die Erstellung eines Kanals nach berechneten Punkten in 2 Teilen teilen.
Der erste Teil betrifft die zeitlichen Koordinaten - es werden der Anfang und das Ende des Kanals definiert. Bei dieser Methode gibt es einen Codeblock:
//--- 1) Zeitkoordinaten //--- Der Anfang des Kanals int first_date_idx=ArrayMinimum(times); if(first_date_idx<0) { Print("Der Empfangsfehler der Zeit-Koordinaten!"); m_channels_arr.Delete(m_channels_arr.Total()-1); return false; } datetime first_point_date=times[first_date_idx]; //--- Das Ende des Kanals datetime dates[]; if(CopyTime(_Symbol,_Period,0,1,dates)!=1) { Print("Der Empfangsfehler der Zeit des letzten Bars!"); m_channels_arr.Delete(m_channels_arr.Total()-1); return false; } datetime last_point_date=dates[0];
Auf dieser Weise werden alle Punkte die Werte der Zeitkoordinate folgendermaßen haben:
//--- Die endgültigen Zeitkoordinaten times[0]=times[2]=first_point_date; times[1]=last_point_date;
Der zweite Teil des Problems betrifft den Preis-Koordinaten - es wird der neue Preis für den dritten Punkt bestimmt, oder für den ersten.
Zunächst bestimmen wir, wie schnell sich die Kanallinie Preis von Bar zu Bar ändert und wohin der Kanal selbst gerichtet ist - nach oben oder nach unten.
//--- 2) Preis-Koordinaten //--- 2.1 Die Neigung der Linie //--- Bars zwischen dem 1-en und dem 2-en Punkte datetime bars_dates[]; int bars_between=CopyTime(_Symbol,_Period, times[0],times[1],bars_dates ); if(bars_between<2) { Print("Der Empfangsfehler der Anzahl der Bars zwischen den Punkten!"); m_channels_arr.Delete(m_channels_arr.Total()-1); return false; } bars_between-=1; //--- Die Gesamtdifferenz double price_differential=MathAbs(prices[0]-prices[1]); //--- Die Geschwindigkeit des Preises (Preisänderungen im ersten Bar) double price_speed=price_differential/bars_between; //--- Die Richtung des Kanals bool is_up=(prices[0]<prices[1]);
Jetzt können Sie die Preis-Koordinaten der Punkte aktualisieren. Es ist wichtig, zu wissen, welcher Punkt früher gebildet wurde. Außerdem müssen Sie wissen, wohin der Kanal selbst gerichtet ist - nach oben oder nach unten:
//--- 2.2 Der neue Preis des ersten oder des dritten Punktes if(times[0]!=times[2]) { datetime start,end; start=times[0]; end=times[2]; //--- Wenn der dritte Punkt früher war als erste bool is_3_point_earlier=false; if(times[2]<times[0]) { start=times[2]; end=times[0]; is_3_point_earlier=true; } //--- Bars zwischen dem 1-en und dem 3-en Punkte int bars_between_1_3=CopyTime(_Symbol,_Period, start,end,bars_dates ); if(bars_between_1_3<2) { Print("Der Empfangsfehler der Anzahl der Bars zwischen den Punkten!"); m_channels_arr.Delete(m_channels_arr.Total()-1); return false; } bars_between_1_3-=1; //--- Wenn der Kanal aufsteigt if(is_up) { //--- Wenn der dritte Punkt früher war if(is_3_point_earlier) prices[0]-=(bars_between_1_3*price_speed); else prices[2]-=(bars_between_1_3*price_speed); } //--- oder wenn der Kanal absteigt else { //--- Wenn der dritte Punkt früher war if(is_3_point_earlier) prices[0]+=(bars_between_1_3*price_speed); else prices[2]+=(bars_between_1_3*price_speed); } }In unserem Beispiel wurde früher der erste Punkt gebildet, dann müssen Sie den Preis für den dritten Punkt aktualisieren.
Und schließlich aktualisieren Sie die Koordinaten des zweiten Punktes:
//--- 2.3 Der neue Preis des 2-en Punktes if(times[1]<last_point_date) { datetime dates_for_last_bar[]; //--- Bars zwischen dem 2-en Punkt und dem letzten Bar bars_between=CopyTime(_Symbol,_Period,times[1],last_point_date,dates_for_last_bar); if(bars_between<2) { Print("Der Empfangsfehler der Anzahl der Bars zwischen den Punkten!"); m_channels_arr.Delete(m_channels_arr.Total()-1); return false; } bars_between-=1; //--- Wenn der Kanal aufsteigt if(is_up) prices[1]+=(bars_between*price_speed); //--- oder wenn der Kanal absteigt else prices[1]-=(bars_between*price_speed); }
Dann erhalten wir:
- $1.05189 от 2015.12.03 (Minimum);
- $1.10575 von 2016.02.26 (berechneter Wert);
- $1.09864 von 2015.12.03 (berechneter Wert).
Der Kanal kann sowohl ohne Strahlen auf der rechten Seite gezeichnet werden und auch mit ihnen. Allerdings gilt diese Option nur für den aktuellen Kanal. Alle letzten Objekte der Kanäle auf dem Chart werden ohne Strahlen auf der rechten Seite.
2.3.2 Die Berechnung der vergangen fraktalen Punkte
Zu der Klasse CFractalSet wurde die Aufrufsoption der History hinzugefügt und die Suche der fraktalen Punkte nach den gegebenen Parametern. Diese Option wird nur bei der Initialisierung der Klasse-Kopie verwendet. Erinnern daran, dass für die Anzahl der "Punkte der Vergangenheit" (sie können von 0 bis 3 sein) der Mitglied m_prev_frac_num verantwortlich ist.
Betrachten wir das folgende Beispiel (Abb.11). Nehmen wir an, dass direkt nach der Initialisierung des Beraters TestChannelEA ein paar fraktalen Punkte auf dem Chart gefunden werden müssen. Diese Fraktale können mit entsprechenden Zahlen bezeichnet werden.
Abb.11 Die fraktalen Punkte während der Initialisierung
Wenn wir alle drei Punkte nehmen, dann bauen wir den Kanal (Abb.12).
Abb.12 Der erste Kanal während der Initialisierung gebaut
Im Journal sehen wir den Eintrag:
2016.02.25 15:49:23.248 TestChannelEA (EURUSD.e,H4) Es wurden 3 vorherigen Fraktalen hinzugefügt:
Es ist leicht zu sehen, dass die Punkte zur Reihe von rechts nach links hinzugefügt werden. Ein Kanal wird auf der Grundlage der Punkte gebaut, die von links nach rechts gesammelt werden müssen. Die private Methode der Sortierung CFractalSet::BubbleSort() ermöglicht eben, die Punkte bis zum Zeichen des Kanals zu ordnen.
Ein Block des Codes, der für eine Reihe von Punkten bei der Initialisierungsmethode CFractalSet::Init() verantwortlich ist, sieht folgendermaßen aus:
//--- wenn die vorherigen fraktalen Punkte hinzugefügt werden if(m_prev_frac_num>0) { //--- 1) Das Laden der History [start] bool synchronized=false; //--- Der Zähler der Loop int attempts=0; //--- 10 Versuche auf die Synchronisation zu warten while(attempts<10) { if(SeriesInfoInteger(_Symbol,0,SERIES_SYNCHRONIZED)) { synchronized=true; //--- Es gibt eine Synchronisation, verlassen break; } //--- Erhöhen wir den Zähler attempts++; //--- warten auf 50 Millisekunden vor der nächsten Iteration Sleep(50); } //--- if(!synchronized) { Print("Fehler, die Anzahl der Bars hat man auf _Symbol nicht erhalten",); return false; } int curr_bars_num=Bars(_Symbol,_Period); if(curr_bars_num>0) { PrintFormat("Die Anzahl der Bars in der History des Terminals aus der Symbolperiode im Moment: %d", curr_bars_num); } //--- 1) Das Laden der History [end] //--- 2) Die berechneten Daten für den angeforderten Indikator [start] double Ups[]; int i,copied=CopyBuffer(m_fractals_ha,0,0,curr_bars_num,Ups); if(copied<=0) { Sleep(50); for(i=0;i<100;i++) { if(BarsCalculated(m_fractals_ha)>0) break; Sleep(50); } copied=CopyBuffer(m_fractals_ha,0,0,curr_bars_num,Ups); if(copied<=0) { Print("Fehler, die obere Fraktalen wurden nicht kopiert. Error = ",GetLastError(), "i=",i," copied= ",copied); return false; } else { if(m_to_log) Print("die oberen Fraktalen wurden kopiert.", " i = ",i," copied = ",copied); } } else { if(m_to_log) Print("die oberen Fraktalen wurden kopiert. ArraySize = ",ArraySize(Ups)); } //--- 2) Die berechneten Daten für den angeforderten Indikator [end] //--- 3) Das Hinzufügen der fraktalen Punkte [start] int prev_fracs_num=AddFrac(curr_bars_num-1); if(m_to_log) if(prev_fracs_num>0) PrintFormat("Das Hinzufügen der vorherigen Fraktalen: %d",prev_fracs_num); //--- Wenn der Kanal angezeigt werden kann if(prev_fracs_num==3) if(!this.PlotChannel()) Print("Der Kanal wurden nicht angezeigt!"); //--- 3) Das Hinzufügen der fraktalen Punkte [end] }
Der kann in drei Unterblocken unterteilt werden:
- Das Laden der Notierungen-History;
- Die Berechnung der Daten des fraktalen Indikators;
- Das Hinzufügen der fraktalen Punkte zur Reihe.
Somit kann bei dem Initialisierungsmoment der Kanal gezeichnet werden. Dafür wird einige Zeit angefordert, insbesondere in den Fällen, in denen die Verkehrsdaten nicht mit dem Server synchronisiert sind.
2.3.3 Die Berechnung der Bars zwischen der benachbarten fraktalen Punkten
In den vorhergehenden Charts wurden die verwendeten fraktalen Punkten (der erste und der zweite sowie der dritte und der vierte) nebeneinander angeordnet. Es ist möglich, einen Filter hinzuzufügen, der die nächsten Punkte herauszufiltert. Das kann der Mitglied m_bars_between sein - Die Anzahl der Zwischenbars zwischen der benachbarten Punkten. Wenn Sie diese Zahl auf 1 gesetzt haben, wird der zweite Punkt nicht in der Reihe sein, und ihr Platzt wird durch momentan dem dritte Punkt ersetzt.
Abb.13 Der erste Kanal im Hinblick auf die Zwischenbars
Wir bauen einen Kanal unter der Bedienung, dass mindestens 1 bar zwischen den benachbarten fraktalen Punkten sein wird (Abb.13). Es stellt sich heraus, dass wir den Punkt nach dem ersten Punkt überspringen müssen, und noch den Punkt, der nach dem zweiten kommen. Sie sind mit Gelb-Tags markiert worden.
Wenn zum Beispiel bei der Protokollierung der erste übersprungene Punkt einen solchen Log-Eintrag hat:
2016.02.25 16:11:48.037 TestChannelEA (EURUSD.e,H4) Der vorherige Punkt wird überspringen: 2016.02.24 12:00 2016.02.25 16:11:48.037 TestChannelEA (EURUSD.e,H4) Die Zwischenbars sind nicht genug. Ein Punkt wurde übersprungen.
Dann wird der gewünschte Kanal schmal und höchstwahrscheinlich nicht sehr funktionell aus der Sicht des Händlers.
Bezüglich des Codes wird die Überprüfung auf die zulässige Anzahl der Zwischenbars im Körper der privaten Methode CFractalSet::CheckSet() durchgeführt.
//--- wenn die Anzahl der Bars zwischen dem letzten und dem aktuellen Punkten überprüft werden muss if(m_bars_between>0) { curr_fractal_num=this.Total(); if(curr_fractal_num>0) { CFractalPoint *ptr_prev_frac=this.At(curr_fractal_num-1); if(CheckPointer(ptr_prev_frac)!=POINTER_DYNAMIC) { Print("Der Empfangsfehler des Objektes des fraktalen Punktes aus der Reihe!"); return -1; } datetime time1,time2; time1=ptr_prev_frac.Date(); time2=ptr_temp_frac.Date(); //--- Bars zwischen Punkten datetime bars_dates[]; int bars_between=CopyTime(_Symbol,_Period, time1,time2,bars_dates ); if(bars_between<0) { Print("Der Empfangsfehler der Daten der Öffnungszeit von Bars!"); return -1; } bars_between-=2; //--- Wenn es auf verschiedenen Bars ist if(bars_between>=0) //--- Wenn die Zwischenbars nicht genug sind if(bars_between<m_bars_between) { bool to_delete_frac=false; if(m_to_log) Print("Die Zwischenbars sind nicht genug. Ein Punkt wird übersprungen."); // ... } } }
Die Variable bars_between nimmt die Anzahl der Bars zwischen zwei benachbarten fraktalen Punkten. Wenn der Wert kleiner als der zulässige ist, wird der Punkt übersprungen. Welcher ist - der aktuelle oder frühere - erfahren wir im nächsten Abschnitt.
2.3.4 Die Auswahl des fraktalen aktuellen Punktes
In dem Fall, in dem die Zwischenbars nicht genug sind und einer der Punkte muss man ignorieren, kann man genau erfahren, welcher Punkt übersprungen wird. In dem obigen Beispiel wurde der ältere Punkt nach der Auftrittszeit übersprungen, denn als aktuelle fraktale Punkt galt der letzte Punkt. Lassen Sie uns den vorhergehenden Punkt als aktuelle Punkt tun und sehen wir mal, was passiert (Abb.14).
Abb.14 Der erste Kanal im Hinblick auf die Zwischenbars und auf den vorhergehenden Punkt
Zum Beispiel, für den ersten übersprungenen Punkt im Journal erhalten wir einen solchen Eintrag:
2016.02.25 16:46:06.212 TestChannelEA (EURUSD.e,H4) Der aktuelle Punkt wird überspringen: 2016.02.24 16:00 2016.02.25 16:46:06.212 TestChannelEA (EURUSD.e,H4) Die Zwischenbars sind nicht genug. Ein Punkt wurde übersprungen.
Vielleicht ist dieser Kanal nützlicher, weil der alle benachbarten Bars begrenzt. Aber schwer im Voraus zu sagen, welcher aktuelle Punkt - vorherige oder letzter produktiver beim Kanal-Zeichen sein wird.
Wenn wir auf den Code schauen (und das ist immer noch der Code-Block im Körper der privaten Methode CFractalSet::CheckSet()), dann sehen wir, dass auf das Verhalten der Methode nur 2 Faktoren beeinflussen: der ausgewählter Typ des aktuellen Punktes und Initialisierungsflagge.
//--- Wenn die Zwischenbars nicht genug sind if(bars_between<m_bars_between) { bool to_delete_frac=false; if(m_to_log) Print("Die Zwischenbars sind nicht genug. Ein Punkt wird übersprungen."); //--- wenn der vorherige Punkt aktuell ist if(m_rel_frac==RELEVANT_EXTREMUM_PREV) { datetime curr_frac_date=time2; //--- wenn es die Initialisierung gab if(m_is_init) { continue; } //--- wenn es keine Initialisierung gab else { //--- den aktuellen Punkt entfernen to_delete_frac=true; curr_frac_date=time1; } if(m_to_log) { PrintFormat("Der aktuelle Punkt wird überspringen: %s", TimeToString(curr_frac_date)); } } //--- wenn der letzte Punkt aktuell ist else { datetime curr_frac_date=time1; //--- wenn es die Initialisierung gab if(m_is_init) { //--- den vorherigen Punkt entfernen to_delete_frac=true; } //--- wenn es keine Initialisierung gab else { curr_frac_date=time2; } if(m_to_log) PrintFormat("Der vorherige Punkt wird überspringen: %s", TimeToString(curr_frac_date)); if(curr_frac_date==time2) continue; } //--- Wenn Sie einen Punkt entfernen if(to_delete_frac) { if(!this.Delete(curr_fractal_num-1)) { Print("Fehler bei der Löschung des letzten Punktes in der Reihe!"); return -1; } } }
Im nächsten Abschnitt befassen wir uns mit dem Satz von gleich entfernten Kanälen und wenn man ihre Parameter variiert, kann man das Bild von der Preisgleitung erhalten.
3. Das automatische Zeichen der Gleitkanäle
Um das Zeichen der Kanäle zu testen, wurde die Version EAs unter dem Name ChannelsPlotter erstellt. Das Ergebnis des EAs wurde in Abb.15. dargestellt Offensichtlich ist basierend auf Fraktalen und beim Abwesend eines klaren Trends auf dem Markt, beginnen die Kanäle zu "flackern". Von daher wurde die Möglichkeit hinzugefügt, einen alternativen Indikator von Fraktalen zu verwenden, wo eine andere Anzahl von benachbarten Extremen der Bars gegeben wird. Selbst der Indikator X-bars Fractals wurde aus dem Anfangscodebank genommen.
Abb.15 Die Gleitkanäle auf herkömmlichen Fraktalen
Wenn Sie den EA mit der Wahl eines alternativen Indikators von Fraktalen starten, gibt da ein zufriedenstellendes Ergebnis eine Anzahl-Erhöhung der Bars, die eine Gruppe bildet, um die Extremen zu bestimmen. Wenn wir also in einer Gruppe von 23 Bars einen Fraktal suchen, kann das Bild genauso wie in Abb.16 aussehen.
Abb.16 Die Gleitkanäle auf alternativen Fraktalen
So wird es, je weniger benachbarten Bars in der Bestimmung des Fraktals teilnehmen, desto größer ist der "Kanal"-Rauschen im Chart.
Fazit
In diesem Artikel habe ich versucht, eine Weise anzubieten, das System der gleich entfernten Kanäle zu programmieren. Es wurden einige Nuancen des Zeichens der Kanäle betrachtet. Die Basis der Idee war von Viktor Barishpolt. Im nächsten Artikel betrachten wir die Trading-Signale, die von Gleit-Kanälen erzeugt werden.
Dateiordner:
Meiner Meinung nach, ist es am besten die Dateien im Projekt-Ordner zu erstellen und zu speichern. Zum Beispiel kann es so aussehen: <Verzeichnis_Daten>\MQL5\Projects\ChannelsPlotter. Vergessen Sie nicht, den alternativen fraktalen Indikator X-bars_Fractals zu kompilieren. Der Anfangsindikator muss im Ordner der Indikatoren <Verzeichnis_Daten>\MQL5\Indicators sein.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1862
- 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.