Indikator für Renko-Diagramme
Einleitung
Die Beiträge Indikator für Punkt- und Zeichendiagramme und Indikator für Kagi-Diagramme beschrieben die Prinzipien für die Zeichnung von Diagramm-Indikatoren der Typen Punkte und Zeichen und "Kagi". Betrachten wir nun die Programmierung von -Diagrammen.
Der Name "Renko" leitet sich vom japanischen Wort "renga" (Ziegel) ab. Das Renko-Diagramm wird aus einer Reihe von Ziegeln konstruiert, deren Erstellung durch Preisschwankungen definiert wird. Wenn ein Preis steigt, wird ein aufwärts gerichteter Ziegel im Diagramm platziert, bei sinkendem Preis ein abwärts gerichteter. "Renko" heißt im Japanischen "langsame Geschwindigkeit". Das Renko-Diagramm ist in Japan vermutlich irgendwann im 19. Jahrhundert erschienen. In den USA und Europa hörte man erstmals davon, nachdem Steve Nison 1994 sein Buch Beyond Candlesticks: New Japanese Charting Techniques Revealed veröffentlichte.
Das Renko-Diagramm und die oben erwähnten Diagramme ignorieren die Zeitskala und richten sich ausschließlich nach der Preisbewegung. Im Gegensatz zum Punkt- und Zeichendiagramm platziert das Renko jeden "Ziegel" in einer neuen Spalte (in einer neuen vertikalen Ebene), für den Rest gibt es eine gemeinsame Erstellungsmethode: Der Preis eines "Ziegels" ("Punkt", "Zeichen") ist fix, die Analyse des Preises und der Aufbau der Zeichen geschieht ähnlich.
Also ist das Renko-Diagramm ein Satz von vertikalen Balken ("Ziegeln"). Weiße (hohle) Ziegel werden verwendet, wenn der Trend aufwärts gerichtet ist, schwarze (ausgefüllte) Ziegel, wenn er abwärts gerichtet ist. Der Aufbau wird durch das Verhalten des Preises gesteuert. Der aktuelle Preis des beobachteten Zeitraums wird mit dem Minimum und Maximum des vorherigen Ziegels (weiß oder schwarz) verglichen. Wenn die Aktie mit einem höheren Preis als ihrem Öffnungspreis schließt, wird ein hohler (weißer) Ziegel gezeichnet, bei dem der untere Teil des Körpers den Öffnungspreis und der obere Teil den Schließungspreis darstellt. Wenn die Aktie mit einem niedrigeren Preis als ihrem Öffnungspreis schließt, wird ein ausgefüllter (schwarzer) Ziegel gezeichnet, bei dem der obere Teil des Körpers den Öffnungspreis und der untere Teil den Schließungspreis darstellt.
Der erste Ziegel des Diagramms wird abhängig vom Verhalten des Preises gezeichnet, der Öffnungspreis des Balkens wird dem Maximum und Minimum des vorherigen Ziegels entnommen.
Ein Beispiel eines standardmäßigen Renko-Diagramms sehen Sie in Abb. 1:
Abb. 1. Beispiel eines standardmäßigen Renko-Diagramms
1. Beispiel der Diagrammzeichnung
Ein standardmäßiges Renko-Diagramm wird basierend auf dem Schließungspreis gezeichnet. Wählen Sie als Erstes den Timeframe und die Box-Größe.
In diesem Beispiel wird EURUSD (H4-Timeframe) mit einer Box-Größe von 30 Punkten verwendet. Das Ergebnis der Zeichnung des Renko-Diagramms von 03.01.2014 bis 31.01.2014 (etwa ein Monat) sehen Sie in Abb. 2. Auf der linken Seite ist das Diagramm eines bestimmten Timeframes abgebildet (hier sehen Sie die horizontale Ausdehnung von Ziegeln), auf der rechten sehen Sie das Ergebnis der Zeichnung des Renko-Diagramms:
Abb. 2 Ergebnis der Zeichnung des Renko-Diagramms auf EURUSD (H4, Box-Größe 30 Punkte)
Sehen wir uns das Prinzip der Diagrammzeichnung näher an. In Abb. 2 zeigen rote horizontale Linien die Größe jedes Ziegels gemäß den Preisveränderungen (30 Punkte). Die interessantesten Daten sind blau gekennzeichnet.
Wie Sie im Diagramm sehen können, schließt eine Kerze am Ende des 03.01.2014 unter 1,3591 der vorher definierten Preisbereiche (rote horizontale Linien) bei 1,3589 (mit Preis markiert), wodurch ein nach unten gerichteter Ziegel im Diagramm erstellt wird.
Anschließend bleibt der Preis flach (er kommt nicht unter 1,3561 oder über 1,3651), er bleibt bis 10.01.2014, 20:00 geöffnet (die um 16:00 erstellte Kerze schließt) und schließt (oberhalb der Preismarkierung bei 1,3651) bei 1,3663 (mit Preis markiert). Anschließend wird der Preis bis 14.01.2014, 20:00 wieder flach (die um 16:00 erstellte Kerze schließt) und übersteigt dann den Preisbereich, erstellt einen neuen Ziegel und schließt bei 1,3684.
Im Anschluss sehen Sie einen nach unten gerichteten Tick, bei dem der Preis bei seiner Abwärtsbewegung im Diagramm vier Preisbereiche überschreitet. Am 23.01.2014 um 12:00 (die um 08:00 geöffnete Kerze schließt) gibt es einen aufwärts gerichteten Durchbruch zweier Preisbereiche, wodurch wiederum zur Schließung bei 1,3639 zwei Ziegel geöffnet werden. Der erste Ziegel ist deutlich sichtbar, der zweite wird zu einer langen vertikalen Linie gezogen (aufgrund der gleichzeitigen Öffnung mit dem ersten Ziegel). Der weitere Aufbau folgt den gleichen Prinzipien.
2. Prinzip der Zeichnung des Renko-Diagramms
Während der Entwicklung dieses Indikators wurden alle Funktionen so unabhängig wie möglich umgesetzt. Eins der Hauptziele war es, das Potenzial des Indikators für die einfachere Durchführung der Marktanalyse zu maximieren.
Die Berechnungen finden nicht innerhalb des aktuellen Timeframes statt, d. h. der Timeframe wird in den Einstellungen ausgewählt und wird unabhängig von dem Timeframe, auf dem der Indikator ausgeführt wird, die festgelegten Daten anzeigen. Dies lässt sich durch Kopieren der Daten des festgelegten Zeitraums in separate Puffer-Arrays bewerkstelligen. Später werden Berechnungen durchgeführt und die Ausgabepuffer des Indikators gefüllt.
Das standardmäßige Renko-Diagramm wird gemäß den Close-Preisen erstellt, allerdings werden die Werte von Open, High und Low genutzt, um die Analyse zu verbessern.
Da Ziegel im Renko-Diagramm die gleiche Größe haben, ist es nützlich, die dynamischsten Punkte des Marktes anhand des am stärksten ausgeprägten Preisverhaltens (in wenigen Ziegeln) zu kennen. Zu diesem Zweck gibt es eine (deaktivierte) Anzeige, die durch einen kleinen vertikalen Schatten eines Ziegels dargestellt wird (wie bei japanischen Kerzen), der zum letzten Ziegelniveau des Balkens des ausgewählten Timeframes steigt oder sinkt.
Die Möglichkeit, ZigZag im Hauptdiagramm zu erstellen, erweitert die grafische Analyse.
Abb. 3 zeigt den Indikator mit seiner vollen Funktionalität:
Abbildung 3. Indikator für das EURUSD-Diagramm (täglich, Schrittgröße 25 Punkte)
3. Code und Algorithmus des Indikators
Der Code des Indikators ist mit 900 Zeilen ziemlich groß. Wie bereits erwähnt, können maximal getrennte Funktionen das Verständnis des Algorithmus erschweren. Einige Funktionen aus dem vorherigen Beitrag werden als Basis verwendet. Falls Sie bestimmte Aspekte nicht verstehen, können Sie sich auf den Beitrag Indikator für die Erstellung eines Kagi-Diagramms beziehen oder mir eine E-Mail schreiben.
Jede Funktion des Codes wird im Beitrag erklärt. Funktionen werden an der entsprechenden Stelle beschrieben.
3,1. Indikator Eingabe-Parameter
Das Renko-Diagramm ist eine Ansammlung aufwärts und abwärts gerichteter verschiedenfarbiger Ziegel. Diese Art der Konstruktion erfordert nur fünf Puffer, kombiniert in der grafischen Konstruktion "farbige Kerzen". Die verbleibenden vier Puffer sammeln Daten, die für die Berechnung des Indikators benötigt werden.
Betrachten wir die in Gruppen eingeteilten Eingabeparameter (25).
- step – Größe oder Schrittweite eines Ziegels;
- type_step – Art des Schritts, in Punkten oder als prozentualer Anteil (letzterer wird abhängig vom aktuellen Preis berechnet);
- magic_numb – magische Nummer, die zum Unterscheiden grafischer Objekte benötigt wird und genutzt wird, um sie aus dem Diagramm zu entfernen;
- levels_number – Ebenen (0: keine Ebenen) zum Unterteilen von Ziegeln im Indikatorfenster;
- levels_color – Farbe der Ebenen im Indikatorfenster;
- time_frame – Festlegung eines Zeitraums für die Konstruktion des Diagramms (zu analysierender Zeitraum);
- time_redraw – Aktualisierungszeit des Diagramms;
- first_date_start – Anfangsdatum der Diagrammzeichnung;
- type_price – Preisarten für die Konstruktion: Close – Standardmethode auf Basis des Schließungspreises; Open – Öffnungspreis; High – Höchstpreis; Low – Mindestpreis;
- shadow_print – ist diese Option true, stellen Schatten den Höchst- oder Mindestpreis zum gleichzeitigen Öffnen mehrerer Ziegel dar;
- filter_number – Wert der Ziegel für eine Umkehrung des Diagramms (eine Zusatzoption, die für die Menge der Ziegel verantwortlich ist, die für eine Umkehrung des Diagramms erforderlich sind);
- zig_zag – Zeichnung von ZigZags im Hauptdiagramm (eine zusätzliche Darstellung im Hauptdiagramm, die die Analyse erleichtert oder für eine Aktualisierung des Diagramms genutzt wird);
- zig_zag_shadow – Zeichnung von ZigZags gemäß den Höchst- und Mindestpreisen (nutzt die nächstgelegenen Höchst- und Mindestpreise für die Konstruktion von ZigZags an Randpunkten);
- zig_zag_width – Linienstärke des ZigZag;
- zig_zag_color_up – Farbe der aufwärts gerichteten Linien des ZigZag;
- zig_zag_color_down – Farbe der abwärts gerichteten Linien des ZigZag;
- square_draw – Zeichnung von Ziegeln im Hauptdiagramm (in diesem Modus sehen Sie die Preisbewegungen, die die Ziegel öffnen);
- square_color_up – Farbe der Ziegel im Hauptdiagramm nach oben;
- square_color_down – Farbe der Ziegel im Hauptdiagramm nach unten;
- square_fill – Färbung der Ziegel im Hauptdiagramm;
- square_width – Breite der Ziegellinien im Hauptdiagramm;
- frame_draw – Zeichnung von Ziegelrändern (stellt Ränder von Ziegeln dar, selten verwendete Zusatzfunktion);
- frame_width – Breite der Ziegellinien;
- frame_color_up – Farbe der Ränder aufwärts gerichteter Ziegel;
- frame_color_down – Farbe der Ränder abwärts gerichteter Ziegel.
Anschließend deklariert der Code Puffer: Fünf Hauptpuffer werden für den grafischen Aufbau verwendet, während vier zum Speichern des Designs und der Berechnung von Daten genutzt werden. Price[] – Puffer zum Speichern der kopierten Preise für den Aufbau, Date[] – Puffer zum Speichern kopierter Daten für das Zeichnen im Hauptdiagramm, Price_high[] und Price_low[] – Puffer zum Speichern der Höchst- und Mindestwerte für die Zeichnung von ZigZags im Hauptdiagramm.
Anschließend werden Arrays von Berechnungspuffern und Hilfsvariablen für Funktionen deklariert: func_draw_renko, func_draw_zig_zag, func_draw_renko_main_chart. Sie werden später erläutert.
//+------------------------------------------------------------------+ //| ABCR.mq5 | //| Azotskiy Aktiniy ICQ:695710750 | //| https://www.mql5.com/ru/users/Aktiniy | //+------------------------------------------------------------------+ //--- Auto Build Chart Renko #property copyright "Azotskiy Aktiniy ICQ:695710750" #property link "https://www.mql5.com/ru/users/Aktiniy" #property version "1.00" #property description "Auto Build Chart Renko" #property description " " #property description "This indicator used to draw Renko chart in the indicator window, and in the main chart window" #property indicator_separate_window #property indicator_buffers 9 #property indicator_plots 1 //--- plot RENKO #property indicator_label1 "RENKO" #property indicator_type1 DRAW_COLOR_CANDLES #property indicator_color1 clrRed,clrBlue,C'0,0,0',C'0,0,0',C'0,0,0',C'0,0,0',C'0,0,0',C'0,0,0' #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- construction method enum type_step_renko { point=0, // Point percent=1, // Percent }; //--- type of price enum type_price_renko { close=0, // Close open=1, // Open high=2, // High low=3, // Low }; //--- input parameters input double step=10; // Step input type_step_renko type_step=point; // Type of step input long magic_numb=65758473787389; // Magic number input int levels_number=1000; // Number of levels (0-no levels) input color levels_color=clrLavender; // Color of levels input ENUM_TIMEFRAMES time_frame=PERIOD_CURRENT; // Calculation period input ENUM_TIMEFRAMES time_redraw=PERIOD_M1; // Chart redraw period input datetime first_date_start=D'2013.09.13 00:00:00'; // Start date input type_price_renko type_price=close; // Price for construction input bool shadow_print=true; // Show shadows input int filter_number=0; // Bricks number needed to reversal input bool zig_zag=true; // Whether ZigZag should be drawn on the main chart input bool zig_zag_shadow=true; // Draw ZigZag at highs and lows of the price input int zig_zag_width=2; // ZigZag line width input color zig_zag_color_up=clrBlue; // ZigZag up line color input color zig_zag_color_down=clrRed; // ZigZag down line color input bool square_draw=true; // Whether bricks should be drawn on the main chart input color square_color_up=clrBlue; // Up brick color on the main chart input color square_color_down=clrRed; // Down brick color on the main chart input bool square_fill=true; // Brick filling on the main chart input int square_width=2; // Brick line width on the main chart input bool frame_draw=true; // Whether to draw frames of the bricks input int frame_width=2; // Brick frame line width input color frame_color_up=clrBlue; // Up brick frames color input color frame_color_down=clrRed; // Down brick frames color //--- indicator buffers double RENKO_open[]; double RENKO_high[]; double RENKO_low[]; double RENKO_close[]; double RENKO_color[]; double Price[]; // copy price data to the buffer double Date[]; // copy data to the buffer double Price_high[]; // copy high prices to the buffer double Price_low[]; // copy low prices to the buffer //--- calculation buffer arrays double up_price[]; // up brick price double down_price[]; // down brick price char type_box[]; // brick type (up, down) datetime time_box[]; // brick copy time double shadow_up[]; // up high price double shadow_down[]; // down low price int number_id[]; // Index of Price_high and Price_low arrays //--- calculation global variables int obj=0; //variable for storing number of graphics objects int a=0; // variable to count bricks int bars; // number of bars datetime date_stop; // current data datetime date_start; // start date variable, for calculations bool date_change; // variable for storing details about time changes
3,2. Initialisierungsfunktion des Indikators
Indikatorpuffer werden mit eindimensionalen dynamischen Arrays verbunden. Die Adressierung wird genauso wie bei Zeitreihen in den Puffern INDICATOR_DATA und INDICATOR_COLOR_INDEX festgelegt. Die Adressierung der verbleibenden dynamischen Arrays (Price[], Date[], Price_high[], Price_low[]) bleibt unverändert, da diese nur zum Speichern von Daten verwendet werden.
Werte, die nicht im Diagramm angezeigt werden, werden festgelegt. Anschließend wird der Name dem Indikator zugewiesen, die Genauigkeit der Anzeige festgelegt und die Anzeige der aktuellen numerischen Werte im Indikatorfenster verboten.
Danach wird der Wert der Variable date_start (Datum für den Beginn der Berechnungen) zugewiesen. Der Wert wird der Variable zugewiesen, der Eingabewert wird nicht verwendet, da das Diagramm sich als zu groß für den Indikatorpuffer erweisen kann. Das Anfangsdatum wird korrigiert und der Benutzer gewarnt. Die Funktion der Analyse des Startdatums, "func_calc_date_start", übernimmt die Korrektur der Zeit.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,RENKO_open,INDICATOR_DATA); ArraySetAsSeries(RENKO_open,true); SetIndexBuffer(1,RENKO_high,INDICATOR_DATA); ArraySetAsSeries(RENKO_high,true); SetIndexBuffer(2,RENKO_low,INDICATOR_DATA); ArraySetAsSeries(RENKO_low,true); SetIndexBuffer(3,RENKO_close,INDICATOR_DATA); ArraySetAsSeries(RENKO_close,true); SetIndexBuffer(4,RENKO_color,INDICATOR_COLOR_INDEX); ArraySetAsSeries(RENKO_color,true); //--- SetIndexBuffer(5,Price,INDICATOR_CALCULATIONS); // initialize price buffer SetIndexBuffer(6,Date,INDICATOR_CALCULATIONS); // initialize data buffer SetIndexBuffer(7,Price_high,INDICATOR_CALCULATIONS); // initialize high price SetIndexBuffer(8,Price_low,INDICATOR_CALCULATIONS); // initialize low price //--- set data which will not be drawn PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0); //--- set the indicator appearance IndicatorSetString(INDICATOR_SHORTNAME,"ABCR "+IntegerToString(magic_numb)); // indicator name //--- display accuracy IndicatorSetInteger(INDICATOR_DIGITS,_Digits); //--- prohibit display of the results of the indicator current values PlotIndexSetInteger(0,PLOT_SHOW_DATA,false); //--- assign start date variable value date_start=first_date_start; //--- return(INIT_SUCCEEDED); }
3,3. Funktion der Berechnung des Anfangsdatums der Analyse
Die Funktion ist klein und besteht hauptsächlich aus einer Schleife. Es gibt nur zwei Eingabeparameter – die erste Festlegung des Anfangsdatums und das Enddatum der Berechnung (aktuelles Datum). Das Anfangsdatum wird in der Funktion geändert und als Antwort ausgegeben.
Der Körper der Funktion beginnt bei der Messung des empfangenden Puffer-Arrays (alle Puffer haben die gleiche Größe, die der Menge der Balken des ausgewählten Timeframes entspricht). Anschließend wird die Menge der Balken auf dem ausgewählten Timeframe gemessen.
Die Menge der Balken des ausgewählten Timeframes und die Größe des Puffer-Arrays werden in der Bedingung der Schleife verglichen. Falls Sie mehr Balken haben, sodass nicht alle im Puffer-Array platziert werden können, wird der ausgewählte Timeframe zu zehn Tagen gekürzt. Das bedeutet, dass zehn Tage zum Startdatum der Analyse hinzugefügt werden. Dies setzt sich fort, bis das Puffer-Array nicht mehr alle Daten der Balken aufnehmen kann. Die Funktion gibt das errechnete Datum aus.
//+------------------------------------------------------------------+ //| Func Calculate Date Start | //+------------------------------------------------------------------+ datetime func_calc_date_start(datetime input_data_start,// initially start date set datetime data_stop) // calculation end date (current date) //--- { int Array_Size=ArraySize(Price); int Bars_Size=Bars(_Symbol,time_frame,input_data_start,data_stop); for(;Bars_Size>Array_Size;input_data_start+=864000) // 864000 = 10 days { Bars_Size=Bars(_Symbol,time_frame,input_data_start,data_stop); } return(input_data_start); //--- }
3,4. Funktionen zum Kopieren von Daten
Als Erstes werden die Daten mit den Funktionen zum Kopieren der Daten kopiert (func_copy_price und func_copy_date).
Betrachten wir die Funktion zum Kopieren von Preisen, func_copy_price, die es Ihnen ermöglicht, Open-, Close-, High- und Low-Preise des festgelegten Zeitraums und Timeframes in das Array zu kopieren. Bei erfolgreichem Kopieren gibt die Funktion "true" aus.
Am Anfang des Funktionsaufrufs wird der Wert false initialisiert, anschließend wird eine Variable des Ergebnisses der kopieren Daten initialisiert und ein negativer Wert zugewiesen. Das gemeinsame Array price_interim[] zum Speichern temporärer kopierter Daten und die Variable bars_to_copy werden deklariert, um ein Speichern kopierter Daten zu vermeiden.
Weiterhin setzt die Funktion früher deklarierte Variablen zum Speichern der kopierten Daten zurück, berechnet die Menge der Balken auf dem Timeframe und weist in Übereinstimmung mit dem gewählten Preis (0-Close, 1-Open, 2-High und 3-Low) und dem Operator switch den Wert der vorher kopierten Daten anhand der Preise der Variable bars_copied zu. Anschließend wird die Menge der zu kopierenden Daten berechnet. Falls die Daten vorher kopiert wurden, werden die Informationen über den letzten kopierten Balken gelöscht, um Änderungen im Diagramm zu vermeiden.
Ein Umschalter kopiert die erforderlichen Preisdaten in das Zeit-Array price_interim[]. Anschließend wird das Ergebnis des Kopiervorgangs geprüft und ein Umschalter befüllt die Variablen kopierter Daten.
//+------------------------------------------------------------------+ //| Func Copy Price | //+------------------------------------------------------------------+ bool func_copy_price(double &result_array[], ENUM_TIMEFRAMES period,// Timeframe datetime data_start, datetime data_stop, char price_type) // 0-Close, 1-Open, 2-High, 3-Low { //--- int x=false; // Variable for answering int result_copy=-1; // copied data number //--- static double price_interim[]; // Temporal dynamic array for storing copied data static int bars_to_copy; // number of bars to copy static int bars_copied_0; // number of copied bars from Close start date static int bars_copied_1; // number of copied bars from Open start date static int bars_copied_2; // number of copied bars from High start date static int bars_copied_3; // number of copied bars from Low start date static int bars_copied; // number of copied bars from the common variable start date //--- variables reset due to changes in a start date if(date_change==true) { ZeroMemory(price_interim); ZeroMemory(bars_to_copy); ZeroMemory(bars_copied_0); ZeroMemory(bars_copied_1); ZeroMemory(bars_copied_2); ZeroMemory(bars_copied_3); ZeroMemory(bars_copied); } //--- get an information about the current bars number on the timeframe bars_to_copy=Bars(_Symbol,period,data_start,data_stop); //--- assign a copied function value to a common variable switch(price_type) { case 0: //--- Close bars_copied=bars_copied_0; break; case 1: //--- Open bars_copied=bars_copied_1; break; case 2: //--- High bars_copied=bars_copied_2; break; case 3: //--- Low bars_copied=bars_copied_3; break; } //--- calculate number of bars required to be copied bars_to_copy-=bars_copied; //--- if it is not the first time the data has been copied if(bars_copied!=0) { bars_copied--; bars_to_copy++; } //--- change the size of the recieving array ArrayResize(price_interim,bars_to_copy); //--- copy data to the recieving array switch(price_type) { case 0: //--- Close { result_copy=CopyClose(_Symbol,period,0,bars_to_copy,price_interim); } break; case 1: //--- Open { result_copy=CopyOpen(_Symbol,period,0,bars_to_copy,price_interim); } break; case 2: //--- High { result_copy=CopyHigh(_Symbol,period,0,bars_to_copy,price_interim); } break; case 3: //--- Low { result_copy=CopyLow(_Symbol,period,0,bars_to_copy,price_interim); } break; } //--- check the result of data copying if(result_copy!=-1) // if copying to the intermediate array is successful { ArrayCopy(result_array,price_interim,bars_copied,0,WHOLE_ARRAY); // copy the data from the temporary array to the main one x=true; // assign the positive answer to the function bars_copied+=result_copy; // increase the value of the processed data } //--- return the information about the processed data with one of the copied variables switch(price_type) { case 0: //--- Close bars_copied_0=bars_copied; break; case 1: //--- Open bars_copied_1=bars_copied; break; case 2: //--- High bars_copied_2=bars_copied; break; case 3: //--- Low bars_copied_3=bars_copied; break; } //--- return(x); }
"func_copy_date", die Funktion zum Kopieren des Datums. Der Code der Funktion ähnelt dem obigen Block. Der Unterschied ist der Typ der kopierten Daten.
//+------------------------------------------------------------------+ //| Func Copy Date | //+------------------------------------------------------------------+ bool func_copy_date(double &result_array[], ENUM_TIMEFRAMES period,// timeframe datetime data_start, datetime data_stop) { //--- int x=false; // variable for answer int result_copy=-1; // number of copied data static datetime time_interim[]; // temporaty dynamic array for storing the copied data static int bars_to_copy; // bars number required to be copied static int bars_copied; // copied bars with start date //--- variables reset due to the start date change if(date_change==true) { ZeroMemory(time_interim); ZeroMemory(bars_to_copy); ZeroMemory(bars_copied); } //--- bars_to_copy=Bars(_Symbol,period,data_start,data_stop); // Find out the current number of bars on the time interval bars_to_copy-=bars_copied; // Calculate the number of bars to be copied //--- if(bars_copied!=0) // If it is not the first time the data has been copied { bars_copied--; bars_to_copy++; } //--- ArrayResize(time_interim,bars_to_copy); // Change the size of the receiving array result_copy=CopyTime(_Symbol,period,0,bars_to_copy,time_interim); //--- if(result_copy!=-1) // If copying to the intermediate array is successful { ArrayCopy(result_array,time_interim,bars_copied,0,WHOLE_ARRAY); // Copy the data from the temporary array to the main one x=true; // assign the positive answer to the function bars_copied+=result_copy; // Increase the value of the processed data } //--- return(x); }
3,5. Funktion zur Berechnung von Ziegeln
Wie Sie anhand der Parameter des Indikators sehen, kann die Größe eines Ziegels sowohl in Punkten als auch als prozentualer Anteil des aktuellen Preises ausgedrückt werden. Punkte sind ein fester Wert, doch wie wird der prozentuale Anteil berechnet? Zu diesem Zweck gibt es die Funktion zum Berechnen von Ziegeln, "func_calc_dorstep".
Es gibt drei Eingabeparameter: den aktuellen Preis (zum Berechnen des prozentualen Anteils des Preises, wenn die Ziegelgröße in Prozent angegeben wird), die Berechnungsmethode (Punkte oder Prozent) und die Schrittgröße (Eingabe als ein Wert, der in Prozent oder Punkten ausgedrückt werden kann).
Am Anfang der Funktion wird die Variable für die Antwort des typen double initialisiert und je nach ausgewählter Berechnungsmethode, die durch eine bedingte Wenn-Dann-Anweisung geprüft wird, in Punkten zugewiesen. Anschließend wird die Antwortvariable in int konvertiert, um den Wert ganzzahlig zu halten, auch wenn die Berechnung einen nicht ganzzahligen Wert ergibt.
//+------------------------------------------------------------------+ //| Func Calculate Doorstep | //+------------------------------------------------------------------+ int func_calc_dorstep(double price, // price char type_doorstep,// step type double doorstep) // step { double x=0; // variable for answer if(type_doorstep==0) // If the calculation is to be performed in points { x=doorstep; } if(type_doorstep==1) // If the calculation is to be performed in percentage { x=price/_Point*doorstep/100; } return((int)x); }
3,6. Hauptfunktion – Aufbau des Renko-Diagramms
Die Hauptfunktion des Aufbaus des Renko-Diagramms – "func_draw_renko". Diese Funktion ist für die Befüllung von Grafikpuffern (Indikatorpuffern) und der Arrays von Berechnungspuffern verantwortlich. Berechnungspuffer speichern die Informationen über jeden Ziegel.
Die Eingabeparameter der Funktion sind Daten-Arrays von Preisen und Daten des Aufbaus von Balken. Hier finden Sie die Information über die Art des Schritts und dessen Parameter, den Umkehrfilter und den Parameter der Zeichnung von Schatten.
Die Funktion lässt sich in zwei Abschnitte unterteilen: den Teil für die Berechnung der Menge der Ziegel und den Teil für die Berechnung und Befüllung von Grafikpuffern.
Am Anfang der Funktion werden die Puffer zurückgesetzt, um leere Zellen zu deaktivieren. Danach werden Hilfsvariablen eingegeben: Die Variable "doorstep_now" wird für den Schritt verwendet (bei der Änderung seiner Größe beim Schritt als prozentualer Anteil), "point_go" speichert Informationen über die Distanz zum zuletzt aufgebauten Ziegel, "a" wird bei der Berechnung von Ziegeln verwendet, "up_price_calc" und "down_price_calc" sind die zuletzt analysierten Höchst- und Mindestpreise, "type_box_calc" ist der zuletzt analysierte Ziegeltyp (aufwärts oder abwärts).
Beide Funktionsteile bestehen aus einer Schleife, der zweite Teil vervollständigt den ersten. Analysieren wir den Prozess im Detail.
Die erste Schleife wird über alle kopierten Werte verarbeitet, der Wert "bars" ist für die Menge der kopierten Daten verantwortlich (Berechnung in der Funktion "func_concolidation", die später betrachtet wird). Im weiteren Verlauf der Schleife beginnt die Berechnung der Ziegelgröße. Wenn die Schrittgröße als Prozentsatz angegeben wird, muss sie für jeden Balken separat berechnet werden, da jeder Balken einen anderen Schließungspreis hat.
Die bedingte if-Anweisung prüft die Richtung des Preises, wobei der Preis eine Distanz von mindestens einem Schritt zurücklegen muss. Nach der Bestimmung der Richtung der Preisbewegung wird die Bedingung der vorherigen Bewegung (des letzten Ziegels) geprüft. Das liegt daran, dass die Parameter des Indikators einen Filterparameter enthalten (Menge der für eine Umkehrung erforderlichen Ziegel). Nach der Prüfung aller Bedingungen beginnt die Schleife. Sie wird so oft verarbeitet, wie die aktuelle Preisbewegung durch Ziegel dargestellt wird.
Die anzuzeigenden Balken werden berechnet, die Größe der Berechnungspuffer wird geändert und sie werden zurückgesetzt. Daraufhin werden den ersten paar (beim ersten Vergleich verwendeten) Berechnungs-Arrays die ersten Werte zugewiesen.
Wenn die maximal zulässige Menge der angezeigten Balken weniger ist als die mögliche Menge von Ziegeln, werden die überschüssigen Ziegel berechnet und eine Benachrichtigung über den zu geringen Wert angezeigt. Das geschieht, um eine falsche Darstellung des Diagramms zu vermeiden.
Die Variable der Berechnung der Menge von Ziegeln wird zurückgesetzt und die Hauptschleife beginnt. Im Gegensatz zur vorherigen Schleife ist die Hauptschleife ebenso für das Befüllen von Arrays von Berechnungspuffern und das Zurücksetzen des Ziegelzählers verantwortlich.
Am Ende der Funktion werden die Grafikpuffer befüllt.
//+------------------------------------------------------------------+ //| Func Draw Renko | //+------------------------------------------------------------------+ void func_draw_renko(double &price[], // prices array double &date[], // date array int number_filter, // bricks number for reversal bool draw_shadow, // draw shadow char type_doorstep,// step type double doorstep) // step { //--- arrays reset //--- drawing buffer arrays ZeroMemory(RENKO_close); ZeroMemory(RENKO_color); ZeroMemory(RENKO_high); ZeroMemory(RENKO_low); ZeroMemory(RENKO_open); //--- additional variables int doorstep_now; // current step int point_go; // passed points //--- additional variables for bricks number calculating a=0; double up_price_calc=price[0]; double down_price_calc=price[0]; char type_box_calc=0; for(int z=0; z<bars; z++) //---> bricks calculating loop { //--- calculate step according to the current price doorstep_now=func_calc_dorstep(price[z],type_doorstep,doorstep); //--- if price rises if((price[z]-up_price_calc)/_Point>=doorstep_now) { //--- calculate points passed point_go=int((price[z]-up_price_calc)/_Point); //--- prices was rising or unknown price behavour if(type_box_calc==1 || type_box_calc==0) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { //--- add the next brick a++; //--- add value of the next brick low price down_price_calc=up_price_calc; //--- add value of the next brick up price up_price_calc=down_price_calc+(doorstep_now*_Point); //--- set the brick type (up) type_box_calc=1; } } //--- price went down if(type_box_calc==-1) { if((point_go/doorstep_now)>=number_filter) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { //--- add the next brick a++; //--- set the next brick down price down_price_calc=up_price_calc; //--- set the next brick up price up_price_calc=down_price_calc+(doorstep_now*_Point); //--- set the brick type (up) type_box_calc=1; } } } } //--- if the price moves downwards if((down_price_calc-price[z])/_Point>=doorstep_now) { //--- calculate the points passed point_go=int((down_price_calc-price[z])/_Point); //--- if the price went downwards or the direction is unknown if(type_box_calc==-1 || type_box_calc==0) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { //--- add the next brick a++; //--- set the next brick low price value up_price_calc=down_price_calc; //--- set the next brick up price value down_price_calc=up_price_calc-(doorstep_now*_Point); //--- set the britck type (up) type_box_calc=-1; } } //--- the price moved upwards if(type_box_calc==1) { if((point_go/doorstep_now)>=number_filter) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { //--- add the next brick a++; //--- set the next brick down price value up_price_calc=down_price_calc; //--- set the next brick up price value down_price_calc=up_price_calc-(doorstep_now*_Point); //--- set the brick type (up) type_box_calc=-1; } } } } } //---< bricks calculate loop //--- calculate the number of display bars int b=Bars(_Symbol,PERIOD_CURRENT); //--- resize arrays ArrayResize(up_price,b); ArrayResize(down_price,b); ArrayResize(type_box,b); ArrayResize(time_box,b); ArrayResize(shadow_up,b); ArrayResize(shadow_down,b); ArrayResize(number_id,b); //--- resize calculation buffers array ZeroMemory(up_price); ZeroMemory(down_price); ZeroMemory(type_box); ZeroMemory(time_box); ZeroMemory(shadow_up); ZeroMemory(shadow_down); ZeroMemory(number_id); //--- fill arrays with the initial values up_price[0]=price[0]; down_price[0]=price[0]; type_box[0]=0; //--- calculate odd bricks number int l=a-b; int turn_cycle=l/(b-1); int turn_rest=(int)MathMod(l,(b-1))+2; int turn_var=0; //--- message of partially displayed bricks if(a>b)Alert("More bricks than can be placed on the chart, the step is small"); a=0; //--- reset bricks claculating variable for(int z=0; z<bars; z++) //---> Main loop { //--- calculate the step according to the price doorstep_now=func_calc_dorstep(price[z],type_doorstep,doorstep); //---if the price moves upwards if((price[z]-up_price[a])/_Point>=doorstep_now) { //--- calculate the points passed point_go=int((price[z]-up_price[a])/_Point); //--- price moved upwards or its behavour is unknown if(type_box[a]==1 || type_box[a]==0) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { a++; //--- add the next brick if((a==b && turn_var<turn_cycle) || (turn_var==turn_cycle && turn_rest==a)) { up_price[0]=up_price[a-1]; a=1; // bricks calculator reset turn_var++; // calculator of loops reset } //--- the next brick low price value down_price[a]=up_price[a-1]; //--- set the brick up price up_price[a]=down_price[a]+(doorstep_now*_Point); //--- set the up shadow value if(shadow_print==true) shadow_up[a]=price[z]; //to the upper price level else shadow_up[a]=up_price[a]; // to the up price level //--- set the low price value(to the brick price level) shadow_down[a]=down_price[a]; //--- value of the brick closing time time_box[a]=(datetime)Date[z]; //--- set the brick type (up) type_box[a]=1; //--- set the index number_id[a]=z; } } //--- the price moved downwards if(type_box[a]==-1) { if((point_go/doorstep_now)>=number_filter) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { a++; //--- add the next brick if((a==b && turn_var<turn_cycle) || (turn_var==turn_cycle && turn_rest==a)) { up_price[0]=up_price[a-1]; a=1; // bricks counter reset turn_var++; // loops reset cycle } //--- set the next brick low price value down_price[a]=up_price[a-1]; //--- set the next brick up price up_price[a]=down_price[a]+(doorstep_now*_Point); //--- set the up shadow value if(shadow_print==true) shadow_up[a]=price[z]; // at the up price level else shadow_up[a]=up_price[a]; // the brick up price level //--- set of the down price value (the brick price level) shadow_down[a]=down_price[a]; //--- set the close time time_box[a]=(datetime)Date[z]; //--- set the up brick type_box[a]=1; //--- set index number_id[a]=z; } } } } //--- if price moves upwards if((down_price[a]-price[z])/_Point>=doorstep_now) { //--- calculate the points passed point_go=int((down_price[a]-price[z])/_Point); //--- price moved downwards or the direction is unknown if(type_box[a]==-1 || type_box[a]==0) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { a++; //--- add the next brick if((a==b && turn_var<turn_cycle) || (turn_var==turn_cycle && turn_rest==a)) { down_price[0]=down_price[a-1]; a=1; // set the bricks counter to zero turn_var++; // reset loop counter } //--- set the next brick down price up_price[a]=down_price[a-1]; //--- set the next brick up price down_price[a]=up_price[a]-(doorstep_now*_Point); //--- set the down shadow value if(shadow_print==true) shadow_down[a]=price[z]; //--- the last lowest price level else shadow_down[a]=down_price[a]; //--- low price level //--- set the up price value shadow_up[a]=up_price[a]; //--- set the brick close time time_box[a]=set the down shadow value]; //--- set the brick type (down) type_box[a]=-1; //--- set index number_id[a]=z; } } //--- price moved upwards if(type_box[a]==1) { if((point_go/doorstep_now)>=number_filter) { for(int y=point_go; y>=doorstep_now; y-=doorstep_now) { a++; //--- add the next brick if((a==b && turn_var<turn_cycle) || (turn_var==turn_cycle && turn_rest==a)) { down_price[0]=down_price[a-1]; a=1; // reset bricks counter turn_var++; // reset loop counter } up_price[a]=down_price[a-1]; //--- set the next brick down price down_price[a]=up_price[a]-(doorstep_now*_Point); //--- set the up price value //--- set the down shadow value if(shadow_print==true) shadow_down[a]=price[z]; // at the lowest price level else shadow_down[a]=down_price[a]; // at the down price level //--- set the up price level shadow_up[a]=up_price[a]; //--- set the brick close time time_box[a]=(datetime)Date[z]; //--- set the brick type (down) type_box[a]=-1; //--- index set number_id[a]=z; } } } } } //---< Main loop //--- fill the draw buffer int y=a; for(int z=0; z<a; z++) { if(type_box[y]==1)RENKO_color[z]=0; else RENKO_color[z]=1; RENKO_open[z]=down_price[y]; RENKO_close[z]=up_price[y]; RENKO_high[z]=shadow_up[y]; RENKO_low[z]=shadow_down[y]; y--; } }
3,7. Funktionen zum Erstellen der grafischen Objekte "Trendlinie" und "Rechteck"
Die Funktion "func_create_trend_line" zum Erstellen des grafischen Objekts "Trendlinie" und die Funktion "func_create_square_or_rectangle" zum Erstellen des grafischen Objekts "Rechteck" basieren auf den Daten aus dem Leitfaden zu OBJ_RECTANGLE und OBJ_TREND. Sie werden zum Erstellen von grafischen Objekten im Renko-Diagramm und zum Aufbau von ZigZag im Hauptdiagramm genutzt.
//+------------------------------------------------------------------+ //| Func Create Trend Line | //+------------------------------------------------------------------+ void func_create_trend_line(string name, double price1, double price2, datetime time1, datetime time2, int width, color color_line) { ObjectCreate(0,name,OBJ_TREND,0,time1,price1,time2,price2); //--- set the line color ObjectSetInteger(0,name,OBJPROP_COLOR,color_line); //--- set the line display style ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID); //--- set the width of the line ObjectSetInteger(0,name,OBJPROP_WIDTH,width); //--- display in the foreground (false) or in the (true) background ObjectSetInteger(0,name,OBJPROP_BACK,false); //--- enable (true) or disable (false) the mode of the left line display ObjectSetInteger(0,name,OBJPROP_RAY_LEFT,false); //--- enable (true) or disable (false) the right line display ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,false); }
//+------------------------------------------------------------------+ //| Func Create Square or Rectangle | //+------------------------------------------------------------------+ void func_create_square_or_rectangle(string name, double price1, double price2, datetime time1, datetime time2, int width, color color_square, bool fill) { //--- create rectangle according to the setpoints ObjectCreate(0,name,OBJ_RECTANGLE,0,time1,price1,time2,price2); //--- set the rectangle color ObjectSetInteger(0,name,OBJPROP_COLOR,color_square); //--- set style of rectangle color ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID); //--- set lines width ObjectSetInteger(0,name,OBJPROP_WIDTH,width); //--- activate (true) or disactivate (false) mode of rectangle colouring ObjectSetInteger(0,name,OBJPROP_FILL,fill); //--- display in the foreground (false) or in the background (true) ObjectSetInteger(0,name,OBJPROP_BACK,false); }
3,8. Aufbau des Renko-Diagramms im Hauptdiagramm
Aufgrund der Verwendung gemeinsamer Arrays für Berechnungspuffer ist die Funktion "func_draw_renko_main_chart" für die Zeichnung des Renko-Diagramms ziemlich kompakt.
Zu den Eingabeparametern gehören: aufwärts und abwärts gerichtete Ziegel mit Rahmen, zwei Arten der Rahmenbreite (die erste wird für den Ziegel benutzt, die zweite für dessen Rahmen), drei Anzeigeoptionen (von Ziegeln sowie deren Farben und Rahmen).
Als Erstes werden die Variablen mit Namen von Objekten deklariert, dann wird die Schleife mit dem erzeugten Namen jedes Objekts geöffnet und abhängig vom Typen des vorherigen Ziegels werden die Funktionen der grafischen Objekte "Trendlinie" und "Rechteck" ausgeführt. Die Parameter werden aus den Arrays der Berechnungspuffer bezogen.
//+------------------------------------------------------------------+ //| Func Draw Renko Main Chart | //+------------------------------------------------------------------+ void func_draw_renko_main_chart(color color_square_up, color color_square_down, color color_frame_up, color color_frame_down, int width_square, int width_frame, bool square, bool fill, bool frame) { string name_square; string name_frame; for(int z=2; z<=a; z++) { name_square=IntegerToString(magic_numb)+"_Square_"+IntegerToString(z); name_frame=IntegerToString(magic_numb)+"_Frame_"+IntegerToString(z); if(type_box[z]==1) { if(square==true)func_create_square_or_rectangle(name_square,up_price[z],down_price[z],time_box[z-1],time_box[z],width_square,color_square_up,fill); if(frame==true)func_create_square_or_rectangle(name_frame,up_price[z],down_price[z],time_box[z-1],time_box[z],width_frame,color_frame_up,false); } if(type_box[z]==-1) { if(square==true)func_create_square_or_rectangle(name_square,up_price[z],down_price[z],time_box[z-1],time_box[z],width_square,color_square_down,fill); if(frame==true)func_create_square_or_rectangle(name_frame,up_price[z],down_price[z],time_box[z-1],time_box[z],width_frame,color_frame_down,false); } } }
3,9. Aufbau des ZigZag-Diagramms im Hauptdiagramm
Die nächste Ergänzung des Indikators ist die Funktion "func_draw_zig_zag" für die Erstellung des ZigZag-Diagramms.
Eingabeparameter: Art der Zeichnung (nach Höchst- oder Mindestpreisen oder nach Diagrammpunkten), Linienbreite, Farbe der aufwärts oder abwärts gerichteten Linien.
Die Änderung des Parameters "zig_zag_shadow" ist in Abbildung 4 sichtbar. Beim Wert "true" zeichnet der Indikator die ZigZag-Linien nach den Punkten der Schatten (Mindest- und Höchstpreise), bei "false" werden die ZigZag-Linien nach den Höchst- und Mindestpunkten des Renko-Diagramms gezeichnet.
Abb. 4. Wirkung des Parameters "zig_zag_shadow" auf EURUSD, H1, 10 Punkte.
Für den Aufbau des Objekts "Trendlinie" werden zwei Punkte (Beginn und Ende) benötigt. Geben Sie zwei Variablen für den Preis-Parameter und zwei für den Datum-Parameter ein. Bedingte if-Anweisungen legen den ersten Punkt abhängig vom Typen des ursprünglichen Balkens fest.
Die Schleife, die alle Objekte aufbaut, wird gestartet. Wie Sie sehen können, beginnt die Schleife bei der Analyse des zweiten Ziegels, da der erste Punkt bereits festgelegt ist. Anschließend prüft die bedingte if-Anweisung die Art des Ziegels (das Preisverhalten). Die Variable des Objektnamens wird befüllt und die Schleife wird abhängig von der Bewegungsänderung aufgeteilt. Diese Aufteilung wird abhängig von der Zeichnungsmethode ebenfalls in zwei Varianten unterteilt.
Bei der Anzeige auf den Höchst- und Mindestpreisen suchen die Daten-Arrays Price_high[] und Price_low[] nach den nächstliegenden Mindest- und Höchstpunkten. Die Suche wird durch die benachbarten Balken eingegrenzt.
Bei einem Aufbau nach Diagrammpunkten werden die Daten aus den Arrays der Puffer zugewiesen.
Die Funktion zum Aufbau der Trendlinie wird aufgerufen. Die Funktion beendet die Analyse und Zeichnung des ZigZag.
//+------------------------------------------------------------------+ //| Func Draw Zig Zag | //+------------------------------------------------------------------+ void func_draw_zig_zag(bool price_shadow, int line_width, color line_color_up, color line_color_down) { double price_1=0; double price_2=0; datetime date_1=0; datetime date_2=0; if(type_box[1]==1)price_1=down_price[1]; if(type_box[1]==-1)price_1=up_price[1]; date_1=time_box[1]; int id=0; // Low & High array storing variable int n=0; // variable for name forming string name_line; //--- variable responsible for the "trend line" name for(int z=2; z<=a; z++) { if(type_box[z]!=type_box[z-1]) { n++; name_line=IntegerToString(magic_numb)+"_Line_"+IntegerToString(n); if(type_box[z]==1) { if(price_shadow==true) { id=number_id[z-1]; if((id-1)>0 && Price_low[id-1]<Price_low[id])id--; if(Price_low[id+1]<Price_low[id])id++; price_2=Price_low[id]; date_2=(datetime)Date[id]; } else { price_2=down_price[z-1]; date_2=time_box[z-1]; } func_create_trend_line(name_line,price_1,price_2,date_1,date_2,line_width,line_color_down); price_1=price_2; date_1=date_2; } if(type_box[z]==-1) { if(price_shadow==true) { id=number_id[z-1]; if((id-1)>0 && Price_high[id-1]>Price_high[id])id--; if(Price_high[id+1]>Price_high[id])id++; price_2=Price_high[id]; date_2=(datetime)Date[id]; } else { price_2=up_price[z-1]; date_2=time_box[z-1]; } func_create_trend_line(name_line,price_1,price_2,date_1,date_2,line_width,line_color_up); price_1=price_2; date_1=date_2; } } } }
3,10. Funktion zum Löschen von grafischen Objekten
Zum Bestimmen der Objekte des Indikators wird die magische Nummer verwendet. Dies vereinfacht die Ausführung mehrerer Indikatoren auf einem Diagramm und den Prozess der Löschung von Objekten.
Die nächste Funktion ist die Funktion "func_delete_objects" zum Löschen von Objekten. Die zwei Eingabeparameter sind der Name (Festlegung abhängig von den Objekten – Trendlinie oder Rechteck) und die Menge der Objekte. Die Funktion wählt Objekte aus und löscht Objekte mit bereits zugewiesenem Namen.
//+------------------------------------------------------------------+ //| Func Delete Objects | //+------------------------------------------------------------------+ void func_delete_objects(string name, int number) { string name_del; for(int x=0; x<=number; x++) { name_del=name+IntegerToString(x); ObjectDelete(0,name_del); } }
Zur Vereinfachung wurde eine Funktion erstellt, die alle Funktionen zum Löschen aller Indikatorobjekte vereint.
//+------------------------------------------------------------------+ //| Func All Delete | //+------------------------------------------------------------------+ void func_all_delete() { //--- the graphical objects calculating obj=ObjectsTotal(0,-1,-1); //--- all indicator graphical objects deleting func_delete_objects(IntegerToString(magic_numb)+"_Line_",obj); func_delete_objects(IntegerToString(magic_numb)+"_Square_",obj); func_delete_objects(IntegerToString(magic_numb)+"_Frame_",obj); //--- the chart redrawing ChartRedraw(0); }
3,11. Funktion zum Erstellen von Ebenen
Die Funktion "func_create_levels" zum Erstellen von Ebenen erleichtert die Darstellung des Diagramms im Indikatorfenster. Sie hat nur zwei Eingabeparameter: die Anzahl der erstellten Ebenen und deren Farbe.
Im Körper der Funktion wird die Funktion IndicatorSetInteger verwendet, um die Menge der anzuzeigenden Ebenen festzulegen. Anschließend werden für jede Ebene der Preis und die Farbe bestimmt.
//+------------------------------------------------------------------+ //| Func Create Levels | //+------------------------------------------------------------------+ void func_create_levels(int level_number, color level_color) { //--- set the number of levels in the indicator window IndicatorSetInteger(INDICATOR_LEVELS,level_number); which brick is taken to draw levels int k=0; if(a>level_number)k=a-level_number; //--- set levels prices for(int z=0;(z<=level_number && k<=a); z++,k++) { IndicatorSetDouble(INDICATOR_LEVELVALUE,z,up_price[k]); IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,level_color); } }
3,12. Konsolidierungsfunktion
Die Funktion "func_consolidation" wurde zum Konsolidieren aller Funktionen erstellt.
Diese Funktion ruft alle auszuführenden Funktionen auf.
//+------------------------------------------------------------------+ //| Func Consolidation | //+------------------------------------------------------------------+ void func_concolidation() { //--- deleting all the graphical objects of the indicator func_all_delete(); //--- the current date date_stop=TimeCurrent(); //--- the initial date changing due to the restricted buffer size if((bars=Bars(_Symbol,time_frame,date_start,date_stop))>ArraySize(Price)) { date_start=func_calc_date_start(date_start,date_stop); Alert("The initial date was changed due to the lack of the chart size"); date_change=true; //--- calculation of bars on the taken timeframe bars=Bars(_Symbol,time_frame,date_start,date_stop); } //--- bool result_copy_price=func_copy_price(Price,time_frame,date_start,date_stop,type_price); bool result_copy_date=func_copy_date(Date,time_frame,date_start,date_stop); //--- change the date parameter if(result_copy_price=true && result_copy_date==true)date_change=false; //--- if(zig_zag_shadow==true) { func_copy_price(Price_high,time_frame,date_start,date_stop,2); func_copy_price(Price_low,time_frame,date_start,date_stop,3); } //--- func_draw_renko(Price,Date,filter_number,shadow_print,type_step,step); if(zig_zag==true)func_draw_zig_zag(zig_zag_shadow,zig_zag_width,zig_zag_color_up,zig_zag_color_down); //--- func_draw_renko_main_chart(square_color_up,square_color_down,frame_color_up,frame_color_down,square_width,frame_width,square_draw,square_fill,frame_draw); func_create_levels(levels_number,levels_color); //--- redraw the chart ChartRedraw(0); }
3,13. Funktionen OnCalculate() und OnChartEvent()
Bevor wir mit der Funktion OnCalculate() fortfahren, sehen wir uns die Funktion "func_new_bar" an, die den neuen Balken analysiert.
Dabei handelt es sich um die vereinfachte, in IsNewBar beschriebene Funktion.
//+------------------------------------------------------------------+ //| Func New Bar | //+------------------------------------------------------------------+ bool func_new_bar(ENUM_TIMEFRAMES period_time) { //--- static datetime old_times; // array for storing old values bool res=false; // analysis result variable datetime new_time[1]; // new bar time //--- int copied=CopyTime(_Symbol,period_time,0,1,new_time); // copy the time of the new bar into the new_time box //--- if(copied>0) // все ок. data have been copied { if(old_times!=new_time[0]) // if the bar's old time is not equal to new one { if(old_times!=0) res=true; // if it is not the first launch, true = new bar old_times=new_time[0]; // store the bar's time } } //--- return(res); }
Die Funktion OnCalculate() startet die Konsolidierung aller Funktionen, wenn während der Aktualisierung des Diagramms ein neuer Balken entsteht.
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- if(func_new_bar(time_redraw)==true) { func_concolidation(); } //--- return value of prev_calculated for next call return(rates_total); }
Die Funktion OnChartEvent() löscht alle grafischen Objekte durch Drücken der Taste "C". Mit der Taste "R" wird die Neuzeichnung des Diagramms gestartet (Konsolidierungsfunktion).
//+------------------------------------------------------------------+ //| OnChartEvent | //+------------------------------------------------------------------+ void OnChartEvent(const int id, // event ID const long& lparam, // long type event parameter const double& dparam, // double type event parameter const string& sparam) // string type event parameter { //--- Keyboard button pressing event if(id==CHARTEVENT_KEYDOWN) { if(lparam==82) //--- "R" key has been pressed { //--- call of the consolidation function func_concolidation(); } if(lparam==67) //--- "C" key has been pressed { //--- deletion of all objects of the indicator func_all_delete(); } } }
3,14. Funktion OnDeinit()
Zu guter Letzt folgt die Funktion OnDeinit(). Diese Funktion startet die Funktion zum Löschen aller grafischen Objekte des Indikators.
//+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- delete all graphical objects of the indicator func_all_delete(); }
4. Praktische Anwendung des Renko-Diagramms
Das Renko-Diagramm wird in Übereinstimmung mit der Strategie der Preisbewegungen aufgebaut.
Beginnen wir mit der populärsten Strategie: Verkaufen, wenn der aufwärts gerichtete Ziegel beginnt, sich abwärts zu bewegen, und kaufen, wenn das Gegenteil eintritt.
Dies wird in Abb. 5 gezeigt:
Abb. 5. Standardmäßiges Renko-Diagramm (EURUSD, H4, 20 Punkte)
Abb. 5 zeigt sechs Punkte des Markteintritts (A,B,C,D,E,F).
Bei Punkt "A" wird aus dem aufwärts gerichteten Ziegel ein abwärts gerichteter.
Der umkehrende Ziegel in B,C,D wird durch eine Bewegung erstellt. Allerdings wurden bei Punkt "E" zwei Ziegel durch eine Bewegung erstellt. Dies ist anhand der abwärts gerichteten Schatten erkennbar, die auf der gleichen Ebene erstellt wurden.
In diesem Fall liegt der mögliche Eintrittspunkt zwischen den Punkten "E" und "F". Dabei handelt es sich nicht um einen erfolgreichen Eintritt, da sich der Preis in entgegengesetzter Richtung bewegt. Bei Punkt "F" liegt eine ähnliche Situation vor, in der eine Bewegung ebenfalls zwei Ziegel erstellt. Die aufwärts gerichteten Schatten befinden sich auf der gleichen Ebene. Trotz der starken Bewegung ändert der Preis nicht seine Richtung.
Daraus lässt sich schlussfolgern, das der günstigste Moment für den Markteintritt dann vorliegt, wenn ein umkehrender Ziegel (achten Sie auf die Schatten) durch eine Bewegung erstellt wird. Wenn zwei Ziegel gleichzeitig erstellt werden, ist der Eintritt möglicherweise unsicher.
Der Aufbau von ZigZag in diesem Diagramm kann für die grafische Analyse genutzt werden. Abb. 6 zeigt ein paar Beispiele: die Unterstützungs- und Widerstandslinien sowie das Modell "Kopf und Schultern".
Abb. 6. Grafische Analyse (GBPUSD, H4, 20 Punkte)
Die grafische Analyse "Abstandsgleicher Kanal" wird in Abb. 7 gezeigt.
Der Indikator ist für die Analyse des Timeframes vorgesehen und der Aufbau wird auf dem vierstündigen Timeframe angezeigt.
Solche Einstellungen ermöglichen es dem Kunden, Signale auf unterschiedlichen Timeframes gleichzeitig zu verfolgen, was bedeutet, dass ein Indikator auf einem Timeframe und der andere auf dem zweiten verwendet werden kann.
Abb. 7. Analyse des "Abstandsgleichen Kanals" USDCHF, H4, Einstellungen auf H1, 20 Punkte.
Abb. 8 zeigt ein weiteres Beispiel für unterschiedliche Timeframes in einem Diagramm.
Das Zeitdiagramm zeigt die möglichen nächstliegenden Umkehrungen. Das vierstündige Diagramm löscht nutzlose Signale, das tägliche Diagramm bestätigt die langfristigen Tendenzen der Bewegung.
Abb. 8. Renko-Indikator auf GBPUSD, H1, H4 und D1
Ein weiteres Beispiel des Indikators sehen Sie in Abb. 9. Die Regel ist: Errichten Sie die aufsteigende Linie zwischen den nächstgelegenen roten Ziegeln mit mindestens einem blauen Ziegel zwischen ihnen und verkaufen Sie, nachdem ein Ziegel unter der Linie entsteht.
Und umgekehrt: Errichten Sie die absteigende Linie zwischen den nächstgelegenen blauen Ziegeln mit mindestens einem roten Ziegel zwischen ihnen und verkaufen Sie, nachdem ein Ziegel über der Linie entsteht.
Die aufgezählten Farben entsprechen Abb. 9. Abb. 9. Blaue und rote Pfeile kennzeichnen die Orte der Zeichnung der Linie und große Pfeile kennzeichnen Signale zum Verkaufen und Kaufen.
Abb. 9. Beispiel des Indikators für GBPUSD, H4, 25 Punkte
Fazit
Das Renko-Diagramm ist sowohl für Einsteiger als auch für professionelle Händler von Interesse. Nach vielen Jahren wird es immer noch auf den Märkten genutzt.
In diesem Beitrag wollte ich Ihre Aufmerksamkeit auf dieses Diagramm richten und die Analyse von Renko-Diagrammen verbessern. Ich habe versucht, die Methode des Aufbaus von Renko-Diagrammen im Detail zu erläutern.
Über neue Ideen und Verbesserungsvorschläge für den Indikator würde ich mich sehr freuen und versuchen, sie in Zukunft umzusetzen. Es gibt viele Arten, den Indikator umzusetzen. Vielleicht finden Sie Ihre eigenen Methoden, ihn zu implementieren.
Vielen Dank für Ihr Interesse! Ich wünsche Ihnen erfolgreiches Handeln und das Entdecken und Umsetzen neuer Handelsstrategien.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/792
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.