English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Indicatore per la creazione di grafici Renko

Indicatore per la creazione di grafici Renko

MetaTrader 5Esempi | 12 gennaio 2022, 10:04
253 0
Dmitriy Zabudskiy
Dmitriy Zabudskiy

Introduzione

Articoli Indicatore per grafici a punti e cifre e Indicatore per grafici Kagi descritti Point and Figure e "Kagi" principi per la creazione dei grafici. Studieremo uno dei metodi di programmazione per creare il grafico Renko.

Il nome "Renko" deriva dalla parola giapponese "renga", mattone. Il grafico Renko è costruito da una serie di mattoncini la cui creazione è determinata dalle fluttuazioni del prezzo. Quando un prezzo sale, sul grafico viene posizionato un mattone in su e, con il calo dei prezzi, viene aggiunto un mattone in giù. "Renko" significa "ritmo lento" in giapponese. Il grafico Renko è apparso in Giappone, probabilmente verso il XIX secolo. Gli Stati Uniti e l'Europa ne hanno sentito parlare per la prima volta dopo che Steeve Nison l'ha pubblicato nel 1994, nel suo libro Beyond Candlesticks: Sveliamo i segreti delle nuove tecniche di creazione dei grafici giapponesi.

Il grafico Renko come i grafici sopra menzionati ignora la linea temporale, occupandosi solo del movimento dei prezzi. A differenza del grafico a punti e figure, il Renko posiziona ogni "mattone" in una nuova colonna (in un nuovo piano verticale), come per il resto, hanno un metodo di creazione comune: la dimensione di un "mattone" ("punto", "figura ") è fissa, l'analisi dei prezzi e il rivestimento delle cifre sono fatti in modo simile.

Quindi, il grafico Renko è un insieme di barre verticali ("mattoni"). I mattoncini bianchi (vuoti) vengono utilizzati quando la direzione del trend è rialzista, mentre i mattoncini neri (pieni) vengono utilizzati quando il trend è ribassista. La costruzione è regolata con il comportamento dei prezzi. Il prezzo attuale del periodo in esame viene confrontato con il minimo e il massimo del mattone precedente (bianco o nero). Se il titolo chiude più in alto del suo prezzo di apertura, viene disegnato un mattone vuoto (bianco) con la parte inferiore del corpo che rappresenta il prezzo di apertura e la parte superiore del corpo che rappresenta il prezzo di chiusura. Se il titolo chiude al di sotto del suo prezzo di apertura, viene disegnato un mattone pieno (nero) con la parte superiore del corpo che rappresenta il prezzo di apertura e la parte inferiore del corpo che rappresenta il prezzo di chiusura.

Il primo mattone del grafico viene disegnato a seconda del comportamento del prezzo, il prezzo di apertura della barra viene preso per un massimo e un minimo del mattone precedente.

Un esempio di grafico Renko standard, Fig. 1:

Fig. 1. Un esempio di grafico Renko standard

Fig. 1. Un esempio di grafico Renko standard

1. Esempio di creazione di grafici

Un grafico Renko standard viene disegnato sulla base del prezzo di chiusura. Innanzitutto, seleziona l'intervallo di tempo e la dimensione della scatola.

In questo esempio viene utilizzato l'EURUSD (intervallo di tempo H4), con una dimensione della scatola di 30 punti. Il risultato del grafico Renko dal 03.01.2014 al 31.01.2014 (circa un mese) è mostrato in Fig. 2. A sinistra, c'è il grafico di un dato lasso di tempo (puoi vedere l'estensione orizzontale dei mattoni), a destra, c'è il risultato della creazione di grafici Renko:


Fig.2. Il risultato del grafico Renko in EURUSD (H4, box è 30 punti)  

Fig.2. Il risultato del grafico Renko in EURUSD (H4, box è 30 punti)

Diamo un'occhiata più da vicino al principio della creazione di grafici. Nella Fig. 2 linee orizzontali rosse mostrano la dimensione di ogni mattone in base alle variazioni di prezzo (30 punti), il colore blu indica le date più interessanti.

Come puoi vedere sul grafico alla fine del 03.01.2014 una candela chiude sotto 1,3591 range di prezzi precedentemente definiti (linee rosse orizzontali) a 1,3589 (contrassegnato con il prezzo), il quale crea un mattone al ribasso sul grafico.

Dopodiché il prezzo è flat (non chiude sotto 1,3561 o sopra 1,3651), viene aperto fino alle 20:00 10.01.2014 (chiude la candela creata alle 16:00) e chiude (sopra quota 1,3651) a 1,3663 (contrassegnato col prezzo). Quindi il prezzo diventa nuovamente flat entro le 20:00 del 14.01.2014 (la candela si apre alle 16:00), dove supera la fascia di prezzo, crea un nuovo mattone e chiude a 1,3684.

Quindi assisti a un downtick in cui il prezzo rompe quattro volte gli intervalli in calo sul grafico. Alle 12:00 del 23.01.2014 (la candela aperta alle 08:00 chiude) c'è uno sfondamento al rialzo di due fasce di prezzo che, a sua volta, apre due mattoni chiudendo a 1,3639. Il primo mattone è ben visibile, il secondo si estende in una lunga linea verticale (a causa dell'apertura simultanea con il primo mattone). L'ulteriore costruzione continua sugli stessi principi.


2. Principio di creazione di grafici Renko

Durante lo sviluppo di questo indicatore tutte le funzioni sono state implementate nel modo più indipendente possibile. Uno degli obiettivi principali era massimizzare il potenziale dell'indicatore per condurre più facilmente l'analisi di mercato.

I calcoli non vengono effettuati entro l'intervallo di tempo corrente, ovvero l'intervallo di tempo è selezionato nelle impostazioni e, indipendentemente dall'intervallo di tempo, in cui l'indicatore è stato lanciato, mostrerà i dati di impostazione. Può essere ottenuto copiando i dati del periodo preso in considerazione, in array di buffer separati. Vengono eseguiti calcoli successivi e l'indicatore del buffer di output viene riempito.

Il grafico Renko standard è costruito in base ai prezzi di chiusura. Tuttavia, i valori di apertura, alto e basso vengono utilizzati per migliorare l'analisi.

Poiché i mattoni nel grafico Renko sono di dimensioni simili, è utile conoscere i punti di mercato più dinamici guidati dal forte comportamento dei prezzi (in pochi mattoni). A tal fine è presente un'indicazione (disabilitata) rappresentata con una piccola ombra verticale (come nelle Candele giapponesi) di un mattone, che si alza o si abbassa sull'ultimo livello di mattone della barra dei tempi prescelta.

La possibilità di costruire ZigZag sul grafico principale amplia l'analisi grafica.

La Fig. 3 rappresenta l'indicatore in piena funzionalità:

Figura 3. L'indicatore per il grafico EURUSD (giornaliero, il passaggio è di 25 punti)

Figura 3. L'indicatore per il grafico EURUSD (giornaliero, il passaggio è di 25 punti)


3. Codice e algoritmo dell'indicatore

Il codice dell'indicatore è piuttosto grande in quanto è composto da 900 linee. Come accennato in precedenza, le funzioni separate al massimo possono complicare la comprensione dell'algoritmo. Alcune funzioni dell'articolo precedente verranno utilizzate come base. In caso di incomprensione di alcuni aspetti, puoi fare riferimento all'indicatore di costruzione del grafico Kagi o puoi inviarmi un'e-mail.

Ogni funzione del codice verrà spiegata nell'articolo. Le funzioni saranno descritte mano a mano.


3.1. Parametri di input dell'indicatore

Il grafico Renko è la gamma di mattoni in alto e in basso di colore diverso. Questo tipo di costruzione richiede solo cinque buffer combinati in una costruzione grafica "Candele colorate". I restanti quattro buffer raccolgono i dati necessari per il calcolo dell'indicatore.

Prendi i parametri di input (25), divisi in gruppi.

  • step - una dimensione o un gradino del mattone;
  • type_step - tipo di step, in punti o in percentuale (quest'ultimo viene calcolato in base al prezzo corrente);
  • magic_numb - un numero magico richiesto per distinguere gli oggetti grafici e utilizzato per rimuoverli dal grafico;
  • levels_number - livelli (0- nessun livello) per dividere i mattoni nella finestra dell'indicatore;
  • levels_color - colore dei livelli nella finestra dell'indicatore;
  • time_frame - utilizzato per impostare un periodo per la costruzione del grafico (il periodo analizzato);
  • time_redraw - ora di aggiornamento del grafico;
  • first_date_start - data di inizio della creazione di grafici;
  • type_price - tipi di prezzo per la costruzione: Close - il metodo standard basato sul prezzo di chiusura; Open - prezzo di apertura; High - prezzi massimi e Low - prezzi minimi;
  • shadow_print - se imposti l'opzione true, le ombre rappresentano il prezzo massimo o minimo causato dall'apertura di diversi mattoni;
  • filter_number - valore dei mattoni utilizzato per l'inversione del grafico (un'opzione aggiuntiva responsabile del numero di mattoni necessari per invertire il grafico);
  • zig_zag - utilizzato per tracciare ZigZag sul grafico principale (un disegno extra sul grafico principale che facilita l'analisi o utilizzato per l'aggiornamento del grafico);
  • zig_zag_shadow - usato per disegnare ZigZag in base ai prezzi massimo e minimo (usa i prezzi massimo e minimo più vicini per costruire zigzag sui punti finali);
  • zig_zag_width - Larghezza della linea ZigZag;
  • zig_zag_color_up - Colore della linea a zigzag verso l'alto;
  • zig_zag_color_down - Colore della linea a zigzag verso il basso;
  • square_draw - usato per disegnare i mattoni sul grafico principale (in questa modalità puoi vedere i movimenti dei prezzi che aprono i mattoni);
  • square_color_up - colore mattone sul grafico principale verso l'alto;
  • square_color_down - colore del mattone sul grafico principale verso il basso;
  • square_fill - colorazione del mattone sul grafico principale;
  • square_width - larghezza della linea del mattone sul grafico principale;
  • frame_draw - usato per disegnare cornici di mattoni (rappresenta bordi di mattoni, è un'opzione extra che viene usata raramente);
  • frame_width - larghezza della linea del mattone;
  • frame_color_up - colore dei bordi dei mattoni;
  • frame_color_down - colore dei bordi dei mattoni in basso.

Quindi il codice dichiara i buffer: cinque buffer principali vengono utilizzati per il disegno grafico mentre quattro vengono utilizzati per memorizzare i dati di progettazione e calcolo. Prezzo[] - buffer per memorizzare i prezzi copiati utilizzati per la costruzione, Data[] - buffer per memorizzare i dati copiati utilizzati per disegnare sul grafico principale, Price_high[] e Price_low[] - buffer per memorizzare i valori massimi e minimi applicati nei disegni ZigZag sul grafico principale.

Dopo che i buffer di calcolo vengono dichiarati gli array e le variabili delle funzioni ausiliarie: func_draw_renko, func_draw_zig_zag, func_draw_renko_main_chart. Verranno spiegati in seguito.

//+------------------------------------------------------------------+
//|                                                         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. Indicatore inizializzatore

I buffer degli indicatori sono associati a matrici dinamiche unidimensionali, l'indirizzamento, così come le serie temporali, sono impostati nei buffer INDICATOR_DATA e INDICATOR_COLOR_INDEX. L'indirizzamento degli altri array dinamici (Price[], Date[], Price_high[], Price_low[]) non viene modificato, poiché vengono utilizzati solo per memorizzare i dati.

I valori che non vengono visualizzati nel grafico sono impostati. Quindi il nome viene assegnato all'indicatore, viene impostata la precisione di visualizzazione e la visualizzazione dei valori numerici correnti è vietata nella finestra dell'indicatore.

Successivamente viene assegnato il valore della variabile date_start (data di inizio dei calcoli). Il valore viene assegnato alla variabile, il valore di input non viene utilizzato in quanto il grafico potrebbe essere troppo pesante per il buffer dell'indicatore. La data di inizio viene corretta e viene annunciato il custom. La funzione della data di inizio dell'analisi o "func_calc_date_start" esegue correzioni di tempo.

//+------------------------------------------------------------------+
//| 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. La funzione di calcolo della data di inizio dell'analisi

La funzione è piccola e consiste principalmente in un ciclo. Ci sono solo due parametri di input: la data di inizio impostata inizialmente e la data di fine del calcolo (la data corrente). La data di inizio viene modificata nella funzione e viene visualizzata come risposta.

Il corpo della funzione inizia dalla misurazione dell'array del buffer di ricezione (tutti i buffer hanno la stessa dimensione che è uguale al numero delle barre dell'intervallo di tempo selezionato). Quindi viene misurato un numero di barre sull'intervallo di tempo selezionato.

Il numero di barre dell'intervallo di tempo scelto e la dimensione dell'array del buffer vengono confrontati nella condizione di loop. Se si dispone di più barre, ovvero non possono essere posizionate tutte nell'array buffer, l'intervallo di tempo impiegato viene ridotto di dieci giorni, il che significa che vengono aggiunti dieci giorni alla data di inizio dell'analisi. Questo continua fino a quando l'array del buffer non sarà in grado di includere tutti i dati delle barre. La funzione restituisce la data calcolata.

//+------------------------------------------------------------------+
//| 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. La funzione di copia dei dati

Innanzitutto, i dati vengono copiati con le funzioni di copia dei dati (func_copy_price e func_copy_date).

Consideriamo la funzione di copia prezzo o func_copy_price, che consente di copiare nell'array i prezzi Open, Close, High e Low del periodo e del timeframe impostati. In caso di copia riuscita la funzione restituisce "true".

All'inizio della chiamata di funzione viene inizializzato il valore falso, quindi viene inizializzata una variabile di esito dei dati copiati e viene assegnato un valore negativo. Viene dichiarato un array comune price_interim[] per memorizzare i dati copiati temporanei e la variabile bars_to_copy per impedire il salvataggio dei dati copiati.

Inoltre, la funzione ripristina le variabili dichiarate in precedenza per la memorizzazione dei dati copiati, calcola il numero di barre sull'intervallo di tempo e, in base al prezzo scelto (0-Chiudi, 1-Apri, 2-Alto e 3-Basso) e uno switch statement, assegna il valore dei dati precedentemente copiati sulla variabile bars_copied prezzi. Successivamente viene calcolato il numero di dati da copiare. Se i dati sono stati copiati in precedenza, le ultime informazioni sulla barra copiate vengono eliminate per impedire modifiche al grafico.

Uno switch copia i dati del prezzo richiesti nell'array price_interim[] time. Successivamente, viene controllato il risultato della copia e un interruttore riempie le variabili dei dati copiati.

//+------------------------------------------------------------------+
//| 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" o la funzione di copia della data. Il codice della funzione è simile all'unità sopra menzionata, la differenza sta nel tipo di dati copiati.

//+------------------------------------------------------------------+
//| 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. Calcolo dei mattoni

Come puoi vedere dai parametri dell'indicatore, una dimensione del mattone può essere impostata sia in punti che in percentuale del prezzo corrente. I punti sono un valore fisso, ma come si verificano i calcoli in percentuale? A questo scopo esiste la funzione di calcolo dei mattoni "func_calc_dorstep".

Ci sono tre parametri di input: il prezzo corrente (per calcolare la percentuale del prezzo, se la dimensione del mattone è in percentuale), il metodo di calcolo (punti o percentuale) e la dimensione del passo (impostata con un valore che può essere in percentuale o in punti).

All'inizio della funzione la variabile per la risposta viene inizializzata di tipo double e a seconda del metodo di calcolo selezionato dall'istruzione condizionale if-else viene assegnata in punti. Quindi la variabile di risposta viene convertita nel tipo int per mantenere il valore intero, anche se i calcoli hanno prodotto un valore non intero.

//+------------------------------------------------------------------+
//| 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. La funzione principale - Renko Chart graduating

La funzione principale del Renko Chart graduating - "func_draw_renko". Questa funzione è responsabile dei buffer grafici (buffer indicatori) e del riempimento degli array dei buffer di calcolo. I buffer di calcolo memorizzano le informazioni di ciascun mattone.

I parametri di input della funzione sono array di dati di prezzi e date di costruzione delle barre. Qui puoi trovare informazioni sul tipo di passo e il suo parametro, il filtro inverso e il parametro di disegno delle ombre.

La funzione può essere suddivisa in due parti: la parte con il numero di calcolo dei mattoni e la parte con il calcolo e il riempimento dei buffer grafici.

All'inizio della funzione i buffer vengono ripristinati per spegnere le caselle vuote. Successivamente vengono immesse le variabili ausiliarie: la variabile "doorstep_now" viene utilizzata per il passo (utilizzata per modificare la sua dimensione al passo percentuale), "point_go" memorizza le informazioni sulla distanza dall'ultimo mattone costruito, la variabile "a" viene utilizzata per il calcolo dei mattoni, "up_price_calc" e "down_price_calc" - l'ultimo prezzo massimo e minimo analizzato, "type_box_calc" - l'ultimo tipo di mattone analizzato (su o giù).

Entrambe le parti della funzione sono costituite da un ciclo, la seconda parte completa la prima. Analizza il processo in dettaglio.

Il primo ciclo viene elaborato attraverso tutti i valori copiati, il valore "bars" è responsabile di un numero di dati copiati (viene calcolato in una funzione "func_concolidation", che verrà considerata in seguito). Più avanti nel ciclo, la funzione inizia il calcolo della dimensione del mattone. Poiché ogni barra ha un prezzo di chiusura diverso, se viene utilizzato il gradino percentuale, esso dovrebbe essere calcolato separatamente per ciascuna barra.

L'istruzione if condizionale controlla la direzione del prezzo, mentre il prezzo deve superare uno o più passi di distanza. Dopo che è stata determinata la direzione del movimento del prezzo, viene verificata la condizione del movimento precedente (l'ultimo mattone). Ciò avviene perché i parametri dell'indicatore includono il parametro del filtro (numero di mattoni necessari per l'inversione). Dopo che tutte le condizioni sono state verificate, il ciclo viene avviato, viene elaborato tante volte quanti i mattoni rappresentano l'attuale movimento del prezzo.

Le barre di visualizzazione vengono calcolate, le matrici dei buffer di calcolo vengono ridimensionate e ripristinate. Successivamente, ai primi array di calcolo (utilizzati durante il primo confronto) vengono assegnati valori primari.

Se il numero massimo possibile di barre visualizzate è inferiore al numero possibile di mattoncini, vengono calcolati i mattoncini aggiuntivi e viene visualizzato il messaggio relativo al valore basso. Questo viene fatto per evitare una visualizzazione errata del grafico.

La variabile di calcolo del numero di mattoni viene azzerata e si avvia il ciclo principale. A differenza del ciclo precedente, il ciclo principale è anche responsabile del riempimento del calcolo degli array di buffer e dell'azzeramento del contatore di mattoni.

Al termine della funzione vengono riempiti i buffer grafici.

//+------------------------------------------------------------------+
//| 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. Funzione per la creazione degli oggetti grafici "Trend line" e "rettangolo"

La funzione per la creazione dell'oggetto grafico "linea di tendenza" o "func_create_trend_line" e la funzione per la creazione dell'oggetto grafico "rettangolo" o "func_create_square_or_rectangle" si basano sui dati menzionati nel riferimento a OBJ_RECTANGLE e OBJ_TREND. Sono utilizzati per creare oggetti grafici nel grafico "Renko" e per costruire "ZigZag" sul grafico principale.

//+------------------------------------------------------------------+
//| 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. La costruzione "Renko" sulla carta principale

A causa dell'uso degli array di buffer comuni di calcolo, la funzione per i grafici Renko o "func_draw_renko_main_chart" è piuttosto compatta.

I parametri di input includono: il mattone verso l'alto e verso il basso con le loro cornici, due tipi di larghezza delle cornici (la prima è usata per il mattone, la seconda - per la sua cornice), tre opzioni di visualizzazione (di "mattoni", i loro colori e cornici ).

Per prima cosa vengono dichiarate le variabili con i nomi degli oggetti, poi viene aperto il ciclo con il nome generato di ogni oggetto e a seconda del tipo di mattone precedente viene lanciata la funzione degli oggetti grafici "linea di tendenza" e "rettangolo". I parametri sono presi dalle matrici del buffer di calcolo.

//+------------------------------------------------------------------+
//| 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. La costruzione "ZigZag" sul grafico principale

Il prossimo tipo di supplemento all'indicatore è la funzione di creazione di grafici "ZigZag" o "func_draw_zig_zag".

I parametri di input: la modalità di disegno (sul prezzo massimo o minimo, o sui punti del grafico), la larghezza della linea, il colore della linea verso l'alto o verso il basso.

La modifica del parametro "zig_zag_shadow" è visibile nell'immagine 4. Se "vero" è attivato, l'indicatore disegna le linee "ZigZag" sui punti ombra (prezzi minimo e massimo), nell'opzione "falso", le linee "ZigZag" sono disegnate sui punti massimo e minimo "Renko" .


Fig.4. L'impatto del parametro "zig_zag_shadow" su EURUSD, H1, 10 punti.

Fig.4. L'impatto del parametro "zig_zag_shadow" su EURUSD, H1, 10 punti. 

Per costruire l'oggetto "linea di tendenza" sono necessari due punti (inizio e fine), inserire due variabili per il parametro prezzo e due variabili per il parametro data. Se le istruzioni condizionali impostano il primo punto in base al tipo di mattone iniziale.

Viene avviato il ciclo che costruisce tutti gli oggetti. Come puoi vedere, il ciclo si avvia dalla seconda analisi del mattone, poiché il primo punto è già impostato. Quindi l'istruzione condizionale if controlla il tipo di mattone (il comportamento del prezzo). La variabile del nome dell'oggetto viene riempita e, a seconda del cambio di spostamento, il ciclo si divide. A sua volta, a seconda del metodo di disegno, è diviso in due varianti.

Se viene visualizzato sui prezzi minimo e massimo, gli array di dati Price_high[] e Price_low[] cercano i punti minimi e massimi vicini. La ricerca è ristretta con le barre vicine.

Se è graduato sui punti del grafico, i dati vengono assegnati dagli array di buffer.

Viene chiamata la funzione di costruzione della "linea di tendenza". La funzione termina l'analisi e la creazione di grafici dello "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. Eliminazione di oggetti grafici creati in precedenza

Il numero magico viene utilizzato per determinare gli oggetti dell'indicatore. Semplifica il lancio di diversi indicatori su un grafico e il processo di eliminazione degli oggetti.

La funzione successiva è la funzione per l'eliminazione di oggetti o "func_delete_objects". Il nome (impostato a seconda degli oggetti: linea di tendenza o rettangolo) e il numero di oggetti sono due parametri di input. La funzione sceglie gli oggetti ed elimina gli oggetti con nome già assegnato.

//+------------------------------------------------------------------+
//| 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);
     }
  }

È stata creata la funzione che consolida tutte le funzioni per l'eliminazione di tutti gli oggetti indicatori.

//+------------------------------------------------------------------+
//| 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. Funzione per la creazione dei livelli

La funzione "func_create_levels" per la creazione di livelli semplifica la visualizzazione del grafico nella finestra dell'indicatore. Ha solo due parametri di input: numero di livelli creati e il loro colore.

Nel corpo della funzione l’IndicatorSetInteger viene utilizzato per impostare il numero di livelli visualizzati, quindi prezzo e colore vengono impostati per ciascun livello.

//+------------------------------------------------------------------+
//| 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. La funzione di consolidamento

La funzione "func_consolidation" è stata creata per consolidare tutte le funzioni.

La funzione chiama tutte le funzioni eseguite.

//+------------------------------------------------------------------+
//| 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. Funzioni OnCalculate() e OnChartEvent()

Prima di passare alla funzione OnCalculate(), diamo un'occhiata alla funzione "func_new_bar" che analizza la nuova barra.

È la funzione semplificata descritta in IsNewBar.

//+------------------------------------------------------------------+
//| 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);
  }

La funzione OnCalculate() avvia il consolidamento di tutte le funzioni se viene creata una nuova barra durante l'aggiornamento del grafico. 

//+------------------------------------------------------------------+
//| 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);
  }

La funzione OnChartEvent() cancella tutti gli oggetti grafici premendo "C", premendo "R" si avvia il ridisegno del grafico (la funzione di consolidamento).

//+------------------------------------------------------------------+
//| 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. OnDeinit() Function

E, infine, la funzione OnDeinit(). Questa funzione lancia la funzione di cancellazione di tutti gli oggetti grafici dell'indicatore.

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+ 
void OnDeinit(const int reason)
  {
//--- delete all graphical objects of the indicator
   func_all_delete();
  }


4. Utilizzo del grafico Renko nella pratica

Il grafico Renko è costruito secondo la strategia dei movimenti di prezzo.

Cominciamo con la strategia più popolare: vendere quando il mattone che si muove verso l'alto inizia a muoversi verso il basso e comprare nel caso contrario.

Questo è mostrato in Fig. 5:


Fig.5. Grafico Renko standard (EURUSD H4, 20 punti)

Fig.5. Grafico Renko standard (EURUSD H4, 20 punti)

La Fig. 5 mostra sei punti (A,B,C,D,E,F) dell'ingresso al mercato.

Nel punto "A" il mattone verso l'alto si trasforma in mattone verso il basso.

Il mattone invertito come nei punti (B,C,D) viene creato con un movimento. Tuttavia, sul punto "E" sono stati creati due mattoni con un movimento poiché le ombre in basso vengono create allo stesso livello.

In questo caso l'ingresso è possibile tra i punti "E" e "F". Non è un'entrata riuscita, in quanto il prezzo si muove in direzione opposta, la situazione analogica è sul punto "F": dove un movimento crea anche due mattoni. Le ombre in alto sono allo stesso livello. Anche se con un forte movimento il prezzo non cambia direzione.

Ciò implica che l'ingresso più favorevole al mercato è quando si crea un mattone di inversione (guarda le ombre) con un movimento. Se vengono creati due mattoni alla volta, questo ingresso potrebbe non essere sicuro.

La laurea a "ZigZag" in questo grafico può essere utilizzata per l'analisi grafica. La Fig. 6 mostra alcuni esempi: le linee "supporto" e "resistenza", l'impostazione del modello "testa e spalle".


Fig.6. L'analisi grafica (GBPUSD H4, 20 punti)

Fig.6. L'analisi grafica (GBPUSD H4, 20 punti)

L'analisi grafica "Canale equidistante" è mostrata in Fig. 7.

L'indicatore è impostato per analizzare l'intervallo di tempo e la graduazione viene visualizzata sull'intervallo di quattro ore.

Tali impostazioni consentono ai segnali personalizzati di seguire simultaneamente i diversi intervalli di tempo, il che significa che un indicatore può essere utilizzato su un intervallo di tempo e l'altro sul secondo.


Fig.7. Analisi del "canale Equidistante" USDCHF, H4, impostazioni su H1, 20 punti.

Fig.7. Analisi del "canale equidistante" USDCHF, H4, impostazioni su H1, 20 punti.

La Fig. 8 rappresenta un altro esempio di tempi diversi su un grafico.

Il grafico a tempo mostra le possibili inversioni di chiusura, il grafico a quattro ore cancella i segnali inutili, il grafico giornaliero approva la lunga durata dei movimenti di tendenza.


Fig.8. L'indicatore Renko su GBPUSD, H1, H4 e D1

Fig.8. L'indicatore Renko su GBPUSD, H1, H4 e D1

Un altro esempio di indicatore è nella Fig. 9. La regola dice: costruisci la linea verso l'alto tra i mattoni rossi più vicini con almeno un mattone blu tra di loro e vendi dopo che il mattone è stato creato sotto la linea.

E il contrario: costruisci la linea verso il basso tra i mattoni blu più vicini con almeno un mattone rosso tra di loro e vendi dopo che il mattone è stato creato sopra la linea.

I colori sono citati secondo la Fig. 9. Fig. 9. Le frecce blu e rosse segnano i punti di disegno della linea e le grandi frecce segnano i segnali per la vendita e l'acquisto.

Fig.9. Un esempio di GBPUSD, H4, indicatore a 25 punti

Fig.9. Un esempio di GBPUSD, H4, indicatore di 25 punti

Conclusione

Il grafico Renko è interessante sia per i principianti che per i trader professionisti. Sono passati molti anni, tuttavia, è ancora utilizzato nei mercati.

In questo articolo ho voluto attirare la tua attenzione verso il grafico Renko e migliorarne la sua analisi. Ho cercato di mostrare il metodo dettagliato della costruzione del grafico Renko.

Sarò lieto di prendere in considerazione nuove idee e miglioramenti per l'indicatore e, forse, di implementarle in futuro. Esistono diversi modi per implementare l'indicatore, potresti trovarene anche tu di nuovi.

Ti ringrazio per l’interesse! Ti auguro di avere successo nel trading e nell'implementazione di nuove strategie commerciali.


Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/792

File allegati |
abcr.mq5 (77.52 KB)
Lavorare con il modem GSM da un Expert Advisor MQL5 Lavorare con il modem GSM da un Expert Advisor MQL5
Attualmente esistono un discreto numero di mezzi per un comodo monitoraggio remoto di un conto di trading: terminali mobili, notifiche push, lavoro con ICQ. Ma tutte richiedono una connessione a Internet. Questo articolo descrive il processo di creazione di un Expert Advisor che ti consentirà di rimanere in contatto con il tuo terminale di trading anche quando Internet mobile non è disponibile, tramite chiamate e messaggi di testo.
MQL5 Cookbook - Consulente esperto multi-valuta e il lavoro con ordini in sospeso in MQL5 MQL5 Cookbook - Consulente esperto multi-valuta e il lavoro con ordini in sospeso in MQL5
Questa volta creeremo un Expert Advisor multi-valuta con un algoritmo di trading basato sul lavoro con gli ordini in sospeso Buy Stop e Sell Stop. Questo articolo considera le seguenti questioni: fare trading in un intervallo di tempo specificato, inserire/modificare/eliminare ordini in sospeso, verificare se l'ultima posizione è stata chiusa a Take Profit o Stop Loss e controllo della cronologia delle operazioni per ciascun simbolo.
Contratti future continui in MetaTrader 5 Contratti future continui in MetaTrader 5
La breve durata dei contratti future complica la loro analisi tecnica. È difficile analizzare tecnicamente grafici brevi. Ad esempio, il numero di barre sul grafico giornaliero del future sull'indice azionario ucraino UX-9.13 è superiore a 100. Pertanto, il trader crea contratti a lungo termine sintetici. Questo articolo spiega come unire i contratti future con date diverse nel terminale MetaTrader 5.
Manuale MQL5: Sviluppo di un indicatore multi-simbolo per l’analisi della divergenza dei prezzi Manuale MQL5: Sviluppo di un indicatore multi-simbolo per l’analisi della divergenza dei prezzi
In questo articolo, considereremo lo sviluppo di un indicatore multi-simbolo per analizzare la divergenza dei prezzi in un determinato periodo di tempo. Gli argomenti principali sono già stati discussi nel precedente articolo sulla programmazione degli indicatori multi-valuta "MQL5 Cookbook: Sviluppo di un indicatore di volatilità multi-simbolo in MQL5". Quindi questa volta ci soffermeremo solo su quelle nuove caratteristiche e funzioni che sono state cambiate radicalmente. Se sei un neofita della programmazione di indicatori multi-valuta, ti consiglio di leggere prima l'articolo precedente.