English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Indicatore per la costruzione di un grafico Three Line Break

Indicatore per la costruzione di un grafico Three Line Break

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

Introduzione

Gli articoli precedenti riguardavano i grafici Point and Figure, Kagi and Renko. Continuando la serie di articoli sui grafici del 20 ° secolo, questa volta parleremo del grafico Three Line Break o, per essere precisi, della sua implementazione attraverso un codice di programma . Ci sono pochissime informazioni sull'origine di questo grafico. Suppongo che sia stato inventato in Giappone. Negli Stati Uniti è stato introdotto da "Beyond Candlesticks" di Steve Nison pubblicato nel 1994.

Così come nei grafici sopra menzionati, l'intervallo di tempo non viene preso in considerazione quando si costruisce il grafico Three Line Break. Il grafico si basa sui prezzi di chiusura di nuova formazione di un determinato intervallo di tempo, che consente di filtrare le fluttuazioni minori di un prezzo rispetto al movimento precedente.

Steve Nison nel suo libro "Beyond Candlesticks" ha descritto undici principi per tracciare questo grafico (p. 185). Li ho raggruppati in tre principi:

  • Principio №1: Per la costruzione, seleziona un prezzo iniziale e poi, a seconda che il mercato si muova al rialzo o al ribasso, traccia una linea ascendente o discendente. Questo segnerà un nuovo minimo o massimo.
  • Principio №2: Quando un nuovo prezzo scende al di sotto del minimo o supera il massimo, possiamo tracciare una linea discendente o ascendente.
  • Principio №3: Per tracciare una linea nella direzione opposta al movimento precedente, è necessario superare il minimo o il massimo. Allo stesso tempo, se c'è più di una riga identica, il minimo o il massimo viene calcolato in base a due righe (se ci sono due righe identiche consecutive) o tre righe (se ci sono tre o più righe identiche consecutive).

Diamo uno sguardo più da vicino all'esempio di una classica costruzione di grafici basata su dati storici (fig. 1).

Fig.1 Esempio di costruzione di un grafico Three Line Break (EURUSD H1 27.06.2014)

Fig.1 Esempio di costruzione di un grafico Three Line Break (EURUSD H1 27.06.2014)

La Fig. 1 rappresenta un grafico Candlestick sul lato sinistro e un grafico Three Line Break sul lato destro. Questo è un grafico di EURUSD, timeframe H1. La data di inizio del grafico è 27.06.2014 al prezzo 1.3613 (l'orario di chiusura della candela è 00:00), quindi la candela (01:00) chiude a 1.3614, formando la prima linea ascendente del grafico Three Line Break. La successiva candela di direzione ribassista (02:00) forma una linea ascendente, chiudendo a 1,3612 (il prezzo di chiusura è inferiore al minimo precedente).

Quindi le candele rialziste stanno spostando il prezzo verso il segno 1,3619 (03:00), formando un nuovo massimo e una nuova linea. La candela alle 04:00 non è scesa al di sotto del minimo e non ha influito sulla costruzione. La candela alle 05:00 chiude a 1.3623, segnando un nuovo massimo (nuova linea ascendente).

Ora per estendere la tendenza al ribasso, dobbiamo superare due minimi (1,3613), ma i rialzisti (tori) non rinunceranno alla loro posizione e formeranno un nuovo massimo 1,3626 (06:00). Quindi i rialzisti stanno cercando di invertire il trend rialzista per due ore, ma lo stesso trend continua con un nuovo massimo raggiunto a 1,3634 (09:00). I tori sono in testa. Ora per tracciare una linea ascendente bisogna superare tre minimi (1.3626; 1.3623 e 1.3619).

Come si vede, nelle tre ore successive i ribassisti (orsi) stanno prendendo il sopravvento sul mercato, portandolo a quota 1,3612 (12:00). Questo si riflette in una nuova linea ascendente. Tuttavia, le cinque ore successive mostrano che i rialzisti stanno riconquistando la loro posizione e riportano il mercato al punto di 1.3641, superando il precedente massimo a 1.3626 e formando una nuova linea ascendente alle 17:00. I ribassisti non riescono a superare il minimo precedente alle 18:00 e per le successive cinque ore i rialzisti stanno portando il mercato fino al punto di 1,3649, formando ogni ora una nuova linea ascendente.


Nozioni di base sulla costruzione di grafici

Prima di arrivare al codice, parleremo dell'indicatore stesso e scopriremo cosa lo rende diverso dagli altri. È ovvio che il grafico Three Line Break, come altri indicatori, è stato progettato per facilitare un'analisi di mercato efficiente e la ricerca di nuove strategie. Sono sicuro che vorrai sapere se ci sono novità. In realtà ce ne sono alcune. L'indicatore consente di modificare il tipo di prezzo per il calcolo. Copre tutti e quattro i prezzi standard del bar. Il modello classico è progettato per costruire grafici solo per un tipo di prezzo quando la versione modernizzata prevede l'utilizzo di tutti e quattro i tipi di prezzo (aperto, alto, basso e chiuso). Esso modifica l'aspetto della classica costruzione del grafico aggiungendo "ombre" alle linee e facendole sembrare candele giapponesi, il che migliora la percezione visiva del grafico.

La versione aggiornata dispone anche di impostazioni per la sincronizzazione dei dati sui prezzi nel tempo con la sostituzione dei prezzi mancanti con quelli prioritari.

Il tipo modernizzato di costruzione del grafico è presentato in fig. 2:

Fig.2 Grafico modificato basato su quattro tipi di prezzo

Fig.2 Grafico modificato basato su quattro tipi di prezzo

Poiché la costruzione modernizzata combina quattro grafici Three Line Break di diversi tipi di prezzo, è naturale trovare discrepanze tra i prezzi. Per evitarlo, è necessaria la sincronizzazione dei dati nel tempo. La sincronizzazione dei prezzi è stata effettuata in due varianti: completa (fig. 2 a destra) e parziale (fig. 2 a sinistra). La sincronizzazione completa è una sincronizzazione parziale filtrata, dove tutti i dati vengono disegnati sul grafico e i dati mancanti vengono sostituiti dai prezzi prioritari specificati nelle impostazioni. Nella modalità di sincronizzazione completa i dati mancanti vengono semplicemente omessi e vengono disegnati solo le candele con un set completo di dati.

Un'altra innovazione è un separatore di punti, introdotto per comodità per dividere i segnali. Come ben sai, il separatore di punti può essere abilitato nelle impostazioni del grafico. Nell'indicatore questi cambiano a seconda del periodo di tempo, specificato nelle impostazioni. A differenza dei grafici in MetaTrader 5, dove i periodi sono separati da una linea tratteggiata verticale, in questo indicatore un nuovo periodo viene indicato cambiando il colore di una linea (candele, fig. 3):

Fig.3 Separatori di punti nell'indicatore

Fig.3 Separatori di periodo nell'indicatore

Un'altra aggiunta è l'implementazione di un indicatore tecnico iMA, che è costruito sulla base dei prezzi del grafico principale, ma è sincronizzato con i dati dell'indicatore nel tempo. Pertanto i dati vengono filtrati dalla media mobile (fig. 4):

Fig.4 Media mobile interna

Fig.4 Media mobile interna

L'indicatore ha anche una funzione per impostare un movimento minimo in punti per tracciare una linea e il numero di linee necessarie per un'inversione. Funge anche da filtro.


Codice dell'indicatore

L'algoritmo dell'indicatore è piuttosto semplice e prevede tre fasi: copia dei dati, calcolo basato sui dati copiati e riempimento dei buffer dell'indicatore (costruzione di un grafico basato sui dati ricevuti). Il codice è suddiviso in funzioni che sono interconnesse o tra loro, o con i dati di input. Diamo un'occhiata da vicino al codice.

1. Numero di parametri di input dell'indicatore

Il preambolo dell'indicatore contiene una dichiarazione di costruzioni grafiche. Ce ne sono due nell'indicatore: grafico "ABCTB" (DRAW_COLOR_CANDLES) e media mobile aggiuntiva "LINE_TLB" (DRAW_LINE). Di conseguenza, ci sono sei buffer. Seguono quindi i dati di tipo enum per migliorare le impostazioni dell'interfaccia e le impostazioni stesse:

  • magic_numb - Il numero magico ha il tipo long. È un numero univoco per indicare l'indicatore. In caso di necessità, può essere convertito in tipo string senza molte modifiche;
  • time_frame - L'intervallo di tempo di calcolo, tipo ENUM_TIMEFRAMES, è il parametro principale (l'intervallo di tempo dell'indicatore);
  • time_redraw - Periodo degli aggiornamenti del grafico, tipo ENUM_TIMEFRAMES. È l'intervallo di tempo durante il quale avviene un ricalcolo del grafico. Per ridisegnare velocemente il grafico premere il tasto "R" sulla tastiera, il quale effettuerà un controllo integrato dell'indicatore;
  • first_date_start - Data di inizio, digita datetime.datetime. È il parametro principale, il punto di partenza per la copia dei dati e la creazione di grafici;
  • chart_price - Tipo di prezzo per il calcolo (0-Close, 1-Open, 2-High, 3-Low). Per la costruzione di un grafico classico è necessario selezionare un tipo di prezzo. Come già accennato, questo parametro viene ignorato quando è abilitata la costruzione modificata;
  • step_min_f - Passo minimo per una nuova colonna (>0, tipo int) o un salto richiesto per disegnare una linea;
  • line_to_back_f - Numero di righe per visualizzare un'inversione (>0, tipo int). Il tipo classico suggerisce tre linee per mostrare un'inversione;
  • chart_type - Tipo di costruzione del grafico (0-classico, 1-modificato), tipo select. È un cambiamento tra i tipi di costruzione;
  • chart_color_period - Cambia colore all'inizio di un nuovo periodo (tipo boolean). Utilizzato per cambiare il colore della linea all'inizio di ua nuova frase;
  • chart_synchronization - Costruzione di un grafico solo dopo la sincronizzazione completa (tipo boolean, se vero, si verifica una sincronizzazione completa con l'eliminazione di tutti i valori mancanti prima della costruzione di un grafico);
  • chart_priority_close - Priorità del prezzo di chiusura (tipo select, ha quattro varianti. Punta alla priorità del prezzo di chiusura alla sincronizzazione parziale e viene ignorata a quella completa;
  • chart_priority_open - Priorità del prezzo di apertura. Lo stesso vale qui;
  • chart_priority_high - Priorità del prezzo massimo. Lo stesso vale qui;
  • chart_priority_low - Priorità del prezzo minimo. Lo stesso vale qui;
  • ma_draw - Disegna la media (tipo booleano, se vero, quindi traccia la media mobile);
  • ma_price - Tipo di prezzo per la costruzione della media, può essere uno tra ENUM_APPLIED_PRICE;
  • ma_method - Tipo di costruzione, può essere uno tra ENUM_MA_METHOD;
  • ma_period - Periodo medio della media mobile;

Quindi dichiariamo array di buffer, variabili e strutture necessarie per il calcolo.

//+------------------------------------------------------------------+
//|                                                        ABCTB.mq5 |
//|                                 "Azotskiy Aktiniy ICQ:695710750" |
//|                        "" |
//+------------------------------------------------------------------+
// ABCTB - Auto Build Chart Three Line Break
#property copyright "Azotskiy Aktiniy ICQ:695710750"
#property link      ""
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 6
#property indicator_plots   2
//--- plot ABCTB
#property indicator_label1  "ABCTB"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrBlue,clrRed,clrGreenYellow
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot LINE_TLB
#property indicator_label2  "LINE_TLB"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- Price type for calculation
enum type_price
  {
   close=0, // Close
   open=1,  // Open
   high=2,  // Hight
   low=3,   // Low
  };
//--- type of chart construction
enum type_build
  {
   classic=0,  // Classic
   modified=1, // Modified
  };
//--- priority
enum priority
  {
   highest_t=4, // Highest
   high_t=3,    // High
   medium_t=2,  // Medium
   low_t=1,     // Low
  };
//--- input parameters
input long               magic_numb=65758473787389;                // Magic number
input ENUM_TIMEFRAMES    time_frame=PERIOD_CURRENT;                // Calculation time range
input ENUM_TIMEFRAMES    time_redraw=PERIOD_M1;                    // Period of chart updates
input datetime           first_date_start=D'2013.03.13 00:00:00';  // Start date
input type_price         chart_price=close;                        // Price type for calculation (0-Close, 1-Open, 2-High, 3-Low)
input int                step_min_f=4;                             // Minimum step for a new column (>0)
input int                line_to_back_f=3;                         // Number of lines to display a reversal(>0)
input type_build         chart_type=classic;                       // Type of chart construction (0-classic, 1-modified)
input bool               chart_color_period=true;                  // Changing color for a new period
input bool               chart_synchronization=true;               // Constructing a chart only upon complete synchronization
input priority           chart_priority_close=highest_t;           // Priority of the closing price
input priority           chart_priority_open=highest_t;            // Priority of the opening price
input priority           chart_priority_high=highest_t;            // Priority of the maximum price
input priority           chart_priority_low=highest_t;             // Priority of the minimum price
input bool               ma_draw=true;                             // Draw the average
input ENUM_APPLIED_PRICE ma_price=PRICE_CLOSE;                     // Price type for constructing the average
input ENUM_MA_METHOD     ma_method=MODE_EMA;                       // Construction type
input int                ma_period=14;                             // Averaging period
//--- indicator buffers
//--- buffer of the chart
double         ABCTBBuffer1[];
double         ABCTBBuffer2[];
double         ABCTBBuffer3[];
double         ABCTBBuffer4[];
double         ABCTBColors[];
//--- buffer of the average
double         LINE_TLBBuffer[];
//--- variables
MqlRates rates_array[];// bar data array for analysis
datetime date_stop;    // current date
datetime date_start;   // start date variable for calculation
//+------------------------------------------------------------------+
//| Struct Line Price                                                |
//+------------------------------------------------------------------+
struct line_price// structure for storing information about the past lines
  {
   double            up;  // value of the high price
   double            down;// value of the low price
  };
//+------------------------------------------------------------------+
//| Struct Line Information                                          |
//+------------------------------------------------------------------+
struct line_info// structure for storing information about the shared lines
  {
   double            up;
   double            down;
   char              type;
   datetime          time;
  };
line_info line_main_open[];  // data on the opening prices chart
line_info line_main_high[];  // data on the maximum prices chart
line_info line_main_low[];   // data on the minimum prices chart
line_info line_main_close[]; // data on the closing prices chart
//+------------------------------------------------------------------+
//| Struct Buffer Info                                               |
//+------------------------------------------------------------------+
struct buffer_info// structure for storing data for filling a buffer
  {
   double            open;
   double            high;
   double            low;
   double            close;
   char              type;
   datetime          time;
  };
buffer_info data_for_buffer[];// data for filling the modified construction buffer
datetime array_datetime[];    // array for storing information of the time for every line
int time_array[3];            // array for the function func_date_color
datetime time_variable;       // variable for the function func_date_color
bool latch=false;             // variable-latch for the function func_date_color
int handle;                   // handle of the indicator iMA
int step_min;                 // variable of the minimum step
int line_to_back;             // variable of the number of lines to display a reversal

2. Funzione OnInit 

Tutti i buffer degli indicatori sono dichiarati nella funzione OnInit e l'indicazione dell'array è impostata come in una serie temporale.

Quindi impostiamo i valori dell'indicatore che non si rifletteranno sul grafico, impostiamo il nome, specifichiamo il livello di precisione e rimuoviamo i valori correnti perchè sovraccaricano il grafico. Qui impostiamo anche l'handle dell'indicatore iMA e controlliamo la correttezza dei dati inseriti. In caso di errore, viene stampato un messaggio appropriato e il valore viene modificato al minimo.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//--- buffers for a chart
   SetIndexBuffer(0,ABCTBBuffer1,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer1,true);
   SetIndexBuffer(1,ABCTBBuffer2,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer2,true);
   SetIndexBuffer(2,ABCTBBuffer3,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer3,true);
   SetIndexBuffer(3,ABCTBBuffer4,INDICATOR_DATA);
   ArraySetAsSeries(ABCTBBuffer4,true);
   SetIndexBuffer(4,ABCTBColors,INDICATOR_COLOR_INDEX);
   ArraySetAsSeries(ABCTBColors,true);
//--- buffer for constructing the average
   SetIndexBuffer(5,LINE_TLBBuffer,INDICATOR_DATA);
   ArraySetAsSeries(LINE_TLBBuffer,true);
//--- set the values that are not going to be reflected on the chart
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0); // for the chart
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0); // for the average
//--- set the indicator appearance
   IndicatorSetString(INDICATOR_SHORTNAME,"ABCTB "+IntegerToString(magic_numb)); // name of the indicator
//--- accuracy of display
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//--- prohibit displaying the results of the indicator current value
   PlotIndexSetInteger(0,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(1,PLOT_SHOW_DATA,false);
//---
   handle=iMA(_Symbol,time_frame,ma_period,0,ma_method,ma_price);
   if(step_min_f<1)
     {
      step_min=1;
      Alert("Minimum step for a new column must be greater than zero");
     }
   else step_min=step_min_f;
//---
   if(line_to_back_f<1)
     {
      line_to_back=1;
      Alert("The number of lines to display a reversal must be greater than zero");
     }
   else line_to_back=line_to_back_f;
//---
   return(INIT_SUCCEEDED);
  }

3. Funzione di copia dei dati

Poiché l'indicatore è progettato per funzionare con tutti e quattro i tipi di prezzi, è essenziale copiare tutti i dati, compreso il tempo. In MQL5 c'è una struttura chiamata MqlRates. Viene utilizzata per memorizzare informazioni sull'ora di inizio di una sessione di trading, prezzi, volumi e spread.

I parametri di input della funzione sono la data di inizio e di fine, il timeframe e l'array di destinazione del tipo MqlRates. La funzione restituisce true se la copia ha esito positivo. I dati vengono copiati in un array intermedio. I dati mancanti calcolati più una sessione vengono copiati nell’array intermedio e i dati vengono rinnovati in modo permanente. Se la copia nell'array intermedio ha avuto successo, i dati vengono copiati nell'array e passati per garantire il corretto funzionamento della funzione.

//+------------------------------------------------------------------+
//| Func All Copy                                                    |
//+------------------------------------------------------------------+
bool func_all_copy(MqlRates &result_array[],// response array
                   ENUM_TIMEFRAMES period,  // timeframe
                   datetime data_start,     // start date
                   datetime data_stop)      // end date
  {
//--- declaration of auxiliary variables
   bool x=false;       // variable for the function response
   int result_copy=-1; // copied data count
//--- adding variables and arrays for calculation
   static MqlRates interim_array[]; // temporary dynamic array for storing copied data
   static int bars_to_copy;         // number of bars for copying
   static int bars_copied;          // number of copied bars since the start date
//--- find out the current number of bars in the time range
   bars_to_copy=Bars(_Symbol,period,data_start,data_stop);
//--- count the number of bars to be copied
   bars_to_copy-=bars_copied;
//--- if it is not the first time when data is being copied
   if(bars_copied>0)
     {
      bars_copied--;
      bars_to_copy++;
     }
//--- change the size of the receiving array
   ArrayResize(interim_array,bars_to_copy);
//--- copy data to a temporary array
   result_copy=CopyRates(_Symbol,period,0,bars_to_copy,interim_array);
//--- check the result of copying data
   if(result_copy!=-1) // if copying to the temporary array was successful
     {
      ArrayCopy(result_array,interim_array,bars_copied,0,WHOLE_ARRAY); // copy the data from the temporary array to the main one
      x=true;                   // assign the positive response to the function
      bars_copied+=result_copy; // increase the value of the copied data
     }
//---
   return(x);
  }

4. Funzione di calcolo dei dati

Questa funzione è un prototipo di calcolo dei dati per una costruzione classica del grafico Three Line Break. Come già accennato, la funzione calcola solo i dati e li dispone in un array speciale del tipo di struttura line_info, dichiarato all'inizio del codice.

Questa funzione contiene altre due funzioni: func_regrouping (funzione di raggruppamento) e func_insert (funzione di inserimento). Per cominciare, li esamineremo:

4.1. Funzione di raggruppamento

Questa funzione raggruppa le informazioni su linee consecutive con la stessa direzione. È limitata dalla dimensione dell'array che passa al suo interno o, per essere precisi, dal parametro line_to_back_f (numero di righe per visualizzare un'inversione) nelle impostazioni dell'indicatore. Quindi, ogni volta che il controllo viene passato alla funzione, tutti i dati ricevuti su linee identiche si spostano in basso di un punto verso la fine e l'indice 0 viene riempito con un nuovo valore.

In questo modo vengono memorizzate le informazioni sulle linee necessarie per un'interruzione (in caso di costruzione classica l'interruzione ha tre linee).

//+------------------------------------------------------------------+
// Func Regrouping                                                   |
//+------------------------------------------------------------------+
void func_regrouping(line_price &input_array[],// array for regrouping
                     double new_price,         // new price value
                     char type)                // type of movement
  {
   int x=ArraySize(input_array);// find out the size of the array for regrouping
   for(x--; x>0; x--)           // regrouping loop
     {
      input_array[x].up=input_array[x-1].up;
      input_array[x].down=input_array[x-1].down;
     }
   if(type==1)
     {
      input_array[0].up=new_price;
      input_array[0].down=input_array[1].up;
     }
   if(type==-1)
     {
      input_array[0].down=new_price;
      input_array[0].up=input_array[1].down;
     }
  }

 4.2. Funzione di inserimento

 La funzione esegue l'inserimento dei valori nell'array di risposta. Il codice è semplice e non richiede spiegazioni dettagliate. 

//+------------------------------------------------------------------+
// Func Insert                                                       |
//+------------------------------------------------------------------+
void func_insert(line_info &line_m[],  // target array
                 line_price &line_i[], // source array
                 int index,            // array element being inserted
                 char type,            // type of the target column
                 datetime time)        // date
  {
   line_m[index].up=line_i[0].up;
   line_m[index].down=line_i[0].down;
   line_m[index].type=type;
   line_m[index].time=time;
  }

La funzione per il calcolo dei dati è stata convenzionalmente suddivisa in tre parti. La prima parte copia i dati in analisi su un array intermedio con l'aiuto dell'switch dell'operatore. Viene copiato solo il prezzo in questione. La seconda parte esegue un test per calcolare lo spazio richiesto nell'array di dati. Quindi l'array di dati line_main_array[], inizialmente passato alla funzione per la risposta, subisce una modifica. La terza parte, a sua volta, riempie l'array di dati regolato.

//+------------------------------------------------------------------+
//| Func Build Three Line Break                                      |
//+------------------------------------------------------------------+
void func_build_three_line_break(MqlRates &input_array[],      // array for analysis
                                 char price_type,              // type of the price under analysis (0-Close, 1-Open, 2-High, 3-Low)
                                 int min_step,                 // minimum step for drawing a line
                                 int line_back,                // number of lines for a reversal
                                 line_info &line_main_array[]) // array for return (response) of the function
  {
//--- calculate the size of the array for analysis
   int array_size=ArraySize(input_array);
//--- extract data required for calculation to an intermediate array
   double interim_array[];// intermediate array
   ArrayResize(interim_array,array_size);// adjust the intermediate array to the size of the data
   switch(price_type)
     {
      case 0: // Close
        {
         for(int x=0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].close;
           }
        }
      break;
      case 1: // Open
        {
         for(int x=0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].open;
           }
        }
      break;
      case 2: // High
        {
         for(int x=0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].high;
           }
        }
      break;
      case 3: // Low
        {
         for(int x=0; x<array_size; x++)
           {
            interim_array[x]=input_array[x].low;
           }
        }
      break;
     }
//--- enter the variables for storing information about current situation
   line_price passed_line[];// array for storing information about the latest prices of the lines (type structure line_price)
   ArrayResize(passed_line,line_back+1);
   int line_calc=0;// number of lines
   int line_up=0;// number of the last ascending lines
   int line_down=0;// number of the last descending lines
   double limit_up=0;// upper limit necessary to pass
   double limit_down=0;// lower limit necessary to pass
/* Fill variables informing of the current situation with the first values */
   passed_line[0].up=interim_array[0];
   passed_line[0].down=interim_array[0];
//--- start the first loop to calculate received data for filling a buffer for drawing
   for(int x=0; x<array_size; x++)
     {
      if(line_calc==0)// no lines have been drawn
        {
         limit_up=passed_line[0].up;
         limit_down=passed_line[0].down;
         if(interim_array[x]>=limit_up+min_step*_Point)// the upper limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],1);// regroup
            line_calc++;// update the line counter
            line_up++;
           }
         if(interim_array[x]<=limit_down-min_step*_Point)// the lower limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],-1);// regroup
            line_calc++;// update the line counter
            line_down++;
           }
        }
      if(line_up>line_down)// last ascending line (lines)
        {
         limit_up=passed_line[0].up;
         limit_down=passed_line[(int)MathMin(line_up,line_back-1)].down;
         if(interim_array[x]>=limit_up+min_step*_Point)// the upper limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],1);// regroup
            line_calc++;// update the line counter
            line_up++;
           }
         if(interim_array[x]<limit_down)// the lower limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],-1);// regroup
            line_calc++;// update the line counter
            line_up=0;
            line_down++;
           }
        }
      if(line_down>line_up)// last descending line (lines)
        {
         limit_up=passed_line[(int)MathMin(line_down,line_back-1)].up;
         limit_down=passed_line[0].down;
         if(interim_array[x]>limit_up)// the upper limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],1);// regroup
            line_calc++;// update the line counter
            line_down=0;
            line_up++;
           }
         if(interim_array[x]<=limit_down-min_step*_Point)// the lower limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],-1);// regroup
            line_calc++;// update the line counter
            line_down++;
           }
        }
     }
   ArrayResize(line_main_array,line_calc);// change the size of the target array
//--- zeroise variables and fill with the the initial data
   line_calc=0;
   line_up=0;
   line_down=0;
   passed_line[0].up=interim_array[0];
   passed_line[0].down=interim_array[0];
//--- start the second loop to fill a buffer for drawing
   for(int x=0; x<array_size; x++)
     {
      if(line_calc==0)// no lines have been drawn
        {
         limit_up=passed_line[0].up;
         limit_down=passed_line[0].down;
         if(interim_array[x]>=limit_up+min_step*_Point)// the upper limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],1);// regroup
            func_insert(line_main_array,passed_line,line_calc,1,input_array[x].time);
            line_calc++;// update the line counter
            line_up++;
           }
         if(interim_array[x]<=limit_down-min_step*_Point)// the lower limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],-1);// regroup
            func_insert(line_main_array,passed_line,line_calc,-1,input_array[x].time);
            line_calc++;// update the line counter
            line_down++;
           }
        }
      if(line_up>line_down)// last ascending line (lines)
        {
         limit_up=passed_line[0].up;
         limit_down=passed_line[(int)MathMin(line_up,line_back-1)].down;
         if(interim_array[x]>=limit_up+min_step*_Point)// the upper limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],1);// regroup
            func_insert(line_main_array,passed_line,line_calc,1,input_array[x].time);
            line_calc++;// update the line counter
            line_up++;
           }
         if(interim_array[x]<limit_down)// the lower limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],-1);// regroup
            func_insert(line_main_array,passed_line,line_calc,-1,input_array[x].time);
            line_calc++;// update the line counter
            line_up=0;
            line_down++;
           }
        }
      if(line_down>line_up)// last descending line (lines)
        {
         limit_up=passed_line[(int)MathMin(line_down,line_back-1)].up;
         limit_down=passed_line[0].down;
         if(interim_array[x]>limit_up)// the upper limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],1);// regroup
            func_insert(line_main_array,passed_line,line_calc,1,input_array[x].time);
            line_calc++;// update the line counter
            line_down=0;
            line_up++;
           }
         if(interim_array[x]<=limit_down-min_step*_Point)// the lower limit has been passed
           {
            func_regrouping(passed_line,interim_array[x],-1);// regroup
            func_insert(line_main_array,passed_line,line_calc,-1,input_array[x].time);
            line_calc++;// update the line counter
            line_down++;
           }
        }
     }
  }

5. Funzione di costruzione del grafico

Lo scopo di questa funzione è calcolare i dati per un grafico in base al parametro di costruzione selezionato (classico o modificato) e riempire il buffer dell'indicatore con i dati per la visualizzazione. Oltre alla funzione precedente, la funzione di costruzione del grafico ha tre funzioni aggiuntive. Queste sono la funzione del colore, la funzione della sincronizzazione e la funzione della media mobile. Affrontiamo l’argomento in modo più dettagliato.

5.1. Funzione colore

Questa funzione ha un solo parametro di input: il tempo. La risposta della funzione è una variabile booleana. Se i dati passati sono il bordo del periodo, la funzione restituirà true. Poiché i periodi dipendono dall'intervallo di tempo selezionato, la funzione ha una separazione dei periodi incorporata dall'operatore condizionale if. Dopo che il periodo è stato selezionato, viene verificato se è già iniziato un nuovo periodo. Viene effettuato mediante la conversione di una data in struttura MqlDateTime e tramite il suo confronto. Per il periodo fino al secondo semestre compreso, le variazioni del valore della data indicano l'inizio di un nuovo periodo. I tempi da H12 a D1 inclusi indicano variazioni in mesi e tra W1 e MN controlliamo la variazione nell'anno.

Sfortunatamente, la struttura MqlDateTime non ha informazioni sulla settimana corrente. Questo problema è stato risolto creando un punto iniziale rappresentato dalla variabile time_variable. Più avanti, un certo numero di secondi in una settimana viene sottratto da questa data.

//+------------------------------------------------------------------+
// Func Date Color                                                   |
//+------------------------------------------------------------------+
bool func_date_color(datetime date_time) // input date
  {
   bool x=false;// response variable
   int seconds=PeriodSeconds(time_frame);// find out the calculation time range
   MqlDateTime date;
   TimeToStruct(date_time,date);// convert data
   if(latch==false) // check the state of the latch
     {
      MqlDateTime date_0;
      date_0=date;
      date_0.hour=0;
      date_0.min=0;
      date_0.sec=0;
      int difference=date_0.day_of_week-1;
      datetime date_d=StructToTime(date_0);
      date_d=date_d-86400*difference;
      time_variable=date_d;
      latch=true;// lock the latch
     }
   if(seconds<=7200)// period is less than or equal to H2
     {
      if(time_array[0]!=date.day)
        {
         x=true;
         time_array[0]=date.day;
        }
     }
   if(seconds>7200 && seconds<=43200)// period is greater than H2 but less than or equal to H12
     {
      if(time_variable>=date_time)
        {
         x=true;
         time_variable=time_variable-604800;
        }
     }
   if(seconds>43200 && seconds<=86400)// period is greater than H12 but less than or equal to D1
     {
      if(time_array[1]!=date.mon)
        {
         x=true;
         time_array[1]=date.mon;
        }
     }
   if(seconds>86400)// period W1 or MN
     {
      if(time_array[2]!=date.year)
        {
         x=true;
         time_array[2]=date.year;
        }
     }
   return(x);
  }

5.2. Funzione di sincronizzazione

La funzione di sincronizzazione ha sei parametri di input: quattro di questi sono la priorità dei prezzi, il parametro booleano di sincronizzazione completa o parziale e l'array stesso in analisi. La funzione è divisa in due parti, le quali rappresentano un caso di sincronizzazione completa e parziale.

La sincronizzazione completa viene eseguita in tre fasi:

  1. Calcolo degli elementi dell'array che soddisfano la condizione di contenimento di dati su tutti e quattro i tipi di prezzo.
  2. Copia di elementi in una matrice intermedia nelle stesse condizioni.
  3. Copia dall'array intermedio a quello passato dai parametri.

La sincronizzazione parziale è più complessa.

L'array di struttura unidimensionale passato viene convertito in uno bidimensionale, dove il primo indice indica l'ordine e il secondo il tipo di prezzo. Quindi viene introdotto un array unidimensionale con quattro elementi. I livelli di priorità dei prezzi vengono copiati in questo array e quindi l'array viene ordinato per identificare l'ordine di priorità. Successivamente eseguiamo la distribuzione in base alle priorità utilizzando il ciclo for e l'operatore condizionale if. Allo stesso tempo, se le priorità sono uguali, la sequenza dei prezzi è la seguente: chiusura, apertura, massimo, minimo. Non appena l'operatore if trova il primo valore prioritario, il ciclo for sostituisce tutti i dati ‘zero’ nell'array bidimensionale creato in precedenza con quelli prioritari ecc.

//+------------------------------------------------------------------+
// Func Synchronization                                              |
//+------------------------------------------------------------------+
void func_synchronization(buffer_info &info[],
                          bool synchronization,
                          char close,
                          char open,
                          char high,
                          char low)
  {
   if(synchronization==true)// carry out a complete synchronization
     {
      int calc=0;// count variable
      for(int x=0; x<ArraySize(info); x++)// count complete data
        {
         if(info[x].close!=0 && info[x].high!=0 && info[x].low!=0 && info[x].open!=0)calc++;
        }
      buffer_info i_info[];    // enter a temporary array for copying
      ArrayResize(i_info,calc);// change the size of the temporary array
      calc=0;
      for(int x=0; x<ArraySize(info); x++)// copy data into the temporary array
        {
         if(info[x].close!=0 && info[x].high!=0 && info[x].low!=0 && info[x].open!=0)
           {
            i_info[calc]=info[x];
            calc++;
           }
        }
      ZeroMemory(info);        // clear the target array
      ArrayResize(info,calc);  // change the size of the main array
      for(int x=0; x<calc; x++)// copy data from the temporary array to the main one
        {
         info[x]=i_info[x];
        }
     }
   if(synchronization==false)  // change zero values to priority ones
     {
      int size=ArraySize(info); // measure the size of the array
      double buffer[][4];       // create a temporary array for calculation
      ArrayResize(buffer,size); // change the size of the temporary array
      for(int x=0; x<size; x++) // copy data into the temporary array
        {
         buffer[x][0]=info[x].close;
         buffer[x][1]=info[x].open;
         buffer[x][2]=info[x].high;
         buffer[x][3]=info[x].low;
        }
      char p[4];// enter an array for sorting by the order
      p[0]=close; p[1]=open; p[2]=high; p[3]=low;// assign variables for further sorting
      ArraySort(p); // sort
      int z=0,v=0;  // initialize frequently used variables
      for(int x=0; x<4; x++)// taking into account the results of the sorting, look through all variables and substitute them according to the priority
        {
         if(p[x]==close)// priority is for the closing prices
           {
            for(z=0; z<size; z++)
              {
               for(v=1; v<4; v++)
                 {
                  if(buffer[z][v]==0)buffer[z][v]=buffer[z][0];
                 }
              }
           }
         if(p[x]==open)// priority is for the opening prices
           {
            for(z=0; z<size; z++)
              {
               for(v=0; v<4; v++)
                 {
                  if(v!=1 && buffer[z][v]==0)buffer[z][v]=buffer[z][1];
                 }
              }
           }
         if(p[x]==high)// priority is for the maximum prices
           {
            for(z=0; z<size; z++)
              {
               for(v=0; v<4; v++)
                 {
                  if(v!=2 && buffer[z][v]==0)buffer[z][v]=buffer[z][2];
                 }
              }
           }
         if(p[x]==low)// priority is for the minimum prices
           {
            for(z=0; z<size; z++)
              {
               for(v=0; v<3; v++)
                 {
                  if(buffer[z][v]==0)buffer[z][v]=buffer[z][3];
                 }
              }
           }
        }
      for(int x=0; x<size; x++)// copy data from the temporary array back
        {
         info[x].close=buffer[x][0];
         info[x].open=buffer[x][1];
         info[x].high=buffer[x][2];
         info[x].low=buffer[x][3];
        }
     }
  }

5.3. Funzione della media mobile

È la funzione più semplice. Utilizzando l'handle dell'indicatore, ricevuto nella funzione OnInit, copiamo il valore, corrispondente alla data passata nei parametri della funzione. Quindi questo valore viene restituito come risposta a questa funzione.

//+------------------------------------------------------------------+
// Func MA                                                           |
//+------------------------------------------------------------------+
double func_ma(datetime date)
  {
   double x[1];
   CopyBuffer(handle,0,date,1,x);
   return(x[0]);
  }

La funzione di tracciare un grafico è convenzionalmente divisa in modo classico e quella modificato. La funzione ha due parametri di input: tipo di prezzo per la costruzione (ignorato durante la costruzione modificata) e tipo di costruzione (classica e modificata).

All'inizio i buffer indicatori vengono cancellati e poi, a seconda del tipo di costruzione, divisi in due parti. La prima parte (stiamo parlando della costruzione modificata) inizia con il richiamo della funzione per il calcolo di tutti e quattro i tipi di prezzo. Quindi creiamo un array di dati comune in cui copiamo i dati in uso, ricevuti quando si chiama la funzione di calcolo dei dati. Quindi l'array di dati ricevuto viene ordinato e cancellato dai dati replicati. Successivamente l'array data_for_buffer[], dichiarato a livello globale, viene riempito in base a date consecutive con la seguente sincronizzazione dei dati. Il riempimento dei buffer indicatori è la fase finale della costruzione modificata.

La seconda parte (costruzione classica) è molto più semplice. Dapprima viene richiamata la funzione di calcolo dati e poi vengono riempiti i buffer indicatori.

//+------------------------------------------------------------------+
//| Func Chart Build                                                 |
//+------------------------------------------------------------------+
void func_chart_build(char price, // price type for chart construction
                      char type)  // type of chart construction
  {
//--- Zeroise the buffers
   ZeroMemory(ABCTBBuffer1);
   ZeroMemory(ABCTBBuffer2);
   ZeroMemory(ABCTBBuffer3);
   ZeroMemory(ABCTBBuffer4);
   ZeroMemory(ABCTBColors);
   ZeroMemory(LINE_TLBBuffer);
   if(type==1)// construct a modified chart (based on all price types)
     {
      func_build_three_line_break(rates_array,0,step_min,line_to_back,line_main_close);// data on closing prices
      func_build_three_line_break(rates_array,1,step_min,line_to_back,line_main_open);// data on opening prices
      func_build_three_line_break(rates_array,2,step_min,line_to_back,line_main_high);// data on maximum prices
      func_build_three_line_break(rates_array,3,step_min,line_to_back,line_main_low);// data on minimum prices
      //--- calculate data arrays
      int line_main_calc[4];
      line_main_calc[0]=ArraySize(line_main_close);
      line_main_calc[1]=ArraySize(line_main_open);
      line_main_calc[2]=ArraySize(line_main_high);
      line_main_calc[3]=ArraySize(line_main_low);
      //--- gather the date array
      int all_elements=line_main_calc[0]+line_main_calc[1]+line_main_calc[2]+line_main_calc[3];// find out the number of all elements
      datetime datetime_array[];// enter the array for copying
      ArrayResize(datetime_array,all_elements);
      int y[4];
      ZeroMemory(y);
      for(int x=0;x<ArraySize(datetime_array);x++)// copy data into the array
        {
         if(x<line_main_calc[0])
           {
            datetime_array[x]=line_main_close[y[0]].time;
            y[0]++;
           }
         if(x<line_main_calc[0]+line_main_calc[1] && x>=line_main_calc[0])
           {
            datetime_array[x]=line_main_open[y[1]].time;
            y[1]++;
           }
         if(x<line_main_calc[0]+line_main_calc[1]+line_main_calc[2] && x>=line_main_calc[0]+line_main_calc[1])
           {
            datetime_array[x]=line_main_high[y[2]].time;
            y[2]++;
           }
         if(x>=line_main_calc[0]+line_main_calc[1]+line_main_calc[2])
           {
            datetime_array[x]=line_main_low[y[3]].time;
            y[3]++;
           }
        }
      ArraySort(datetime_array);// sort the array
      //--- delete replicated data from the array
      int good_info=1;
      for(int x=1;x<ArraySize(datetime_array);x++)// count useful information
        {
         if(datetime_array[x-1]!=datetime_array[x])good_info++;
        }
      ArrayResize(array_datetime,good_info);
      array_datetime[0]=datetime_array[0];// copy the first element as it is the pattern in the beginning of comparison
      good_info=1;
      for(int x=1;x<ArraySize(datetime_array);x++)// fill the new array with useful data
        {
         if(datetime_array[x-1]!=datetime_array[x])
           {
            array_datetime[good_info]=datetime_array[x];
            good_info++;
           }
        }
      //--- fill the buffer for drawing (colored candles)
      int end_of_calc[4];// variables of storing information about the last comparison
      ZeroMemory(end_of_calc);
      ZeroMemory(data_for_buffer);
      ArrayResize(data_for_buffer,ArraySize(array_datetime));// change the size of the declared global array for storing data before passing it to a buffer
      for(int x=0; x<ArraySize(array_datetime); x++)
        {
         data_for_buffer[x].time=array_datetime[x];
         for(int s=end_of_calc[0]; s<line_main_calc[0]; s++)
           {
            if(array_datetime[x]==line_main_close[s].time)
              {
               end_of_calc[0]=s;
               if(line_main_close[s].type==1)data_for_buffer[x].close=line_main_close[s].up;
               else data_for_buffer[x].close=line_main_close[s].down;
               break;
              }
           }
         for(int s=end_of_calc[1]; s<line_main_calc[1]; s++)
           {
            if(array_datetime[x]==line_main_open[s].time)
              {
               end_of_calc[1]=s;
               if(line_main_open[s].type==1)data_for_buffer[x].open=line_main_open[s].down;
               else data_for_buffer[x].open=line_main_open[s].up;
               break;
              }
           }
         for(int s=end_of_calc[2]; s<line_main_calc[2]; s++)
           {
            if(array_datetime[x]==line_main_high[s].time)
              {
               end_of_calc[2]=s;
               data_for_buffer[x].high=line_main_high[s].up;
               break;
              }
           }
         for(int s=end_of_calc[3]; s<line_main_calc[3]; s++)
           {
            if(array_datetime[x]==line_main_low[s].time)
              {
               end_of_calc[3]=s;
               data_for_buffer[x].low=line_main_low[s].down;
               break;
              }
           }
        }
      //--- start the function of synchronizing data
      func_synchronization(data_for_buffer,chart_synchronization,chart_priority_close,chart_priority_open,chart_priority_high,chart_priority_low);
      //--- preparatory actions before starting the function func_date_color
      ZeroMemory(time_array);
      time_variable=0;
      latch=false;
      //--- fill the buffer for drawing candles
      for(int x=ArraySize(data_for_buffer)-1,z=0; x>=0; x--)
        {
         ABCTBBuffer1[z]=data_for_buffer[x].open;
         ABCTBBuffer2[z]=data_for_buffer[x].high;
         ABCTBBuffer3[z]=data_for_buffer[x].low;
         ABCTBBuffer4[z]=data_for_buffer[x].close;
         if(ABCTBBuffer1[z]<=ABCTBBuffer4[z])ABCTBColors[z]=0;
         if(ABCTBBuffer1[z]>=ABCTBBuffer4[z])ABCTBColors[z]=1;
         if(func_date_color(data_for_buffer[x].time)==true && chart_color_period==true)ABCTBColors[z]=2;
         if(ma_draw==true)LINE_TLBBuffer[z]=func_ma(data_for_buffer[x].time);
         z++;
        }
     }
   else// construct a classic chart (based on one price type)
     {
      func_build_three_line_break(rates_array,price,step_min,line_to_back,line_main_close);// find data on selected prices
      ArrayResize(array_datetime,ArraySize(line_main_close));
      //--- preparatory actions before starting the function func_date_color
      ZeroMemory(time_array);
      time_variable=0;
      latch=false;
      //--- the buffer for drawing candles
      for(int x=ArraySize(line_main_close)-1,z=0; x>=0; x--)
        {
         ABCTBBuffer1[z]=line_main_close[x].up;
         ABCTBBuffer2[z]=line_main_close[x].up;
         ABCTBBuffer3[z]=line_main_close[x].down;
         ABCTBBuffer4[z]=line_main_close[x].down;
         if(line_main_close[x].type==1)ABCTBColors[z]=0;
         else ABCTBColors[z]=1;
         if(func_date_color(line_main_close[x].time)==true && chart_color_period==true)ABCTBColors[z]=2;
         if(ma_draw==true)LINE_TLBBuffer[z]=func_ma(line_main_close[x].time);
         z++;
        }
     }
  }

6. Funzione di consolidamento

Questa funzione unisce tutti gli elementi indicatori di controllo. Dapprima viene definita la data corrente, poi vengono richiamate la funzione di copia dei dati e la funzione di costruzione del grafico.

//+------------------------------------------------------------------+
//| Func Consolidation                                               |
//+------------------------------------------------------------------+
void func_consolidation()
  {
//--- defining the current date
   date_stop=TimeCurrent();
//--- copying data for analysis
   func_all_copy(rates_array,time_frame,first_date_start,date_stop);
//--- basic construction of the chart
   func_chart_build(chart_price,chart_type);
   ChartRedraw();
  }

7. Funzione di costruzione comandata da chiave e controllata automaticamente

Queste funzioni sono progettate per ridisegnare l'indicatore premendo il tasto "R" (OnChartEvent) sulla tastiera o farlo automaticamente in base all'intervallo di tempo selezionato (OnCalculate). Quest'ultimo viene analizzato dalla nuova funzione bar (func_new_bar) che è una versione semplificata della funzione descritta in IsNewBar.

//+------------------------------------------------------------------+
//| 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_consolidation();
     };
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- event of a keystroke
   if(id==CHARTEVENT_KEYDOWN)
     {
      if(lparam==82) //--- the key "R" has been pressed
        {
         func_consolidation();
        }
     }
  }
//+------------------------------------------------------------------+
//| Func New Bar                                                     |
//+------------------------------------------------------------------+
bool func_new_bar(ENUM_TIMEFRAMES period_time)
  {
//---
   static datetime old_times; // variable of storing old values
   bool res=false;            // variable of the analysis result
   datetime new_time[1];      // time of a new bar
//---
   int copied=CopyTime(_Symbol,period_time,0,1,new_time); // copy the time of the last bar to the cell new_time
//---
   if(copied>0) // everything is ок. data copied
     {
      if(old_times!=new_time[0]) // if the old time of the bar is not equal to the new one
        {
         if(old_times!=0) res=true; // if it is not the first start, then new bar = true
         old_times=new_time[0];     // remember the time of the bar
        }
     }
//---
   return(res);
  }

A questo punto finiremo di descrivere il codice dell'indicatore e parleremo delle modalità di utilizzo.


Esempi di utilizzo dell'indicatore in una strategia di trading

Partiamo dalle principali strategie di analisi basate sulla classica costruzione del grafico.

1. Linee bianche e nere come segnali per comprare e vendere

In linea di massima possiamo parlare di due regole:

  1. Regola №1: Acquista, quando ci sono tre linee ascendenti consecutive e vendi, quando ci sono tre linee discendenti consecutive. Tre linee consecutive indicano una tendenza apparente.
  2. Regola №2: Vendi, quando la linea di inversione scende al di sotto di tre linee ascendenti consecutive, acquista, quando la linea di inversione è superiore a tre linee discendenti consecutive.

Diamo un'occhiata alla fig.6, che rappresenta una costruzione classica per EURUSD H1 dall'inizio del 2013 (l'intervallo temporale analizzato è illustrato nella fig.5).

Fig.5 Intervallo temporale analizzato EURUSD H1

Fig.5 Intervallo temporale analizzato EURUSD H1

Fig.6 Costruzione classica del grafico Three Line Break per EURUSD H1, inizio 2013, prezzi di chiusura

Fig.6 Costruzione classica del grafico Three Line Break per EURUSD H1, inizio 2013, prezzi di chiusura

Sul grafico (fig. 6) possiamo vedere chiaramente il segnale (regola №1) tra i punti 1 e 2, il quale rappresenta un punto di partenza per la vendita. In questo caso il guadagno è di oltre 200 punti per quattro cifre decimali. Il successivo punto 4 indica una situazione favorevole per l'acquisto (come nella regola №2). Alla chiusura del punto 5 il profitto era di 40 punti e alla chiusura del punto 6 siamo in pareggio.

Nel punto 6 riconosciamo un segnale per vendere (regola №2). Otteniamo 10 punti di profitto quando chiudiamo al punto 7 e pareggio quando chiudiamo al punto 8. I punti 8 e 9 non possono essere considerati segnali in quanto non soddisfano né la regola №1, né la regola №2. Possiamo acquistare al punto 10 (regola №1); possiamo anche ottenere un profitto di 20 punti alla chiusura al punto 11 o al pareggio al punto 12. Tutti i numeri sono stati arrotondati.

Nel migliore dei casi, utilizzando questa strategia potremmo generare un profitto di 270 punti, il che è impressionante. Allo stesso tempo, nell'intervallo di tempo specificato c'è un movimento intenso che influisce sul profitto. Nel peggiore dei casi, il trading può portare a un pareggio, il che non è male.

Vale la pena ricordare che quando una situazione soddisfa la regola №1 o la regola №2, dobbiamo attendere una conferma di inversione di tendenza rappresentata da una linea nella stessa direzione della tendenza.

2. Canale equidistante, linee di sostegno e resistenti

Un'altra strategia di trading consiste nell'applicare l'analisi tecnica al grafico Three Line Break. Diamo un'occhiata alla fig. 7:

Fig. 7 Canale equidistante, linee di supporto e resistenza, GBPUSD H1, intervallo temporale dal 01.03.2014 al 01.05.2014

Fig. 7 Canale equidistante, linee di supporto e resistenza, GBPUSD H1, intervallo temporale dal 01.03.2014 al 01.05.2014

In Fig. 7 puoi vedere che il canale discendente equidistante è disegnato in linee rosse, il canale ascendente è disegnato in blu e le linee di supporto e resistenza sono disegnate in nero. È chiaro che la prima linea di resistenza si sta trasformando in linea di supporto.

3. Modelli di candele giapponesi

Un grafico modificato (interruzione di due righe) sul timeframe M30 per la coppia USDCAD all'inizio del 2013 sembra piuttosto interessante.

Possiamo distinguere pattern di candele giapponesi che hanno giustificato i loro segnali (fig. 8).

Fig. 8 Grafico modificato a tre linee di interruzione, USDCAD M30, inizio 2013, due linee di interruzione

Fig. 8 Grafico modificato con tre linee di interruzione, USDCAD M30, inizio 2013, due linee di interruzione

All'inizio del grafico possiamo vedere un modello di inversione detto di "Engulfing" sotto №1. Si compone di due candele: rossa e la precedente blu. Dopo la linea di tendenza al rialzo, il mercato scende al numero 2, che è un modello di inversione a una sola candela detto "Hammer". A questo punto il mercato cambia direzione. Lo stesso accade nel modello №3 ("Trottola"). Il seguente schema di inversione "Kharami" (№4) è mostrato dalla candela 4 e da quella grande ascendente accanto ad essa. Anche il pattern №6 è composto da due candele (pattern "Engulfing") ma a differenza del primo modello molto simile, esso fa girare il mercato nella direzione opposta.

Pertanto, si può concludere che l'utilizzo dell'indicatore in questo tipo di analisi è accettabile, ma presenta svantaggi come la rarità del verificarsi di segnali e la possibilità di un significativo drawdown. Questa strategia ha certamente bisogno di ulteriore sviluppo.

4. Media mobile

La modifica parziale, come l'aggiunta di una media mobile solo alle linee tracciate, offre nuove opportunità di analisi.

Osserviamo la fig. 9:

Fig.9 Analisi della media mobile, EURUSD H4, grafico Three Line Break, costruzione classica, dal 01.01.2014 al 01.07.2014

Fig.9 Analisi della media mobile, EURUSD H4, grafico Three Line Break, costruzione classica, dal 01.01.2014 al 01.07.2014

La parte superiore della fig. 9 illustra una costruzione classica basata sui prezzi alti con una media mobile (il periodo di media è 90, il prezzo basso, la media livellata). La parte inferiore mostra una costruzione classica basata su prezzi bassi con media mobile (periodo medio 90, prezzo alto, media livellata).

Quindi, nella parte superiore della fig. 9 la media mobile può essere considerata una linea di supporto e nella parte inferiore, al contrario, una linea di resistenza. Se il prezzo su entrambi i grafici scende al di sotto della media allora c'è una tendenza al ribasso sul mercato, ed è meglio vendere. Quando il prezzo sale al di sopra della media è il momento di comprare. Uno svantaggio di questa strategia è che è pensata per un trading a lungo termine.


Conclusione

In conclusione posso dire che il Three Line Break dà costantemente buoni segnali o, nel peggiore dei casi, porta al pareggio. La pratica dimostra che è meglio applicarlo in un trend a lungo termine e, quindi, non consiglio di utilizzare questo grafico per un trading a breve termine. Se qualcuno ha nuove idee su come usarlo nel trading, sarei lieto di discuterne.

Come al solito, ho cercato di esplorare il codice in dettaglio. Anche in questo caso, se avete idee su come estenderlo, rielaborarlo o ottimizzarlo, scrivete nei commenti all'articolo.


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

File allegati |
abctb.mq5 (68.78 KB)
Racconti di robot di trading: Meno è veramente di più? Racconti di robot di trading: Meno è veramente di più?
Due anni fa in "The Last Crusade" abbiamo esaminato un metodo piuttosto interessante ma attualmente non ampiamente utilizzato per la visualizzazione di informazioni di mercato - grafici a punti e cifre. Ora ti suggerisco di provare a scrivere un robot di trading basato sui modelli rilevati sul grafico a punti e figure.
SQL e MQL5: Lavorare con il database SQLite SQL e MQL5: Lavorare con il database SQLite
Questo articolo è destinato agli sviluppatori interessati a utilizzare SQL nei loro progetti. Spiega le funzionalità e i vantaggi di SQLite. L'articolo non richiede una conoscenza speciale delle funzioni SQLite, ma sarebbe utile una minima conoscenza di SQL.
Costruire una startup di tecnologia sociale, parte I: Twitta i tuoi segnali MetaTrader 5 Costruire una startup di tecnologia sociale, parte I: Twitta i tuoi segnali MetaTrader 5
Oggi impareremo come collegare un terminale MetaTrader 5 con Twitter in modo da poter twittare i segnali di trading dei tuoi EA. Stiamo sviluppando un Social Decision Support System in PHP basato su un servizio web RESTful. Questa idea nasce da una particolare concezione del trading automatico chiamato trading assistito da un computer. Vogliamo che le capacità cognitive dei trader umani filtrino quei segnali di trading che altrimenti verrebbero automaticamente immessi sul mercato dagli Expert Advisor.
Reti neurali economiche - Collega NeuroPro con MetaTrader 5 Reti neurali economiche - Collega NeuroPro con MetaTrader 5
Se specifici programmi di rete neurale per il trading sembrano costosi e complessi o, al contrario, troppo semplici, prova NeuroPro. È gratuito e contiene il set ottimale di funzionalità per i dilettanti. Questo articolo ti spiegherà come usarlo insieme a MetaTrader 5.