MetaTrader 5 herunterladen

Hat Dir der Artikel gefallen?
Teile ihn mit den anderen -
poste einen Link zu diesem Beitrag!

Nutze neue Möglichkeiten der Plattform MetaTrader 5

Der Indikator für "Spindles" Charting

16 Mai 2016, 15:18
Dmitriy Zabudskiy
0
235
Der Indikator für "Spindles" Charting

Einführung

Das Spindel-Chart gehört zu sogenannten Volumen-Preis-Charts. Volumen-Preis ist ein solches Chart, das ein Symbol der Aktivitätsdaten in Form von Volumen (allgemein Tick Volumen) und einen oder mehrere Preise beim Charts-Aufbau verwendet. Es kommt so etwas wie Marktprofil heraus. Surfen im Internet hat nicht zu viele nützliche Informationen gebracht, es geht da vor allem um die Aspekte des Charts. So können wir sagen, dass das Chart relativ vor kurzer Zeit entstanden ist und deshalb verdient Aufmerksamkeit.

Ich erhielt die Informationen über das Chart von einem Leser, der nach der Erstellung eines solchen Indikators gefragt hat. Wegen des Mangels an freien Zeit und der Komplexität der Realisierung hat die Erstellung des Indikators etwas länger gedauert.

Das Spindel-Chart sieht wie ein Chart der japanischen Kerzen aus, da sind auch Eröffnungspreise und Exit-Price sowie Minima und Maxima. Allerdings dazu wird noch der Mittelpreis für Volumen (Volume Weighted Moving Average — VWMA) und der Koeffizient des Volumens (Volume Ratio — VR) verwendet, wodurch eine Form gebildet wird, die wie eine Spindel aussieht (Abb. 1).

in Abb. 1. Der Vergleich der "japanischen Kerzen" mit "Spindel"

in Abb. 1. Der Vergleich der "japanischen Kerzen" mit "Spindel"

Wie wir im Bild 1 sehen können, werden 2 hinzugefügte Parameter (VWMA — der Mittelpreis für Volumen und VR — der Koeffizient des Volumens) die Kerzen nur ergänzen. Dadurch entsteht eine neue Form, die wie ein Drehkreisel aussieht, welchen jeder seit der Kindheit kennt. Dies ist die so genannte "Spindel".

Betrachten wir, wie VR und VWMA gebildet werden. Der Mittelpreis für Volumen (VWMA) ist nichts anderes als eine Art des gleitenden Mittelwerts und wird nach der Formel (1) berechnet:

Die Berechnung VWMA

wo P — der Preis ist, und V — Volumen ist. Wörtlich wird es ungefähr so gesagt: "Der Mittelpreis für Volumen ist gleich der Summe aller Multiplikationen des Preises durch das Volumen in der gegebenen Periode, geteilt durch die Summe der Volumen der gleichen Periode".

Der Koeffizient des Volumens (VR) — ist eine Art eines gleitenden Mittelwerts, aber es wird auf dem Chart anders dargestellt, erstens, weil es keine Preisspanne hat, und zweitens, weil es für die Aktivität des Marktes bezüglich der vorherigen Perioden verantwortlich ist, deshalb ist es am besten entweder auf einem separaten Chart als Tick-Volumen oder wie die Breite jeder Spindel anzuzeigen. Es wird durch die Formel (2) berechnet:

Die Berechnung VR

wo V — Volumen. Es kommt heraus: "Der Koeffizient des Volumens ist dem aktuellen Volumen gleich, geteilte durch den arithmetischen Mittelwert der Volumens der gewählten Periode".

So, nach all diesen Manipulationen erhalten wir ein Chart der "Spindels" (Abb. 2).

in Abb. 2. Spindels-Chart

in Abb. 2. Spindels-Chart

Es wäre die Frage zur Recht: "Warum wurden die Spindels in Abbildung 2 nicht in Farbe gefüllt, wie es in Abbildung 1 ist?". Diese Frage wird im nächsten Kapitel enthüllt — Die Grundlagen des Zeichnens.


Die Grundlagen des Zeichnens

Für einen benutzerdefinierten Indikator in MQL5 gibt es sieben Aufbau-Style (Linie, Abschnitt, Histogramm, Pfeil, gefüllter Bereich, Bars und japanische Kerzen), aber keiner von ihnen erfüllt die Zeichens-Anforderungen des Spindels-Charts. Dies bedeutet, dass ein eigener Style erstellt werden muss. Leider gibt es keinen eingebauten Style-Konstrukteur, aber es gibt viele andere Funktionen, mit denen einen eigenen Style gemacht werden kann, der generell von dem eingebauten, in der Geschwindigkeit, Funktionalität und Zeichens-Qualität unterscheidet.

Es wurde die Entscheidung getroffen, die Bildung des Styles mit Hilfe des Objektes "Bild" zu organisieren. Der Nachteil einer solchen Entscheidung ist erstens die Verwendung des erheblichen Speichervolumens und zweitens ist die relative Komplexität des Zeichnens, und vom ersten Nachteil kommen andere Probleme mit Geschwindigkeit und Stabilität. Der Vorteil des Objektes "Bild" vor anderen Objekten ist die Möglichkeit, in einem bestimmten Raum das Zeichen zu beschränken, und auch einen Teil des Objekts durchsichtig zu verwenden. Dies sind eben die nötigen Vorteile, um das Chart der Spindels zu organisieren.

Die visuelle Darstellung einer "Spindel" ist in der Abbildung 1 gezeigt, der Körper der "Spindel" ist vollständig gefüllt. Dieses Zeichen ist sehr kompliziert und anspruchsvoll, um das durch das Objekt "Bild" zu realisieren. Schauen wir mal, wie es in der Abbildung 3 dargestellt ist:

in Abb. 3. Die technische Darstellung einer "Spindel" mit Hilfe des Objektes "Bild"

in Abb. 3. Die technische Darstellung einer "Spindel" mit Hilfe des Objektes "Bild"

Die Abbildung 3 zeigt drei mögliche Varianten der technischen Darstellung der "gefüllten Spindel", wo:

  • p — Die Objektankerpunkte des "Bild";
  • x — Die Winkel von verwendeten Bildern, um das Bild zu bilden;
  • Die römischen Ziffern zeigen die Bildungsteile der "Spindel".

Also, um die erste Spindel (Abb. 3, a) zu zeichnen, nennen wir es "mollig Raute", brauchen wir vier Objekte der Typ "Bild" (Abb. 3, a; Teile: I, II, III, IV). Dabei Je nach Art des Rhombus, dessen Breite und Höhe (das heißt, Open, Close, VWMA und VR) braucht man Bilder aus verschiedenen Winkeln (Abb. 3, a; Winkels: x1, x2, x3, x4). Das Bild ist ein genaueres Quadrat-Bild im Format von BMP, in dem ein Strahl aus einem bestimmten Winkel im Verhältnis von einem Winkel zu einer der nächsten Seiten kommt und teilt das Quadrat in zwei Bereichen: gefärbten und durchsichtigen.

Die Berechnung eines bestimmten Bildes wird unten diskutiert. Allerdings ist es schon klar, dass dieses Zeichen-Modell bei unterschiedlichen Werten seiner Breite und Höhe (dh Open, Close, VWMA und VR) 360 Bitmaps erfordert (basierend auf der Genauigkeit von einem Grad) wenn wir für mit einer einzelnen Farbe rechnen und mit zwei Farben wird es 720 Bitmaps sein.

Es ist viel komplizierter mit der zweiten "Spindel" (in Abb. 3, b), trotz der Tatsache, dass die Bildung der Figur (nennen wir sie "Pfeilspitze") aus zwei Teilen besteht. Es gibt hier viel mehr Winkelkombinationen, da es notwendig ist, den Abstand zwischen Eröffnungspreisen und Exit-Preisen zu berücksichtigen. Das weitere Zeichen braucht man nicht zu betrachten (in Abb.3, c), weil ein alternatives Zeichen zur Verfügung steht.

Im dritten Fall (in Abb. 3, c) wird das Zeichen in vier Teilen realisiert, die ersten beiden (I und II) Teile die gleiche wie in "mollige Rhombus" sind, und die beiden letzten (III und IV) decken nur die restlichen Teile von den ersten ab. Es besteht bei solchen Realisierung eine Möglichkeit, die benachbarten Spindeln zu überlappen, und es gibt auch eine Bindung mit dem Hintergrund. Insgesamt sind 180 Teile, die wie in der "mollige Rhombus" sind und 180 Teile zum Abdecken.

In der Regel wird die Realisierung eines Spindelcharts 900 Bitmaps benötigen, wenn wir damit einen einzelnen Charthintergrund anwenden, was wiederum sehr anspruchsvoll ist.

Betrachten wir nun eine wenigerer komplizierte und eine schnellere Version des Zeichens mit ungefüllten "Spindeln" (Abb. 2). Im Voraus gesagt, ist die Anzahl der genauen Bilder 360 (180 von einer Farbe und 180 von der anderen), unabhängig vom Hintergrund des Charts.

in Abb. 4. Die technische Darstellung einer "Spindel" mit Hilfe des Objektes "Bild"

in Abb. 4. Die technische Darstellung einer "Spindel" mit Hilfe des Objektes "Bild"

Genauso wie in der vorherigen Variante wird die "ungefüllte Spindel" aus vier Bildern gezeichnet, die in Form von Farblinien in unterschiedlichen Winkeln (0 bis 180) dargestellt sind. Es besteht keine Notwendigkeit, 360 genaue Bilder zu zeichnen, denn der Winkel variiert sich in Abhängigkeit von dem Ankerpunkt des Objekts. Es gibt nur zwei Ankerpunkten (in Abb. 4, p1 und p2): Zwei Objekte zu einem Punkt, zwei für den anderen.

Lassen Sie mich noch einmal erklären, warum hier weniger genaue Bilder verwendet werden. Stellen Sie sich vor, dass es in der Abbildung 4 (a)-eine symmetrische Rhombus ist, dann ist das Teil I mit dem Teil IV ersetzt werden könnte. Um das zu tun, wäre es notwendig, den Ankerpunkt von der oberen rechten Ecke in die linke untere Ecke des Objekts zu ändern. Als Ergebnis müssen wir dann nur insgesamt 180 Objekte der gleichen Farbe vorbereiten und den Ankerpunkt je nach der Verwendungsseite ändern.

Jetzt kommt ein bisschen Mathematik, genauer gesagt Geometrie. Betrachten wir den Prozess der Berechnung und die Auswahl eines Bildes, um eine "ungefüllte Spindel" zu zeichnen (Abb. 5 und 6).

in Abb. 5. Mathematische Berechnung der "mollige Rhombus"

in Abb. 5. Mathematische Berechnung der "mollige Rhombus"

Die Abbildung 5 zeigt die bereits bekannte "mollige Rhombus" (a) und ihre rechten Seite (b). Alle markierten Abstände (a, b, c, d) sind leicht zu berechnen, wenn Open, Close, VWMA und VR bekannt sind, d.h:

  • a = Close - VWMA,
  • b = VWMA - Open,
  • c = Close - Open,
  • d = VR / 2.

Wenn wir Seiten a, b, d, kennen, kann man die Hypotenuse in der rechten Dreiecke e und f mit den Formeln 3.1 und 3.3 berechnen. Das heißt, wir wissen, dass die Kathete in einem rechtwinkligen Dreieck geteilte durch Hypotenuse entspricht dem Sinus des entgegengesetzten Winkels, dadurch berechnen wir die Sinus des Winkels x1 und x2 mit den Formeln 3.2 und 3.4. Als nächstes finden wir in einer Tabelle oder mit einem Rechner die Winkeln x1 und x2, und durch x2 berechnen wir x3. Das gleiche System wird verwendet, um die "Pfeilspitze" zu zeichnen:

in Abb. 6. Mathematische Berechnung der "Pfeilspitze"

in Abb. 6. Mathematische Berechnung der "Pfeilspitze"

Nach den Grundlagen des Zeichnens, lassen Sie uns bitte den Code des Indikators analysieren.


Der Code des Indikators

Bevor Sie den Code schreiben, war es notwendig, grafische Ressource des Indikators vorzubereiten - 540 х 540 Pixel Größe Bilder im BMP-Format mit durchsichtigen Hintergrund. Die Bilder enthalten einen Strahl, der aus einer Ecke erstreckt. In den ersten 89 Bildern wird der Strahl von der linken oberen Ecke erstrecken und ändert dabei den Winkel von 1 bis 89 Grad. In den zweiten 89-Bilder wird der Strahl von der linken unteren Ecke erstrecken, dessen Winkel sich von 91 bis 179 Grad ändert (1-89 Grad relativ zur horizontalen). Die Bilder mit Winkeln von 0, 90, 180 haben Größen von 1 x 540 Pixel und 540 х 1 Pixel und brauchen keinen durchsichtigen Hintergrund.

Insgesamt sind 362 Bilder - 181 Bilder von einer Farbe und 181 Bilder der anderen (Die Bilder 1 und 181 sind gleich). Die Dateinamen wurden unter Berücksichtigung der Linien-Farben (rot - das erste Zeichen "r" und Blau - das erste Zeichen "b") ausgewählt und dabei wird auch der Winkel berücksichtigt, wie er positioniert ist (0 - 180 Grad).


Das erste Teil

Das erste Teil des Codes erreicht die Funktion OnInit. Betrachten Sie alle Stufen:

  • Die Bezeichnung der bestimmten Parameter (#property), in diesem Fall - 11 Puffers und 4 Arten von grafischen Zeichen (ein Histogramm und drei Linien).
  • Das Hinzufügen der Ressourcen zur aufgeführten Datei (#resource), die sind hier viel, wie erwähnt 362 Dateien. Bitte beachten Sie, dass jede Datei auf einer separaten Zeile hinzugefügt werden muss, sonst wird sie nicht hinzugefügt. Aufgrund dieser Tatsache wurden die meisten Zeilen mit Punkten ersetzt.
  • Als nächstes kommen das Menü der Eingangsparameter, die verwendeten Variablen und Puffers.
//+------------------------------------------------------------------+
//|                                                          SPC.mq5 |
//|                                   Azotskiy Aktiniy ICQ:695710750 |
//|                          https://login.mql5.com/ru/users/aktiniy |
//+------------------------------------------------------------------+
#property copyright "Azotskiy Aktiniy ICQ:695710750"
#property link      "https://login.mql5.com/ru/users/aktiniy"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 11
#property indicator_plots 4
//---
#property indicator_label1  "Shadow"
#property indicator_type1   DRAW_COLOR_HISTOGRAM2
#property indicator_color1  clrRed,clrBlue,clrGray
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//---
#property indicator_label2  "Open"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//---
#property indicator_label3  "Close"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrBlue
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//---
#property indicator_label4  "VWMA"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrMagenta
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1
//--- Laden wir die Ressource-Daten
#resource "\\Images\\for_SPC\\b0.bmp";
#resource "\\Images\\for_SPC\\b1.bmp";
#resource "\\Images\\for_SPC\\b2.bmp";
#resource "\\Images\\for_SPC\\b3.bmp";
//...
//...
//...
#resource "\\Images\\for_SPC\\b176.bmp";
#resource "\\Images\\for_SPC\\b177.bmp";
#resource "\\Images\\for_SPC\\b178.bmp";
#resource "\\Images\\for_SPC\\b179.bmp";
#resource "\\Images\\for_SPC\\b180.bmp";
#resource "\\Images\\for_SPC\\r0.bmp";
#resource "\\Images\\for_SPC\\r1.bmp";
#resource "\\Images\\for_SPC\\r2.bmp";
#resource "\\Images\\for_SPC\\r3.bmp";
//...
//...
//...
#resource "\\Images\\for_SPC\\r176.bmp";
#resource "\\Images\\for_SPC\\r177.bmp";
#resource "\\Images\\for_SPC\\r178.bmp";
#resource "\\Images\\for_SPC\\r179.bmp";
#resource "\\Images\\for_SPC\\r180.bmp";
//+------------------------------------------------------------------+
//| Type Drawing                                                     |
//+------------------------------------------------------------------+
enum type_drawing
  {
   spindles=0,       // Spindels
   line_histogram=1, // Linien und Histogram
  };
//+------------------------------------------------------------------+
//| Type Price                                                       |
//+------------------------------------------------------------------+
enum type_price
  {
   open=0,   // Open
   high=1,   // High
   low=2,    // Low
   close=3,  // Close
   middle=4, // Middle
  };
//--- Eingabeparameter
input long         magic_numb=65758473787389; // Die Magic-Nummer
input type_drawing type_draw=0;               //Der Zeichentyp des Indikators
input int          period_VR=10;              // Die Bildungsperiode des Volumen-Koeffizient 
input int          correct_VR=4;              // Die Korrekturzahl für den Volumen-Koeffizient
input int          period_VWMA=10;            // Die Bildungsperiode des Mittelpreises für Volumen
input int          spindles_num=1000;         // Die Anzahl der Spindels
input type_price   type_price_VWMA=0;         // Der Preis-Typ des Mittelpreises für Volumen
                                              // open=0; high=1; low=2; close=3; middle=4
//--- Ausgangsvariablen
int ext_period_VR=0;
int ext_correct_VR;
int ext_period_VWMA=0;
int ext_spin_num=0;
int long_period=0;
//--- Variablen des Chartsparameters
double win_price_max_ext=0; // Der Maximalwert des Charts
double win_price_min_ext=0; // Der Minimalwert des Charts
double win_height_pixels_ext=0; // Die Höhe in Pixel
double win_width_pixels_ext=0;  // Die Breite in Pixel
double win_bars_ext=0; // Die Breite in Pixel
//--- Hilfsvariablen
int end_bar;
//--- Indikatorpuffers
double         Buff_up[];   // Der Puffer der oberen Punkte des Histogramms
double         Buff_down[]; // Der Puffer der unteren Punkte des Histogramms
double         Buff_color_up_down[]; // Der Puffer der Farbe des Histogramms
double         Buff_open_ext[];  // Der Ausgabepuffer der Eröffnungspreise
double         Buff_close_ext[]; // Der Ausgabepuffer der Exit-Preise
double         Buff_VWMA_ext[];  // Der Ausgabepuffer des Mittelpreises für Volumen
double         Buff_open[];  // Der Puffer der Eröffnungspreise
double         Buff_close[]; // Der Puffer der Exit-Preise
double         Buff_VWMA[];  // Der Puffer des Mittelpreises für Volumen
double         Buff_VR[];   // Der Puffer des Volumen-Koeffizient
double         Buff_time[]; // Der Puffer der Eröffnungszeit des Bars

Sie können sehen, dass es nur wenige Eingabeparameter gibt:

  • Die Magic-Nummer - wird für verschiedene Indikatoren eingegeben;
  • Der Zeichentyp des Indikators — kann eine klassische Ansicht (Spindels) sein oder die gleichen Punkte in Form von Linien sein;
  • Die Bildungsperiode des Volumen-Koeffizienten - die Periode für das Zeichen VR;
  • Die Korrekturzahl für den Volumen-Koeffizient — da Volumen VR die Breite betrifft, kann man ihn mit diesem Parameter einstellen;
  • Die Bildungsperiode des Mittelpreises für Volumen - die Periode für das Zeichen VWMA;
  • Die Anzahl der Spindels — um die Belastung des Systems zu verringern, kann man die Anzahl der angezeigten Spindels reduzieren;
  • Der Preis-Typ des Mittelpreises für Volumen — die Auswahl des Preis-Typs für das Zeichen VWMA.

Die Ausgangsvariablen werden für die Korrektur und die Einstellung der Eingabeparameter erfordert. Die Variablen des Chartsparameters, welche die Änderungen des Indikator-Fensters folgt. Warum das benötigt wird, erfahren wir im nächsten Abschnitt.

Die Erklärung der Indikatorpuffers schließt den ersten Teil des Codes. Es gibt 11 Puffer hier.


Die Funktion OnInit

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Überprüfung, ob es Eingangsvariablen gibt
   if(period_VR<=0)
     {
      ext_period_VR=10; // Die Änderung des Wertes der Variablen
      Alert("Die Bildungsperiode des Volumen-Koeffizient ist die Eingabe falsch geworden und wurde geändert.");
     }
   else ext_period_VR=period_VR;
   if(correct_VR<=0)
     {
      ext_correct_VR=10; // Die Änderung des Wertes der Variable
      Alert("Die Korrekturzahl für den Volumen-Koeffizient ist die Eingabe falsch geworden und wurde geändert.");
     }
   else ext_correct_VR=correct_VR;
   if(period_VWMA<=0)
     {
      ext_period_VWMA=10; // Die Änderung des Wertes der Variable
      Alert("Die Bildungsperiode des Mittelpreises für Volumen ist die Eingabe falsch geworden und wurde geändert.");
     }
   else ext_period_VWMA=period_VWMA;
   if(spindles_num<=0)
     {
      ext_spin_num=10; // Die Änderung des Wertes der Variable
      Alert("Die Anzahl der Spindels ist die Eingabe falsch geworden und wurde geändert.");
     }
   else ext_spin_num=spindles_num;
//--- Die Suche nach der längsten Periode für das Zeichnen des Charts
   if(ext_period_VR>ext_period_VWMA)long_period=ext_period_VR;
   else long_period=ext_period_VWMA;
//--- indicator buffers mapping
   SetIndexBuffer(0,Buff_up,INDICATOR_DATA);
   SetIndexBuffer(1,Buff_down,INDICATOR_DATA);
   SetIndexBuffer(2,Buff_color_up_down,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(3,Buff_open_ext,INDICATOR_DATA);
   SetIndexBuffer(4,Buff_close_ext,INDICATOR_DATA);
   SetIndexBuffer(5,Buff_VWMA_ext,INDICATOR_DATA);
   SetIndexBuffer(6,Buff_open,INDICATOR_CALCULATIONS);
   SetIndexBuffer(7,Buff_close,INDICATOR_CALCULATIONS);
   SetIndexBuffer(8,Buff_VWMA,INDICATOR_CALCULATIONS);
   SetIndexBuffer(9,Buff_VR,INDICATOR_CALCULATIONS);
   SetIndexBuffer(10,Buff_time,INDICATOR_CALCULATIONS);
//--- Einstellung den Namen des Indikators
   IndicatorSetString(INDICATOR_SHORTNAME,"SPC "+IntegerToString(magic_numb));
   PlotIndexSetString(0,PLOT_LABEL,"SPC");
//--- Einstellung der Genauigkeit
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1);
//---die Bestimmung des ersten Bars, von dem der Indikator entsteht
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,long_period+1);
//--- Verbieten die Ergebnisse der aktuellen Werte für den Indikator anzuzeigen
   PlotIndexSetInteger(0,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(1,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(2,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(3,PLOT_SHOW_DATA,false);
//--- Einstellen wir die Werte, die im Chart nicht angezeigt werden
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0);
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,0);
   PlotIndexSetDouble(3,PLOT_EMPTY_VALUE,0);
//--- Erstellung der verwendeten Objekte
   if(type_draw==0)
     {
      for(int x=0; x<=ext_spin_num; x++)
        {
         ObjectCreate(0,"SPC"+IntegerToString(magic_numb)+IntegerToString(x)+"1",OBJ_BITMAP,ChartWindowFind(),__DATE__,0);
         ObjectCreate(0,"SPC"+IntegerToString(magic_numb)+IntegerToString(x)+"2",OBJ_BITMAP,ChartWindowFind(),__DATE__,0);
         ObjectCreate(0,"SPC"+IntegerToString(magic_numb)+IntegerToString(x)+"3",OBJ_BITMAP,ChartWindowFind(),__DATE__,0);
         ObjectCreate(0,"SPC"+IntegerToString(magic_numb)+IntegerToString(x)+"4",OBJ_BITMAP,ChartWindowFind(),__DATE__,0);
        }
     }
//---
   return(INIT_SUCCEEDED);
  }

Hier überprüfen wir die Richtigkeit der eingegebenen Parameter, falls es nötig ist, korrigieren sie durch die zuvor deklarierten Variablen (Ausgangsvariablen). Finden Sie heraus, welche der bisher verwendeten Perioden größer ist, initialisieren die Puffers und konfigurieren Sie das Aussehen des Indikators. Erstellen grafische Objekte mit in einem kleinen Array, um mit ihnen weiter zu arbeiten (begrenzt durch den Parameter "Anzahl der Spindels").


Die Funktion OnChartEvent

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Keypress Ereignis
   if(id==CHARTEVENT_KEYDOWN)
     {
      if(lparam==82)
        {
         if(ChartGetDouble(0,CHART_PRICE_MAX,ChartWindowFind())>0)// Überprüfen wir das Vorhandensein der Daten auf dem Chart
           {
            if(func_check_chart()==true)
              {
               if(type_draw==0)func_drawing(true,ext_spin_num,end_bar);
              }
           }
        }
     }
  }

Diese Funktion bindet der Taste "R" (Code 82) Aktualisierung des Charts, oder genauer gesagt - neu zu zeichnen. Es dient zur Korrektur (neu gezeichnet) des Charts, wenn die Fenstergröße des Indikators sich ändert. Es ist aufgrund der Tatsache, dass die Bilder dehnen, wenn die Fenstergröße sich ändert. Natürlich wird das Chart auch im Falle eines Preisänderungsereignises neu gezeichnet, aber manchmal ist es notwendig, um das Zeichen schnell zu aktualisieren. Dafür braucht man diese Funktion.

Die Funktion selbst besteht aus if-else Bedingungsoperatoren vollständig und enthält eine Funktion, welche die Änderungen der Abmessungen des Anzeigefensters (func_check_chart) sowie eine Chartzeichenfunktion (func_drawing) überprüft.


Die Prüffunktion des Indikatorsfensters

//+------------------------------------------------------------------+
//| Func Check Chart                                                 |
//+------------------------------------------------------------------+
bool func_check_chart()
  {
//--- Die Reaktionsvariable
   bool x=false;
//--- Herauszufinden, die Größe des Charts
   int win=ChartWindowFind(); // Definieren das Pop-Fenster, denn der Indikator funktioniert in einem separaten Fenster
   double win_price_max=ChartGetDouble(0,CHART_PRICE_MAX,win); // Der Maximalwert des Charts
   double win_price_min=ChartGetDouble(0,CHART_PRICE_MIN,win); // Der Minimalwert des Charts
   double win_height_pixels=(double)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,win); // Die Höhe in Pixel
   double win_width_pixels=(double)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS,win); // Die Breite in Pixel
   double win_bars=(double)ChartGetInteger(0,CHART_WIDTH_IN_BARS,win); // Die Breite in Bars

//--- Überprüfen, ob die Werte sich geändert haben
   int factor=(int)MathPow(10,_Digits);// Wir setzen den Multiplikator für die Übersetzung double um den Typ int
   if(int(win_price_max*factor)!=int(win_price_max_ext*factor))
     {
      win_price_max_ext=win_price_max;
      x=true;
     }
   if(int(win_price_min*factor)!=int(win_price_min_ext*factor))
     {
      win_price_min_ext=win_price_min;
      x=true;
     }
   if(int(win_height_pixels*factor)!=int(win_height_pixels_ext*factor))
     {
      win_height_pixels_ext=win_height_pixels;
      x=true;
     }
   if(int(win_width_pixels*factor)!=int(win_width_pixels_ext*factor))
     {
      win_width_pixels_ext=win_width_pixels;
      x=true;
     }
   if(int(win_bars*factor)!=int(win_bars_ext*factor))
     {
      win_bars_ext=win_bars;
      x=true;
     }
   if(func_new_bar(PERIOD_CURRENT)==true)
     {
      x=true;
     }
   return(x);
  }

Diese Funktion wird als ein Signal verwendet, um die Fenstergröße des Indikators zu ändern. Wir finden erstmal die aktuellen Parameter des Fensters (Höhe und Breite in Preis und Pixel) mit Chartsfunktionen (ChartGetInteger und ChartGetDouble), und dann vergleichen sie mit den Werten, die zu vorher deklarierten globalen Variablen gehören (Variablen der Chartsparameter).


Die Kontrollfunktion des grafischen Chart-Zeichens

//+------------------------------------------------------------------+
//| Func Drawing                                                     |
//+------------------------------------------------------------------+
void func_drawing(bool type_action,// Der Typ der Modifikation: 0-letzten zwei, 1-alle
                  int num,         // Die Anzahl der gezeichneten Spindels
                  int end_bar_now) // das aktuelle letzte Bar
  {
   int begin;
   if(end_bar_now>num)begin=end_bar_now-num;
   else begin=long_period+1;
//--- Die Suche des maximalen Wertes VR   
   double VR_max=0;
   for(int x=begin; x<end_bar_now-1; x++)
     {
      if(Buff_VR[x]<Buff_VR[x+1])VR_max=Buff_VR[x+1];
      else VR_max=Buff_VR[x];
     }
//--- Berechnung der Skalierung
   double scale_height=win_height_pixels_ext/(win_price_max_ext-win_price_min_ext);
   double scale_width=win_width_pixels_ext/win_bars_ext;
//--- Das Zeichen (x- Das Teil des Objektnamens, y-Der Datenarraysindex für das Zeichen)
   if(type_action==false)// falsch - die Aktualisierung der letzten zwei Spindels
     {
      for(int x=num-2,y=end_bar_now-2; y<end_bar_now; y++,x++)
        {
         func_picture("SPC"+IntegerToString(magic_numb)+IntegerToString(x),Buff_open[y],Buff_close[y],datetime(Buff_time[y]),Buff_VR[y],VR_max,Buff_VWMA[y],ext_correct_VR,scale_height,scale_width);
        }
     }
//---
   if(type_action==true)// true - Aktualisierung alle Spindels
     {
      for(int x=0,y=begin; y<end_bar_now; y++,x++)
        {
         func_picture("SPC"+IntegerToString(magic_numb)+IntegerToString(x),Buff_open[y],Buff_close[y],datetime(Buff_time[y]),Buff_VR[y],VR_max,Buff_VWMA[y],ext_correct_VR,scale_height,scale_width);
        }
     }
   ChartRedraw();
  }

Die Funktion ist eine Steuerstruktur des Chart-Zeichens. Die Eingabeparameter sind: Der Parameter der Modifikation (entweder die letzten zwei oder alle auf einmal), Die Gesamtmenge der Spindels, der letzte Spindel. Der Parameter der Modifizierung ist hier nur dafür, um den letzten Spindel zu ändern, wenn der Preis sich nur in ihm ändert und dadurch nicht alle Spindels ändern, um die Indikator-Leistung zu erhöhen.

Als nächstes wird berechnet, von welchem Bar es beginnen soll. Wenn es weniger Informationen über die Bars gibt als die Anzahl der Spindels, dann beginnt das Zeichen mit der größten Periode der Chartsbildung.

Dann finden wir den größten Koeffizient des Volumens (Es wird als weiterleitende Parameter der Funktion func_picture erfordert, der unten betrachtet wird) und berechnen wir die Skalierung, um das Chart zu zeichnen. Je nach Parameter der Modifizierung rufen wir die Loop der Modifizierung von Spindels auf (die grafische Objekte, die zuvor mit Hilfe von func_picture erstellt wurden).


Die Funktion des grafischen Chart-Zeichens

//+------------------------------------------------------------------+
//| Func Picture                                                     |
//+------------------------------------------------------------------+
void func_picture(string name,        // der Objektname
                  double open,        // Der Eröffnungspreis des Bars
                  double close,       // Der Exit-Preis des Bars
                  datetime time,      // Die Barszeit
                  double VR,          // Der Wert des Volumen-Koeffizient
                  double VR_maximum,  // Der maximale Wert des Volumen-Koeffizient
                  double VWMA,        // Der Wert des Mittelpreises für Volumen
                  int correct,        // Der Korrekturparameter des Volumen-Koeffizient bei der Darstellung
                  double scale_height,// Die Skalierung der Höhe (in Pixel/Preis)
                  double scale_width) // Die Skalierung der Breite (in Pixel/Bars)
  {
   string first_name;// das erste Buchstabe des Datei-Namens, das beim Zeichen verwendet wird
   string second_name_right;// der Rest des Datei-Namens, der auf der rechten Seite des Zeichens verwendet wird
   string second_name_left; // er Rest des Datei-Namens, der auf der linken Seite des Zeichens verwendet wird
   double cathetus_a;// Kathete a
   double cathetus_b;// Kathete b
   double hypotenuse;// Hypotenuse
   int corner;// Winkel
//--- Finden wir den "Winkel" der Öffnung und Schließung des Bars
   cathetus_b=int(VR/VR_maximum/correct*scale_width);// Die Breite in Pixel
                                                     //picture 540
   if(open<=close) first_name="r";// up-Bar oder Doji
   if(open>close) first_name="b"; // Down-Bar
//---
   if(open<VWMA)// VWMA ist über dem Eröffnungspreis
     {
      cathetus_a=int((VWMA-open)*scale_height);
      hypotenuse=MathCeil(MathSqrt(MathPow(cathetus_a,2)+MathPow(cathetus_b,2)));
      if(hypotenuse<=0) hypotenuse=1;
      corner=int(180-(MathArcsin(cathetus_b/hypotenuse)*360/(M_PI*2)));
      second_name_right=IntegerToString(corner);
      second_name_left=IntegerToString(180-corner);
      func_obj_mod(name+"1","::Images\\for_SPC\\"+first_name+second_name_right+".bmp",int(cathetus_b+1),int(cathetus_a+1),540-int(cathetus_a+2),ANCHOR_LEFT_LOWER,time,open);
      func_obj_mod(name+"2","::Images\\for_SPC\\"+first_name+second_name_left+".bmp",int(cathetus_b+1),int(cathetus_a+1),0,ANCHOR_RIGHT_LOWER,time,open);
     }
   if(open>VWMA)// VWMA ist unter dem Eröffnungspreis
     {
      cathetus_a=int((open-VWMA)*scale_height);
      hypotenuse=MathCeil(MathSqrt(MathPow(cathetus_a,2)+MathPow(cathetus_b,2)));
      if(hypotenuse<=0) hypotenuse=1;
      corner=int((MathArcsin(cathetus_b/hypotenuse)*360/(M_PI*2)));
      second_name_right=IntegerToString(corner);
      second_name_left=IntegerToString(180-corner);
      func_obj_mod(name+"1","::Images\\for_SPC\\"+first_name+second_name_right+".bmp",int(cathetus_b+1),int(cathetus_a+1),0,ANCHOR_LEFT_UPPER,time,open);
      func_obj_mod(name+"2","::Images\\for_SPC\\"+first_name+second_name_left+".bmp",int(cathetus_b+1),int(cathetus_a+1),540-int(cathetus_a+2),ANCHOR_RIGHT_UPPER,time,open);
     }
   if(open==VWMA)// VWMA ist in der gleichen Ebene mit dem Eröffnungspreis
     {
      func_obj_mod(name+"1","::Images\\for_SPC\\"+first_name+"90"+".bmp",int(cathetus_b+1),2,0,ANCHOR_LEFT,time,open);
      func_obj_mod(name+"2","::Images\\for_SPC\\"+first_name+"90"+".bmp",int(cathetus_b+1),2,0,ANCHOR_RIGHT,time,open);
     }
   if(close<VWMA)//  VWMA ist über dem Exit-preis
     {
      cathetus_a=int((VWMA-close)*scale_height);
      hypotenuse=MathCeil(MathSqrt(MathPow(cathetus_a,2)+MathPow(cathetus_b,2)));
      if(hypotenuse<=0) hypotenuse=1;
      corner=int(180-(MathArcsin(cathetus_b/hypotenuse)*360/(M_PI*2)));
      second_name_right=IntegerToString(corner);
      second_name_left=IntegerToString(180-corner);
      func_obj_mod(name+"3","::Images\\for_SPC\\"+first_name+second_name_right+".bmp",int(cathetus_b+1),int(cathetus_a+1),540-int(cathetus_a+2),ANCHOR_LEFT_LOWER,time,close);
      func_obj_mod(name+"4","::Images\\for_SPC\\"+first_name+second_name_left+".bmp",int(cathetus_b+1),int(cathetus_a+1),0,ANCHOR_RIGHT_LOWER,time,close);
     }
   if(close>VWMA)// VWMA ist unter dem Exit-Preis
     {
      cathetus_a=int((close-VWMA)*scale_height);
      hypotenuse=MathCeil(MathSqrt(MathPow(cathetus_a,2)+MathPow(cathetus_b,2)));
      if(hypotenuse<=0) hypotenuse=1;
      corner=int((MathArcsin(cathetus_b/hypotenuse)*360/(M_PI*2)));
      second_name_right=IntegerToString(corner);
      second_name_left=IntegerToString(180-corner);
      func_obj_mod(name+"3","::Images\\for_SPC\\"+first_name+second_name_right+".bmp",int(cathetus_b+1),int(cathetus_a+1),0,ANCHOR_LEFT_UPPER,time,close);
      func_obj_mod(name+"4","::Images\\for_SPC\\"+first_name+second_name_left+".bmp",int(cathetus_b+1),int(cathetus_a+1),540-int(cathetus_a+2),ANCHOR_RIGHT_UPPER,time,close);
     }
   if(close==VWMA)// VWMA ist in der gleichen Ebene mit dem Exit-Preis
     {
      func_obj_mod(name+"3","::Images\\for_SPC\\"+first_name+"90"+".bmp",int(cathetus_b+1),2,0,ANCHOR_LEFT,time,close);
      func_obj_mod(name+"4","::Images\\for_SPC\\"+first_name+"90"+".bmp",int(cathetus_b+1),2,0,ANCHOR_RIGHT,time,close);
     }
  }

Das "Herz" des grafischen Chart-Zeichens - die Berechnungsfunktion und Ersetzung der Bilder von grafischen Objekten. Eben in dieser Funktion wird die Berechnung des Bildes durchgeführt, welches auf einem Bar für das Zeichen des Spindels verwendet wird. Dann wird mit Hilfe der Funktion func_obj_mod das Bild des grafischen Objekts geändert (alle graphischen Objekte wurden am Anfang des Codes erstellt, ist am Ende der Funktion OnInit).

Die Parameter der aktuellen modifizierten Bars werden an die Funktion übergeben, darunter ist der bereits erwähnte maximale Koeffizient des Volumens, der als ein relativer Parameter dient, um die so genannte Kathete bzu berechnen (Bild 5, b; Markiert als Größe d).

Als nächstes werden die Hilfsvariablen für die Berechnung hinzugefügt (das erste Buchstabe ist die Farbe, der Rest ist Dateiname der linken und rechten Seite - der Winkel im Dateinamen, die Kathete a und b, die Hypotenuse und der Winkel), die Farbe des Spindels wird durch einen bedingten Operator if definiert. Dann je nach dem Preisniveaus des Eröffnungspreises und Exit-Preises in Bezug auf den Mittelpreis für Volumen (WVMA) und basiert auf den bekannten Formeln aus den Abbildungen 5 und 6 werden vier Bilder berechnet, es wird auch das grafische Objekt mit Hilfe der Funktion func_obj_mod modifiziert.


Die Funktion der Objektmodifizierung

//+------------------------------------------------------------------+
//| Func Obj Mod                                                     |
//+------------------------------------------------------------------+
void func_obj_mod(string name,             // der Objektname
                  string file,             // Die Verknüpfung zur Datei-Ressource
                  int pix_x_b,             // Sichtbarkeit in X
                  int pix_y_a,             // Sichtbarkeit in Y
                  int shift_y,             // Verschiebung in Y
                  ENUM_ANCHOR_POINT anchor,// Ankerpunkt
                  datetime time,           // Zeitkoordinate
                  double price)            // Preiskoordinate
  {
   ObjectSetString(0,name,OBJPROP_BMPFILE,file);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,pix_x_b);// Sichtbarkeit in X
   ObjectSetInteger(0,name,OBJPROP_YSIZE,pix_y_a);// Sichtbarkeit in Y
   ObjectSetInteger(0,name,OBJPROP_XOFFSET,0);// keine Verschiebung in der X-Achse
   ObjectSetInteger(0,name,OBJPROP_YOFFSET,shift_y);// Stellen die Verschiebung in der Y-Achse ein
   ObjectSetInteger(0,name,OBJPROP_BACK,false);// Zeigen wir es am Vordergrund an
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);// Deaktivieren Drag-Modus
   ObjectSetInteger(0,name,OBJPROP_SELECTED,false);
   ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);// Verstecken den Namen des grafischen Objekts
   ObjectSetInteger(0,name,OBJPROP_ANCHOR,anchor);// Stellen wir den Ankerpunkt ein
   ObjectSetInteger(0,name,OBJPROP_TIME,time);// Stellen wir den Zeitkoordinate ein
   ObjectSetDouble(0,name,OBJPROP_PRICE,price);// Stellen wir den Preiskoordinate ein
  }

Die Funktion ist sehr einfach, sie führt den Austausch die Werte, die ihr gegeben wurden, in der Funktion auf. Die Funktion ist für die Änderung der Objekts-Eigenschaften verantwortlich. Die wichtigsten veränderlichen Eigenschaften sind: das Objektsbild, die Sichtbarkeit und der Ankerpunkt.


Die Funktion OnCalculate

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//--- Überprüfen, ob die Periode-History zur Verfügung steht
   if(rates_total<long_period)
     {
      Alert("Die VR oder VWMA Periode sind größer als Verlaufsdaten, oder die History-Daten werden nicht geladen.");
      return(0);
     }
//--- Die Suche der Position
   int position=prev_calculated-1;
   if(position<long_period)position=long_period; // Die Änderung der Position
//--- Die Hauptloop der Pufferberechnung
   for(int i=position; i<rates_total; i++)
     {
      //--- Füllen wir die Histogrammspuffers
      Buff_up[i]=high[i];
      Buff_down[i]=low[i];
      if(open[i]<close[i])Buff_color_up_down[i]=0;// up-Bar
      if(open[i]>close[i])Buff_color_up_down[i]=1;// Down-Bar
      if(open[i]==close[i])Buff_color_up_down[i]=2;// Doji-bar
      //--- Füllen wir die Hilfspuffers
      Buff_open[i]=open[i];
      Buff_close[i]=close[i];
      Buff_time[i]=double(time[i]);
      //--- Berechnen wir des Volumen-Koeffizient
      double mid_vol=0;
      int x=0;
      for(x=i-ext_period_VR; x<=i; x++)
        {
         mid_vol+=double(tick_volume[x]);
        }
      mid_vol/=x;
      Buff_VR[i]=tick_volume[i]/mid_vol; // die Berechnung VR
      //--- Berechnen wir des Mittelpreises für Volumen
      long vol=0;
      double price_vol=0;
      x=0;
      switch(type_price_VWMA)
        {
         case 0:
           {
            for(x=i-ext_period_VWMA; x<=i; x++)
              {
               price_vol+=double(open[x]*tick_volume[x]);
               vol+=tick_volume[x];
              }
           }
         break;
         //---
         case 1:
           {
            for(x=i-ext_period_VWMA; x<=i; x++)
              {
               price_vol+=double(high[x]*tick_volume[x]);
               vol+=tick_volume[x];
              }
           }
         break;
         //---
         case 2:
           {
            for(x=i-ext_period_VWMA; x<=i; x++)
              {
               price_vol+=double(low[x]*tick_volume[x]);
               vol+=tick_volume[x];
              }
           }
         break;
         //---
         case 3:
           {
            for(x=i-ext_period_VWMA; x<=i; x++)
              {
               price_vol+=double(close[x]*tick_volume[x]);
               vol+=tick_volume[x];
              }
           }
         break;
         //---
         case 4:
           {
            for(x=i-ext_period_VWMA; x<=i; x++)
              {
               double price=(open[x]+high[x]+low[x]+close[x])/4;
               price_vol+=double(price*tick_volume[x]);
               vol+=tick_volume[x];
              }
           }
         break;
        }
      Buff_VWMA[i]=price_vol/vol; // die Berechnung VWMA
      //---
      if(type_draw==1)
        {
         Buff_open_ext[i]=Buff_open[i];
         Buff_close_ext[i]=Buff_close[i];
         Buff_VWMA_ext[i]=Buff_VWMA[i];
        }
      else
        {
         //--- Verringern die Größe der nicht verwendeten Arrays 
         ArrayResize(Buff_open_ext,1);
         ArrayResize(Buff_close_ext,1);
         ArrayResize(Buff_VWMA_ext,1);
         //--- Setzen wir die nicht verwendeten Arrays auf 0 zurück 
         ZeroMemory(Buff_open_ext);
         ZeroMemory(Buff_close_ext);
         ZeroMemory(Buff_VWMA_ext);
        }
     }
   end_bar=rates_total;// Definieren wir die Nummer des letzten Bars 
//---
   if(ChartGetDouble(0,CHART_PRICE_MAX,ChartWindowFind())>0 && type_draw==0)// Überprüfen wir das Vorhandensein der Daten auf dem Indikatorsfenster, um das Zeichen zu beginnen
     {
      func_drawing(func_check_chart(),ext_spin_num,end_bar);
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

Die standarte Funktion des Indikators berechnet und füllt die Puffer mit Daten. Zuerst werden die Perioden VR und VWMA, und auch Daten über Bars überprüft, und falls eine Nichtübereinstimmung auftritt, wird eine Meldung angezeigt. Man sieht weiter die Position, von der man die Puffer-Füllung beginnen muss. Der Histogrammspuffer wird gefüllt, was die höchsten und die niedrigsten Preise bezeichnet. Danach werden die Puffer des Volumen-Koeffizient (VR) und des Mittelpreises für Volumen (VWMA) berechnet und gefüllt, das wird nach den Formeln 1 und 2 durchgeführt(die im Kapitel Einführung definiert wurden).


Weitere Funktionen

Für die mehr richtige Arbeit des Indikators steht die Definition-Funktion des neuen Bars func_new_bar zur Verfügung und es gibt noch die Deinitialisierungsfunktion OnDeinit.

Die Funktion func_new_bar bestimmt die Erscheinung eines neuen Bars im Chart und dient als Hilfsfunktion in func_check_chart.

//+------------------------------------------------------------------+
//| Func New Bar                                                     |
//+------------------------------------------------------------------+
bool func_new_bar(ENUM_TIMEFRAMES period_time)
  {
   static datetime old_times; // Die Speichervariable der alten Werte
   bool res=false;            // Die Variable des Analyseergebnis  
   datetime new_time[1];      // Die Zeit des neuen Bars
   int copied=CopyTime(_Symbol,period_time,0,1,new_time); // Kopieren wir die Zeit des letzten Bars in der Einheit new_time  
   if(copied>0) // Daten wurden kopiert
     {
      if(old_times!=new_time[0]) //  wenn die alte Barszeit der neuen Barszeit nicht gleich ist
        {
         if(old_times!=0) res=true; // Wenn es nicht das erste Start ist, dann true = neue Bar
         old_times=new_time[0];     // Speichern wir die Barszeit
        }
     }
   return(res);
  }
//+------------------------------------------------------------------+

Diese Funktion wurde bereits in früheren Artikeln vorgestellt und benötigt daher keine Kommentare.

Die Funktion OnDeinit dient für die Löschung der grafischen Objekten, die davor in der Funktion OnInit erstellt wurden. Die Funktion ist standart für den Indikator und wird aufgerufen, wenn der Indikator aus dem Chart entfernt wird.

//+------------------------------------------------------------------+
//| OnDeinit                                                         |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Die Löschung der verwendeten Objekte
   if(type_draw==0)
     {
      for(int x=0; x<=ext_spin_num; x++)
        {
         ObjectDelete(0,"SPC"+IntegerToString(magic_numb)+IntegerToString(x)+"1");
         ObjectDelete(0,"SPC"+IntegerToString(magic_numb)+IntegerToString(x)+"2");
         ObjectDelete(0,"SPC"+IntegerToString(magic_numb)+IntegerToString(x)+"3");
         ObjectDelete(0,"SPC"+IntegerToString(magic_numb)+IntegerToString(x)+"4");
        }
     }
  }

Dies schließt den Code des Indikators. Wenn Sie Fragen zum Thema oder Definitionen haben, stellen Sie bitte ihre Fragen über den Artikel in Kommentaren oder kontaktieren Sie durch private Nachrichten.


Expert und Handelsstrategie

Bevor wir eine Trading-Strategie betrachten, überprüfen wir, wie der Expert auf diesem Indikator funktioniert. Der Test wird auf dem Experte durchgeführt, der nur einen Spindel verwendet, um seine Aktionen zu analysieren. Der VR (Volumen-Koeffizient) wird dabei nicht verwendet. Es stellt sich heraus, dass die Analyse in einer Art Muster stattfindet, die aus einem einzigen Spindel bestehen. Es gibt insgesamt 30 solcher Varianten, mehr Details in Abbildung 7:

in Abb. 7. Mögliche Bildungen der "Spindels"

in Abb. 7. Mögliche Bildungen der "Spindels"

Die Spindeltypen können in drei Gruppen und einer Untergruppe (in Abb. 7) aufgeteilt werden. Es wird möglich, wenn wir Unterschiede in Spindels nach "Bewegungsrichtungen der Preise, Eröffnungs- und Schlusskurs bezogen, die bezüglich des gesamten Spindels und des Mittelpreises für Volumen betrachtet wird.

Nehmen wir an, dass der erste Unterschied der Spindeln ihre Farbe ist, d.h. der Aufwärts- oder Rückwärtsmarkt in der beachteten Periode (Abb. 7, Spalte 1). In Abb. 7 in der ersten Spalte (0) - Aufwärts (rot) und (1) - Rückwärts (blau). Die nächste Spalte zeigt Unterschiede im Körper B (Eröffnungs- und Schlusskurs) gegenüber dem Schatten S (die höchsten und die niedrigsten Preise für den Zeitraum). Dieser Unterschied in dem aktuellen Beispiel wird nur in drei Teilen geteilt (Abb. 7, Spalte 2). Die dritte Spalte hält den Vergleich der Ebene VWMA (der Mittelpreis für Volumen) auf den höchsten und den niedrigsten Preisen (High und Low). Er kann über (1) sein, unten (2) und zwischen (3) den höchsten und den niedrigsten Preisen. In der dritten Spalte ist der Spindel (3) kann sich auch durch Erröfnungspreis (Open) und Exit-Preis der Periode bezüglich dem VWMA unterscheiden, wodurch eine weitere Spalte 3-3 (aus Spalte 3 (3) in Abb. 7 gebildet wird.

Mit der Rücksicht auf all den möglichen Kombinationen der oben genannten Unterschiede bekommen wir 30 Arten von Spindeln.

Alle Zahlen in Abbildung 7 sind nach den Ergebnissen einer Funktion in einem Handelsexperte mit nachfolgendem Code zugewiesen.


EA-Parameter

Der gesamte Code wird in Funktionen geteilt, und um die Menge des Codes zu verringern, werden die Funktionen von Unterfunktionen aufgerufen, wodurch ein hierarchischer Baum von Funktionen bildet. Die Eingangsvariablen am Anfang des Codes werden identisch mit den Parametern des Indikators deklariert, und ergänzt nur durch Lotsgröße, Stop-Loss und dreißig Muster von Spindeln. Am Ende werden die Variablen für Indikator-Handle und Puffers zum Daten-Speichern deklariert, die verwendet werden, um das Muster zu bestimmen. 

//+------------------------------------------------------------------+
//|                                                        EASPC.mq5 |
//|                                   Azotskiy Aktiniy ICQ:695710750 |
//|                          https://login.mql5.com/ru/users/aktiniy |
//+------------------------------------------------------------------+
#property copyright "Azotskiy Aktiniy ICQ:695710750"
#property link      "https://login.mql5.com/ru/users/aktiniy"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Type Drawing                                                     |
//+------------------------------------------------------------------+
enum type_drawing
  {
   spindles=0,       // Spindels
   line_histogram=1, // Linien und Histogram
  };
//+------------------------------------------------------------------+
//| Type Price                                                       |
//+------------------------------------------------------------------+
enum type_price
  {
   open=0,   // Open
   high=1,   // High
   low=2,    // Low
   close=3,  // Close
   middle=4, // Middle
  };
//--- input parameters
input long         magic_numb=65758473787389; // Die Magic-Nummer
input type_drawing type_draw=1;               // Der Zeichentyp des Indikators
input int          period_VR=10;              // Die Bildungsperiode des Volumen-Koeffizient 
input int          correct_VR=4;              // Die Korrekturzahl für den Volumen-Koeffizient
input int          period_VWMA=10;            // Die Bildungsperiode des Mittelpreises für Volumen
input int          spindles_num=10;           // Die Anzahl der Spindels
input type_price   type_price_VWMA=0;         // Der Preis-Typ des Mittelpreises für Volumen
                                              // open=0; high=1; low=2; close=3; middle=4
input double lot=0.01;                        // Die Lotsgröße
input int    stop=1000;                       // Stop-Loss
//---
input char   p1=1;                            // Aktionen auf Muster 1-Kauf, 2-Verkauf, 3- Position schließen, 4-nichts tun
input char   p2=1;
input char   p3=1;
input char   p4=1;
input char   p5=1;
input char   p6=1;
input char   p7=1;
input char   p8=1;
input char   p9=1;
input char   p10=1;
input char   p11=1;
input char   p12=1;
input char   p13=1;
input char   p14=1;
input char   p15=1;
input char   p16=1;
input char   p17=1;
input char   p18=1;
input char   p19=1;
input char   p20=1;
input char   p21=1;
input char   p22=1;
input char   p23=1;
input char   p24=1;
input char   p25=1;
input char   p26=1;
input char   p27=1;
input char   p28=1;
input char   p29=1;
input char   p30=1;
//---
int handle_SPC; // Indikator-Handle
long position_type; // Der Typ der Position
//--- Die Puffers für kopierten Werte des Indikators
double         Buff_up[3]; // Der Puffer der oberen Punkte des Histogramms
double         Buff_down[3]; // Der Puffer der unteren Punkte des Histogramms
double         Buff_color_up_down[3]; // Der Puffer der Farbe des Histogramms
double         Buff_open_ext[3]; // Der Ausgabepuffer der Eröffnungspreise
double         Buff_close_ext[3]; // Der Ausgabepuffer der Exit-Preise
double         Buff_VWMA_ext[3]; // Der Ausgabepuffer des Mittelpreises für Volumen
Die Initialisierung des Indikator-Handles wird in OnInit stattfinden. .
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   handle_SPC=iCustom(_Symbol,PERIOD_CURRENT,"SPC.ex5",magic_numb,type_draw,period_VR,correct_VR,period_VWMA,spindles_num,type_price_VWMA);
//---
   return(INIT_SUCCEEDED);
  }


Die Funktion der Orders-Sendung zum Server

Es gibt zwei solcher Funktionen: eine für die Öffnung der Orders, die andere für die Schließung der Positionen. Beide Funktionen werden anhand von Beispielen aus MQL5 Dokumentation und verfügen eine Zusammenarbeit der Handelsanforderungsstruktur und einen Aufruf der Funktion OrderSend mit weiterer Analyse der Ergebnisstruktur.

//+------------------------------------------------------------------+
//| Func Send Order                                                  |
//+------------------------------------------------------------------+
bool func_send_order(ENUM_ORDER_TYPE type_order,// Der Typ des platzierten Orders
                     double volume)             // Volumen des Lots
  {
   bool x=false; // Die Variable für die Antwort
//--- Eingabe der Variable für die Sendung des Orders
   MqlTradeRequest order_request={0};
   MqlTradeResult order_result={0};
//--- Füllung der Variable für die Sendung des Orders
   order_request.action=TRADE_ACTION_DEAL;
   order_request.deviation=3;
   order_request.magic=555;
   order_request.symbol=_Symbol;
   order_request.type=type_order;
   order_request.type_filling=ORDER_FILLING_FOK;
   order_request.volume=volume;
   if(type_order==ORDER_TYPE_BUY)
     {
      order_request.price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
      order_request.sl=order_request.price-(_Point*stop);
     }
   if(type_order==ORDER_TYPE_SELL)
     {
      order_request.price=SymbolInfoDouble(_Symbol,SYMBOL_BID);
      order_request.sl=order_request.price+(_Point*stop);
     }
//--- Den Order absenden
   bool y=OrderSend(order_request,order_result);
   if(y!=true)Alert("Fehler der Orderssendung .");
//--- Überprüfen das Ergebnis
   if(order_result.retcode==10008 || order_result.retcode==10009) x=true;
   return(x);
  }
//+------------------------------------------------------------------+
//| Func Delete Position                                             |
//+------------------------------------------------------------------+
bool func_delete_position()
  {
   bool x=false;
//--- Markieren wir die Position, mit der wir arbeiten werden
   PositionSelect(_Symbol);
   double vol=PositionGetDouble(POSITION_VOLUME);
   long type=PositionGetInteger(POSITION_TYPE);
   ENUM_ORDER_TYPE type_order;
   if(type==POSITION_TYPE_BUY)type_order=ORDER_TYPE_SELL;
   else type_order=ORDER_TYPE_BUY;
//--- Eingabe der Variable für die Sendung des Orders
   MqlTradeRequest order_request={0};
   MqlTradeResult order_result={0};
//--- Füllung der Variable für die Sendung des Orders
   order_request.action=TRADE_ACTION_DEAL;
   order_request.deviation=3;
   order_request.magic=555;
   order_request.symbol=_Symbol;
   order_request.type=type_order;
   order_request.type_filling=ORDER_FILLING_FOK;
   order_request.volume=vol;
   if(type_order==ORDER_TYPE_BUY)order_request.price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   if(type_order==ORDER_TYPE_SELL)order_request.price=SymbolInfoDouble(_Symbol,SYMBOL_BID);
//--- Den Order absenden
   bool y=OrderSend(order_request,order_result);
   if(y!=true)Alert("Fehler der Orderssendung .");
//--- Überprüfen das Ergebnis
   if(order_result.retcode==10008 || order_result.retcode==10009) x=true;
   return(x);
  }

Im Code gibt es auch die Hilfsfunktion func_new_bar, welche die Erscheinung eines neuen Bars im Chart bestimmt. Sie wurde oben beschrieben und erfordert keine Veröffentlichung seines Codes.

Nach der Beschreibung aller standarten Funktionen betrachten wir das "Herz" der Berechnungen.

In der Funktion OnTick läuft die Konsolidierung aller Aktionen. Zuerst werden die Puffer mit der Funktion CopyBuffer gefüllt, die bei den Berechnungen verwendet werden. Als nächstes es wird geprüft, ob es eine Position auf dem aktuellen Symbol gibt, dies ist notwendig, für eine andere Kontrollfunktion der Platzierung und Entfernung (Position). Danach werden die Größen für die Definition der Muster vorbereitet. Dies sind Körper - der Abstand zwischen Eröffnungs- und Schlusskurs, Schatten - der Abstand zwischen den höchsten und den niedrigsten Preisen für die laufende Periode und auch ihr Verhältnis, das später in der Funktion func_one weitergeleitet wird (Abb. 7, Spalte 2).

Danach werden die Funktionen func_two und func_three verwendet, in Abb.7 sind sie die Spalten 3 und 3-3 Danach wird die Farbe des Spindels durch den Schalter switch überprüft, gemäß 7, Spalte 1. Auf diese Weise können wir einen Entscheidungsbaum von Funktionen erhalten, wenn der nächste Schalter switch je nach dem Variable-Wert von afun_1_1 auf func_pre_work (betrachten wir später) schaltet, dies wird entsprechend dem Spalten 2 der Abb. 7 auf der Grundlage der Größen des Körpers und des Schattens durchgeführt.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   if(func_new_bar(PERIOD_CURRENT)==true)
     {
      //--- Kopieren wir die Indiaktorpuffers
      CopyBuffer(handle_SPC,0,1,3,Buff_up);
      CopyBuffer(handle_SPC,1,1,3,Buff_down);
      CopyBuffer(handle_SPC,2,1,3,Buff_color_up_down);
      CopyBuffer(handle_SPC,3,1,3,Buff_open_ext);
      CopyBuffer(handle_SPC,4,1,3,Buff_close_ext);
      CopyBuffer(handle_SPC,5,1,3,Buff_VWMA_ext);
      //--- Analysieren wir die Situation
      //--- Überprüfen wir, ob ein Order platziert wurde
      if(PositionSelect(_Symbol)==true)
        {
         position_type=PositionGetInteger(POSITION_TYPE); // BUY=0, SELL=1
        }
      else
        {
         position_type=-1; //  Keine Position für das Symbol
        }
      //--- Vorbereitung der Werte zu vergleichen
      double body=Buff_open_ext[2]-Buff_close_ext[2];
      body=MathAbs(body);
      double shadow=Buff_up[2]-Buff_down[2];
      shadow=MathAbs(shadow);
      if(shadow==0)shadow=1;// verhindern die Division durch Null
      double body_shadow=body/shadow;
      //--- Die Variablen für die Funktionsantwort
      char afun_1_1=func_one(body_shadow);
      char afun_2_1=func_two(Buff_up[2],Buff_down[2],Buff_VWMA_ext[2]);
      char afun_3_1=func_three(Buff_open_ext[2],Buff_close_ext[2],Buff_VWMA_ext[2]);
      //---
      switch(int(Buff_color_up_down[2]))
        {
         case 0:
           {
            switch(afun_1_1)
              {
               case 1:
                  func_pre_work(afun_2_1,afun_3_1,p1,p2,p3,p4,p5);
                  break;
               case 2:
                  func_pre_work(afun_2_1,afun_3_1,p6,p7,p8,p9,p10);
                  break;
               case 3:
                  func_pre_work(afun_2_1,afun_3_1,p11,p12,p13,p14,p15);
                  break;
              }
           }
         break;
         case 1:
           {
            switch(afun_1_1)
              {
               case 1:
                  func_pre_work(afun_2_1,afun_3_1,p16,p17,p18,p19,p20);
                  break;
               case 2:
                  func_pre_work(afun_2_1,afun_3_1,p21,p22,p23,p24,p25);
                  break;
               case 3:
                  func_pre_work(afun_2_1,afun_3_1,p26,p27,p28,p29,p30);
                  break;
              }
           }
         break;
        }
     }
  }

Die Funktion func_pre_work setzt die Verzweigung des bereits gebildeten Entscheidungsbaums. Wir bekommen eine programmierte Code-Realisierung, die basiert auf 7, Spalten 3 (variable f_2) und 3-3 (variable F_3) ist und wird in der letzten Funktion des Baumes func_work umgeschaltet.

//+------------------------------------------------------------------+
//| Func Pre Work                                                    |
//+------------------------------------------------------------------+
void func_pre_work(char f_2,     // Ergebnis der Funktion Func Two
                   char f_3,     // Ergebnis der Funktion Func Three
                   char pat_1,   // Muster  1
                   char pat_2,   // Muster  2
                   char pat_3_1, // Muster  3_1
                   char pat_3_2, // Muster  3_2
                   char pat_3_3) // Muster  3_3
  {
   switch(f_2)
     {
      case 1: //1
         func_work(pat_1);
         break;
      case 2: //2
         func_work(pat_2);
         break;
      case 3:
        {
         switch(f_3)
           {
            case 1: //3_1
               func_work(pat_3_1);
               break;
            case 2: //3_2
               func_work(pat_3_2);
               break;
            case 3: //3_3
               func_work(pat_3_3);
               break;
           }
        }
      break;
     }
  }

Die Funktion func_work entscheidet, was mit der Position gemacht werden muss, und sucht eine weitere Variante aus: Kauf, Verkauf, Position schließen und nichts zu tun. Hier wird die letzte Kontrolle an den bereits bekannten Funktionen func_send_order und func_delete_position übergeben.

//+------------------------------------------------------------------+
//| Func Work                                                        |
//+------------------------------------------------------------------+
void func_work(char pattern)
  {
   switch(pattern)
     {
      case 1: // Kaufen
         if(position_type!=-1)func_delete_position();
         func_send_order(ORDER_TYPE_BUY,lot);
         break;
      case 2: // Verkaufen
         if(position_type!=-1)func_delete_position();
         func_send_order(ORDER_TYPE_SELL,lot);
         break;
      case 3: //  Position schließen
         if(position_type!=-1)func_delete_position();
         break;
      case 4: // nichts tun
         break;
     }
  }

Es müssen noch die vorher erwähnten Funktionen erklärt werden: func_one, func_two und func_three. Sie wandeln die gesendeten Daten in Form von Preiswerte in ganzzahlige Daten für den Schalter switch. Wenn wir zurück gehen, auf 7, func_one - ist die Realisierung der Säule 2, func_two - der Säule 3 und func_three - der Spalte 3-3. Die Rückgabewerte dieser Funktionen sind ganze Zahlen 1, 2 und 3, die auch den Zahlen von Abb 7 entsprechen.

//+------------------------------------------------------------------+
//| Func One                                                         |
//+------------------------------------------------------------------+
char func_one(double body_shadow_in)
  {
   char x=0; // Die Variable für die Antwort
   if(body_shadow_in<=(double(1)/double(3))) x=1;
   if(body_shadow_in>(double(1)/double(3)) && body_shadow_in<=(double(2)/double(3))) x=2;
   if(body_shadow_in>(double(2)/double(3)) && body_shadow_in<=1) x=3;
   return(x);
  }
//+------------------------------------------------------------------+
//| Func Two                                                         |
//+------------------------------------------------------------------+
char func_two(double up,// high [Buff_up]
              double down,// low [Buff_down]
              double VWMA) // VWMA [Buff_VWMA_ext]
  {
   char x=0; // Die Variable für die Antwort
   if(VWMA>=up) x=1;
   if(VWMA<=down) x=2;
   else x=3;
   return(x);
  }
//+------------------------------------------------------------------+
//| Func Three                                                       |
//+------------------------------------------------------------------+
char func_three(double open,// open [Buff_open_ext]
                double close,// close [Buff_close_ext]
                double VWMA) // VWMA [Buff_VWMA_ext]
  {
   char x=0; // Die Variable für die Antwort
   if(open>=VWMA && close>=VWMA) x=1;
   if(open<=VWMA && close<=VWMA) x=2;
   else x=3;
   return(x);
  }
//+------------------------------------------------------------------+

Nun, da der Expert bereit ist, zu verwenden, testen wir ihn. Zuerst definieren wir die Parameter:

  • Symbol und Zeitrahmen — EURUSD, H1;
  • Testzeitraum — von 01.01.2013 bis 01.01.2015 (2 Jahre);
  • Stop Loss — 1000;
  • Der Server — MetaQuotes-Demo.

Die Optimierung wird nur durch Maßnahmen durchgeführt, und eben durch; Kaufen, verkaufen, Position schließen und nichts zu tun, sowie durch die VWMA-Periode. So werden wir herausfinden, welche Aktionen am profitabelsten für jedes Muster sind und welche die VWMA-Periode am besten geeignet für die Arbeit im Zeitraum H1 ist.

Die Einstellungen des Strategie-Testers sind in Abbildung 8 dargestellt:

in Abb. 8. Die Einstellungen des Strategie-Testers

in Abb. 8. Die Einstellungen des Strategie-Testers

Wie es zuvor erwähnt wurde, wird die Optimierung durch die Aktionen in Abhängigkeit von dem Muster und dem VWMA Zeitraum von 10 bis 500 bar, Abb. 9 durchgeführt:

in Abb. 9. Optimierungsparameter

in Abb. 9. Optimierungsparameter

Im Prozess der Optimierung erhält man ein Chart, Abb 10:

in Abb. 10. Optimierungschart

in Abb. 10. Optimierungschart

Als Ergebnis der Optimierung erhalten wir Gewinn von 138,71, die Lotsgröße von 0,01 und das erste Deposit von 10000, mit dem Verlust von 2,74% (etwa 28 Einheiten), Abbildung 11:

in Abb. 11. Optimierungsergebnisse

in Abb. 11. Optimierungsergebnisse

Lassen Sie uns die Lotsgröße auf 0,1 erhöhen, verringern wir das erste Deposit bis 1000 und führen wir einen zweiten Test durch Parameter aus dem Optimierungsergebnis. Um Genauigkeit des Tests zu erhöhen, lassen Sie uns den Handel-Modus OHLC um M1 ändern, erhalten wir Abbildung 12:

in Abb. 12. Testergebnis (Backtest)

in Abb. 12. Testergebnis (Backtest)

Als Ergebnis wurden über zwei Jahren Zeit 742 Trades (ca. 3 Trades pro Tag) gemacht, während des maximalen Drawdowns 252 war, und der Nettogewinn - 1407, etwa 60 (6% der Gesamtinvestitionen) pro Monat. In der Theorie funktioniert alles ganz gut, aber es gibt keine Garantie, dass es genauso gut in der Praxis wird.

Natürlich muss dieser Experte weiter modernisiert und verbessert werden, vielleicht muss noch ein zusätzlicher Spindel zu dem Muster eingegeben und zur Ebene VR hinzugefügt werden. Das ist die Nahrung für weitere Überlegungen, aber auch bei solchen kleinen Parametern zeigten die Experten einige interessante Ergebnisse auf diesem Indikator.

Die Trading-Strategie während der Arbeit mit dem Indikator ist ganz klar - kaufen, wenn die Pfeilspitze nach oben zeigt und verkaufen, wenn es nach unten zeigt. Der Rhombus ist eine Art von Doji, bedeutet diese eine Wende. Sie können das gut in Abb. 13 sehen:

in Abb. 13. Der Indikator in Aktion

in Abb. 13. Der Indikator in Aktion

Wie Sie bis zur Zahl 1 sehen können(Abb. 13), zeichnet der Indikator Pfeilspitzen, die nach oben eingerichtet sind, dann erscheint eine blaue Raute, die eine mögliche Änderung der Trend-Bewegungsrichtung anzeigt. Der Trend ändert sich, und die Preise gehen nach unten bis zur Nummer 2, dann erscheint eine rote Raute, die auch eine Änderung der Trend ankündigt, so geht es.


Fazit

Ich hatte nur wenige Informationen über den Indikator, aber es hat mich mit seiner Originalität interessiert. Vielleicht hatte auch die Komplexität der Implementierung im Code einen Einfluss, der mir auch denken gemacht hat. Die Zeit wurde nicht umsonst verschenkt, und ich hoffe, dass dieser Indikator für viele Menschen nützlich sein wird. Ich kann davon ausgehen, dass das Thema noch nicht vollständig entwickelt ist, weil es ziemlich groß ist, aber ich denke, das wird schließlich auf dem Forum erledigt. Die besondere Aufmerksamkeit sollte auf die Diskussion und die Modernisierung des Expertes gegeben werden, auch in der Anfangsphase zeigt er ein paar anständige Ergebnisse. Ich freue mich auf Ihre Kommentare und Diskussionen, sowohl unter dem Artikel, als auch in privaten Nachrichten.

Dies war ein weiterer Artikel über das Thema der Indikatoren, wenn jemand irgendwelche Ideen auf neue interessante Indikatoren hat, schreiben Sie mir eine Nachricht. Ich verspreche nicht eine Realisierung, aber ich werde es sicher gucken, und gebe vielleicht einen Ratschlag dazu. Mein nächster Artikel soll radikal das Thema ändern, aber ich werde nicht so weit gehen und darüber reden, denn das ist nur eine Idee, und der Code ist nur in der Planungsphase.

Übersetzt aus dem Russischen von MetaQuotes Software Corp.
Originalartikel: https://www.mql5.com/ru/articles/1844

Beigefügte Dateien |
images.zip (1210.6 KB)
easpc.mq5 (26.64 KB)
spc.mq5 (77.17 KB)
reporttester.zip (125.3 KB)
Markttheorie Markttheorie

Eine logisch vollständige Markttheorie, die alle Arten und Sorten der Märkte für Waren und Dienstleistungen, Mikro und Makro Märkte sowie Forex abdecken würde, stand bisher nicht zur Verfügung. Dieser Artikel behandelt den Kern einer neuen Markt-Theorie, die auf der Gewinnanalyse basiert. Sie enthüllt Muster der aktuellen Kursbewegung und das Prinzip, dass es einem Kurs erlaubt, seinen optimalen Wert durch das Bilden von einer Kette von virtuellen Kursen zu finden, welche einen kontrollierenden Einfluss auf den aktuellen Kurs haben können. Die Mechanismen der Bildung und Veränderung von Markttrends werden hier auch identifiziert.

Einführung in die empirische Bandzerlegung (EMD) Einführung in die empirische Bandzerlegung (EMD)

Dieser Beitrag möchte seine Leser mit dem Verfahren der empirischen Bandzerlegung, der „Empirical Mode Decomposition“ kurz: EMD, vertraut machen. Es handelt sich bei dieser um einen grundlegenden Bestandteil der Hilbert-Huang-Transformation zur Analyse von Daten aus nichtstationären und nichtlinearen Vorgängen. Dieser Artikel beinhaltet zudem eine mögliche Umsetzung dieses Verfahren in Programmform nebst einer Kurzdarstellung seiner Besonderheiten und einiger einfacher Anwendungsbeispiele.

Die Arbeit mit ZIP-Archiven in MQL5 ohne Bibliotheken von Drittanbietern Die Arbeit mit ZIP-Archiven in MQL5 ohne Bibliotheken von Drittanbietern

Die Sprache MQL5 entwickelt sich weiter und es wird zu ihr ständig neue Funktionen hinzugefügt, mit Daten zu arbeiten. Schon seit einiger Zeit ist es wegen Innovationen möglich geworden, mit ZIP-Archiven regelmäßig zu arbeiten, ohne die Beteiligung von Bibliotheken DLL der Drittanbieter. Dieser Artikel beschreibt im Detail, wie das gemacht wird. Als Beispiel ist die Beschreibung der CZIP Klasse - das universelle Werkzeug für das Lesen, Erstellen und Modifizierung der ZIP-Archive.

Die Verwendung der Behauptung (assertions) bei der Entwicklung der Programme in MQL5 Die Verwendung der Behauptung (assertions) bei der Entwicklung der Programme in MQL5

In diesem Artikel wird Behauptung (assertions) im Rahmen der Sprache MQL5 betrachtet. Es werden zwei Beispiele für die Realisierung des Behauptungsmechanismus geben, sowie allgemeine Empfehlungen für die Verwendung der Behauptungen.