Rezepte MQL5 - Programmierung der gleitenden Kanäle

Denis Kirichenko | 24 Juni, 2016

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

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

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

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

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

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

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:

  1. m_date — die Zeit-Koordinate des Punktes auf dem Chart;
  2. m_value — die Preis-Koordinate des Punktes auf dem Chart;
  3. m_extreme_type –  Der Typ des Extremums;
  4. 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

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. 

  1. 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;
  2. m_fractal_num – Die feste Anzahl von Punkten, die in einer Reihe sind;
  3. m_fractals_ha – Die Handle des fraktalen Indikators;
  4. m_new_bar – Das Objekt des neuen Bars;
  5. m_channels_arr – Das Objekt der Arrays von Zeigern;
  6. m_channel_colors[4] — das Array der Farben für die Anzeige der Kanäle;
  7. m_is_init — Die Initialisierungs-Flagge.
    Dann gibt es einen Block von Elementen, die für Einstellungen des Kanals verantwortlich sind.
  8. 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;  
  9. 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;
  10. 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;
  11. m_to_delete_prev — Die Erlaubnis für die Löschung  der vorherigen  Kanäle;
  12. m_is_alt — Die Flagge eines alternativen Indikators von Fraktalen wird verwendet;
  13. 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;
  14. m_is_array — Die Flagge des Zeichens des Strahls;
  15. m_line_wid — Die Linienbreite;
  16. 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.2 Die Reihe des Typs «max-min-max»

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.

  1. 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.
  2. Deinit() - Führt die Deinitialisierung der Reihe aus.
  3. Process() – kontrolliert den Preis-Context. In der Tat identifiziert diese Methode einen Punkt und zeigt den Kanal.

Utility-Methoden:

  1. AddFrac() — fügt eine Reihe von fraktalen Punkten hinzu.
  2. CheckSet() – prüft den aktuellen eingestellten Zustand der Reihe.
  3. PlotChannel() – zeichnet den gleich entfernten Kanal.
  4. Crop() – Schneidet die Reihe.
  5. 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

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. $1.05189 vom 2015.12.03 (Minimum);
  2. $1.07106 vom 2016.01.05 (Minimum);
  3. $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

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. $1.05189 от 2015.12.03 (Minimum);
  2. $1.10575 von 2016.02.26 (berechneter Wert);
  3. $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.9 Die fraktalen Punkte während der Initialisierung

Abb.11 Die fraktalen Punkte während der Initialisierung

Wenn wir alle drei Punkte nehmen, dann bauen wir den Kanal (Abb.12).

Abb.10 Der erste Kanal während der Initialisierung gebaut

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:

  1. Das Laden der Notierungen-History;
  2. Die Berechnung der Daten des fraktalen Indikators;
  3. 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.11 Der erste Kanal im Hinblick auf die Zwischenbars

 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.12 Der erste Kanal im Hinblick auf die Zwischenbars und auf den vorhergehenden Punkt

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.9 Die Gleitkanäle auf herkömmlichen Fraktalen

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.10 Die Gleitkanäle auf alternativen Fraktalen
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.