English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
L'indicatore ZigZag: Nuovo approccio e nuove soluzioni

L'indicatore ZigZag: Nuovo approccio e nuove soluzioni

MetaTrader 5Sistemi di trading | 11 gennaio 2022, 16:45
388 0
Sergey Pavlov
Sergey Pavlov

Introduzione

Ogni trader conosce sicuramente l'indicatore ZigZag destinato all'analisi dei movimenti di prezzo di una certa o maggiore ampiezza. Una linea ZigZag è una linea spezzata i cui nodi si trovano ai massimi e ai minimi del grafico dei prezzi.

Esistono molte varianti di questo indicatore: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16. Tuttavia, molti sviluppatori di programmi MQL5 sono desiderosi di creare il proprio ZigZag "ideale". I principali svantaggi dell'indicatore ZigZag sono ritardi, contrassegni errati di nodi discutibili (barra esterna) e prestazioni insoddisfacenti.

Secondo me, l'implementazione ZigZag più elegante è stata proposta da Yuri Kulikov (Yurich). Inoltre, ci sono alcuni ottimi articoli MQL4, come "Layman's Notes: ZigZag..." e "Show Must Go On, or Once Again about ZigZag". L'argomento sembra essere stato ampiamente esplorato, con un gran numero di pubblicazioni disponibili. Eppure c'è qualcosa di magnetizzante in questo. Ora ha catturato anche il mio interesse, in particolare per la possibilità di creare un indicatore ZigZag avanzato.

Questo articolo descrive un metodo per creare uno ZigZag avanzato utilizzando l'indicatore Inviluppo. Si presume di poter trovare una certa combinazione di parametri di input per una serie di inviluppo, per cui la maggior parte dei nodi ZigZag si trova all'interno dei confini delle bande di Envelopes (inviluppo).

 

Un metodo per creare un indicatore ZigZag avanzato

Stabiliremo un obiettivo: trovare le coordinate di due nodi: il nodo corrente e il nodo previsto (Fig. 1). Il nodo corrente è un nodo non ancora completato le cui coordinate sono ancora in fase di ricerca o regolazione. Inoltre, è sempre sulla barra corrente (zero). Pur essendo nel futuro, un nodo previsto deve mostrare il livello stimato del prossimo nodo ZigZag.

Previsione di nuovi nodi ZigZag

Fig. 1. Previsione di nuovi nodi ZigZag: il nodo corrente e il nodo successivo.

Quindi l'obiettivo è fissato e abbiamo un'idea di come utilizzare le inviluppo a media mobile come base per costruire un indicatore avanzato (Fig. 2). Cercheremo le inviluppo la cui deviazione dai nodi ZigZag è minima. Sembra abbastanza logico che le inviluppo per i picchi e gli avvallamenti ZigZag debbano essere cercati separatamente.

Indicatori ZigZag e inviluppo della media mobile

Fig. 2. Indicatori ZigZag e inviluppo a media mobile.

Per aumentare la significatività statistica della previsione, invece di utilizzare solo uno o anche 10 indicatori Inviluppo, dovremmo utilizzare un pool di 100 o più indicatori con dati di input diversi. Differiranno nel periodo di media della linea dell'indicatore principale e nel prezzo utilizzato (Alto per i picchi e Basso per i minimi). Introduciamo le seguenti notazioni e formule:

  • ZZ- l'indicatore ZigZag;
  • ENV - la linea principale dell'indicatore Inviluppo (coincide con l'indicatore iMA);
  • Inviluppo(i) - valore della riga principale dell'indicatore Inviluppo sulla i-esima barra;
  • ZZ(High) - Valore di picco ZigZag;
  • ZZ(Low) - Valore minimo ZigZag;
  • ENV(High) - valore della linea principale dell'indicatore Inviluppo corrispondente ad un picco ZigZag;
  • ENV(Low) - valore della linea principale dell'indicatore Inviluppo corrispondente ad un avvallamento ZigZag;
  • n_high - numero di picchi ZigZag;
  • n_low - numero di depressioni ZigZag.

Abbiamo due gruppi di indicatori: uno per i picchi e l'altro per i minimi (circa 100 indicatori in ciascuno). Calcoleremo la deviazione dei nodi ZigZag dalla linea principale dell'indicatore Envelopes per ciascun indicatore nel pool e troveremo la media aritmetica delle deviazioni per ciascun indicatore del pool utilizzando le formule di cui sopra. La figura seguente mostra un diagramma delle deviazioni rispetto ai nodi identificati ZZ dalla linea principale ENV per un indicatore.

Diagramma delle deviazioni dei nodi ZZ da ENV

Fig. 3. Diagramma delle deviazioni dei nodi ZZ da ENV.

La media aritmetica delle deviazioni verrà utilizzata per determinare il livello a cui deve essere spostata la linea principale dell'indicatore inviluppo per tracciare le bande delle Envelopes (inviluppo). Quindi, avremo bisogno della media aritmetica delle deviazioni dai picchi ZigZag per disegnare la linea superiore e della media aritmetica delle deviazioni dai minimi per disegnare la linea inferiore dell'indicatore delle inviluppo.

Sono le linee superiori e inferiori delle inviluppo che useremo per trovare punti caratteristici e prevedere i nodi ZigZag. Ancora una volta, siamo interessati al pool di inviluppo costituito da un insieme di indicatori Inviluppo. Per ogni indicatore viene calcolata la media aritmetica delle deviazioni dei nodi ZigZag dalla linea principale di un dato Envelopes (inviluppo). Dopo aver tracciato le linee risultanti (la linea superiore e inferiore) del pool nel grafico, saremo in grado di vedere quanto segue:

Le linee delle inviluppo sul piano

Fig. 4. Le linee di inviluppo sull'aereo.

Se assumiamo che ogni linea si trovi su un piano separato, mentre tutte insieme creano una superficie, la figura sopra mostra solo la proiezione di ciascun indicatore sul piano del grafico dei prezzi. Un'immagine 3D di queste linee sarà approssimativamente la seguente:

Le linee delle inviluppo in 3D

Fig. 5. Le linee di inviluppo in 3D.

Diamo ora una rapida lezione di geometria. Immagina che il pool di linee dell'indicatore Envelopes sia una superficie 3D. Prendi un piano perpendicolare al grafico dei prezzi e taglia la superficie in corrispondenza della barra corrente (zero).

Di conseguenza, otteniamo una sezione trasversale della superficie che rappresenta una curva (le figure sopra mostrano un caso speciale in cui la curva è una linea retta). Per fare la previsione è sufficiente avere le coordinate di ogni punto sulla curva che verranno ulteriormente utilizzate nei calcoli.

Avremo bisogno delle seguenti caratteristiche della sezione trasversale: punto massimo e minimo, nonché il baricentro della sezione trasversale (la media aritmetica di tutti i valori dei punti). I punti caratteristici ottenuti verranno proiettati sulla barra corrente (zero), con i relativi dati memorizzati nella cronologia. Questi punti caratteristici serviranno come base per i nodi ZigZag attuali e successivi.

Poiché la ricerca delle bande di Envelopes (inviluppo) viene eseguita separatamente per picchi e avvallamenti, di conseguenza dovremmo ottenere due sezioni d'urto: una per i picchi e l'altra per gli avvallamenti.

Per ottenere la previsione, utilizzeremo il punto caratteristico più vicino. Ad esempio, durante la ricerca di un picco ZigZag, prendiamo i punti caratteristici della sezione trasversale risultanti dall'intersezione della superficie delle linee superiori dell'indicatore Inviluppo con un piano di taglio. Viceversa, per trovare un avvallamento si prendono i punti caratteristici della sezione risultante dall'intersezione della superficie delle linee inferiori dell'indicatore Inviluppo con un piano di taglio.

 

Test del nuovo indicatore

Ora che abbiamo definito il metodo, creiamo l'indicatore. Per prima cosa troveremo gli ultimi nodi dell'indicatore ZigZag e li disegneremo nel grafico. A questo scopo, utilizzeremo la classe AdvancedZigZag scritta per il compito in questione:

//+------------------------------------------------------------------+
//|                                               AdvancedZigZag.mqh |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                 GetExtremums.mqh |
//+------------------------------------------------------------------+
#include <GetExtremums.mqh>   // author of the code Yurich
#property copyright "Copyright 2012, Yurich"
#property link      "https://www.mql5.com/ru/users/Yurich"
//+------------------------------------------------------------------+
//| ZigZag node structure                                            |
//+------------------------------------------------------------------+
struct MqlZigZag
  {
   double            price;   // Node coordinate
   datetime          t;       // Time
  };
//+------------------------------------------------------------------+
//| The AdvancedZigZag class                                         |
//+------------------------------------------------------------------+
class AdvancedZigZag
  {
private:
   MqlRates          rt[];
   dextremum         zz[];
   int               history;
   double            amplitude;
public:
   dextremum         zHL[];
   MqlZigZag         zzH[],zzL[];
   int               Count(const double range);
   int               Read(const int nodes);
                     AdvancedZigZag(const int bars);
                    ~AdvancedZigZag();
  };
//+------------------------------------------------------------------+
//| Class constructor                                                |
//+------------------------------------------------------------------+
AdvancedZigZag::AdvancedZigZag(const int bars)
  {
   history=bars;
   amplitude=0;
  }
//+------------------------------------------------------------------+
//| The Read method of the class                                     |
//+------------------------------------------------------------------+
int AdvancedZigZag::Read(const int nodes)
  {
   CopyRates(NULL,0,TimeCurrent(),history,rt);
   int cnt=GetExtremums(amplitude,rt,zHL,nodes);
   return(cnt);
  }
//+------------------------------------------------------------------+
//| The Count method of the class                                    |
//+------------------------------------------------------------------+
int AdvancedZigZag::Count(const double range)
  {
   amplitude=range;
   CopyRates(NULL,0,TimeCurrent(),history,rt);
   int cnt=GetExtremums(amplitude,rt,zz);
   ArrayResize(zzH,cnt);
   ArrayResize(zzL,cnt);
   int h=0;
   int l=0;
   for(int i=0; i<cnt; i++)
     {
      if(zz[i].type>0)
        {
         zzH[h]=(MqlZigZag)zz[i];
         h++;
        }
      else
        {
         zzL[l]=(MqlZigZag)zz[i];
         l++;
        }
     }
   ArrayResize(zzH,h);
   ArrayResize(zzL,l);
   return(cnt);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
AdvancedZigZag::~AdvancedZigZag()
  {
  }

Ci sono due metodi in totale:

  • Il metodo Count trova tutti i nodi ZigZag in un determinato periodo di tempo (numero di barre) e li salva in vari array, separando i picchi dai minimi. In questo modo sarà più semplice fare l'analisi e il calcolo delle inviluppo;
  • Il metodo Read trova gli ultimi nodi e li salva in un singolo array. Abbiamo bisogno di questo metodo per la visualizzazione dell'indicatore ZigZag;

La libreria GetExtremums (di Yury Kulikov) sarà necessaria anche nella ricerca dei nodi.

Mettiamo l'indicatore in esame in un Expert Advisor. Perché un Expert Advisor e non un indicatore? Questa è ovviamente una questione di gusti, ma mi sembra che sia più efficiente in questo modo. Le funzionalità grafiche di Expert Advisor sono indubbiamente più deboli, ma guadagniamo in termini di prestazioni poiché gli indicatori dello stesso simbolo operano in un unico flusso, mentre ogni EA opera nel proprio flusso separato. Diamo un'occhiata al codice:

//+------------------------------------------------------------------+
//|                                                   two_Comets.mq5 |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
#include <AdvancedZigZag.mqh>
//--- Depth of history for the indicator calculation
input int      depth_stories=5000;  // Depth stories for calculating the indicator [bars]
//--- Minimum ZigZag amplitude value
input int      amplitude=100;        // The minimum value of the amplitude of the indicator [points]
//--- Declaring the class
AdvancedZigZag Azz(depth_stories);
//---
#define NUMBER_MA   227
#define START_MA    5
//--- macros
#define SIZE(i)                     (double)i*0.3<1?1:(int)(i*0.25)
#define ObjF1                       ObjectSetString(0,name,OBJPROP_FONT,"Wingdings")
#define ObjF2                       ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER)
#define ObjF3(T)                    ObjectSetInteger(0,name,OBJPROP_TIME,T)
#define ObjF4(P)                    ObjectSetDouble(0,name,OBJPROP_PRICE,P)
#define ObjF5(size)                 ObjectSetInteger(0,name,OBJPROP_FONTSIZE,size)
#define ObjF6(code)                 ObjectSetString(0,name,OBJPROP_TEXT,CharToString(code))
#define ObjF7(clr)                  ObjectSetInteger(0,name,OBJPROP_COLOR,clr)
#define ObjF8                       ObjectSetInteger(0,name,OBJPROP_COLOR,clrMagenta)
#define ObjF9                       ObjectSetInteger(0,name,OBJPROP_WIDTH,3)
#define ObjF10                      ObjectSetInteger(0,name,OBJPROP_BACK,true) 
#define ObjFont                     ObjF1;ObjF2;
#define ObjCoordinates(T,P)         ObjF3(T);ObjF4(P);
#define ObjProperty(size,code,clr)  ObjF5(size);ObjF6(code);ObjF7(clr);
#define ObjZZ                       ObjF8;ObjF9;ObjF10;
//---
double      MA[1],sumHi[NUMBER_MA],sumLo[NUMBER_MA];
int         handle_MA_H[NUMBER_MA],handle_MA_L[NUMBER_MA];
datetime    t[1];
int         H,L;
int         t_min,t_max;
int         err=-1;
double      sumH[2],maxH[2],minH[2];
double      sumL[2],maxL[2],minL[2];
string      name;
int         count;
int         shift;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   shift=PeriodSeconds()/30;
//--- calculation of ZigZag nodes using historical data
   Azz.Count(amplitude*Point());
   H=ArraySize(Azz.zzH);
   L=ArraySize(Azz.zzL);
   if(H<30 || L<30)
     {
      Print("Not enough data to calculate ZigZag nodes: "+
            "increase the depth of history; "+
            "or decrease the amplitude value.");
      return(-1);
     }
//---
   for(int i=0; i<NUMBER_MA; i++)
     {
      handle_MA_H[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_HIGH);
      handle_MA_L[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_LOW);
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0,-1,-1);
   for(int i=0; i<NUMBER_MA; i++)
     {
      IndicatorRelease(handle_MA_H[i]);
      IndicatorRelease(handle_MA_L[i]);
     }
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+

void OnTick()
  {
//--- get the current bar's opening time value
   CopyTime(NULL,0,0,1,t);
//--- ZigZag: last 7 nodes
   count=Azz.Read(7);
   for(int i=1; i<count; i++)
     {
      name="ZZ"+(string)i;
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clrRed);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,10);
      ObjectSetInteger(0,name,OBJPROP_BACK,true);
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[i-1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[i-1].time);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,Azz.zHL[i].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,Azz.zHL[i].time);
     }
//--- check for integrity of preliminary calculations
   if(err<0)
     {
      //--- calculate the sums of deviations of the nodes from MA for ZigZag peaks
      ArrayInitialize(sumHi,0.0);
      for(int j=H-1; j>=0; j--)
        {
         for(int i=0; i<NUMBER_MA; i++)
           {
            err=CopyBuffer(handle_MA_H[i],0,Azz.zzH[j].t,1,MA);
            if(err<0) return;
            sumHi[i]+=Azz.zzH[j].price-MA[0];
           }
        }
      //--- calculate the sums of deviations of the nodes from MA for ZigZag troughs
      ArrayInitialize(sumLo,0.0);
      for(int j=L-1; j>=0; j--)
        {
         for(int i=0; i<NUMBER_MA; i++)
           {
            err=CopyBuffer(handle_MA_L[i],0,Azz.zzL[j].t,1,MA);
            if(err<0) return;
            sumLo[i]+=MA[0]-Azz.zzL[j].price;
           }
        }
     }
  }
//+------------------------------------------------------------------+

Dobbiamo chiarire alcune cose qui:

  • L'indicatore iEnvelopes viene sostituito dall'indicatore iMA. Non c'è nulla di falso o fuorviante in esso. Il fatto è che la linea principale di iEnvelopes coincide con iMA! È quindi più conveniente utilizzare l'indicatore della media mobile.
  • Usiamo due pool di medie mobili, composti da 227 linee ciascuno, per un totale di 454 indicatori iMA! È molto o poco? Fondamentalmente, è un numero grande. Ma, prima di tutto, possiamo cambiare il numero di indicatori, se necessario, e in secondo luogo, abbiamo bisogno delle statistiche. Qual è il punto nella ricerca di inviluppo per una dozzina di nodi? Ne servono almeno un centinaio.
  • I valori degli indicatori vengono caricati nel blocco OnTick() anziché OnInit(). Se il blocco di caricamento dei dati viene posizionato in OnInit(), è molto probabile che alcuni dati possano essere caricati in ritardo e gli indicatori di conseguenza non verranno calcolati in modo accurato e completo. Dopo aver ottenuto tutti i dati per i calcoli, il valore della variabile err diventerà positivo e questo blocco verrà escluso dall'operazione.

Quindi, l'indicatore risultante traccia gli ultimi sette nodi ZigZag e calcola le coordinate di tutti gli altri nodi in una data cronologia (Fig. 6). Il calcolo viene eseguito solo una volta e utilizziamo ulteriormente i dati calcolati. Puoi ovviamente implementarlo in modo tale da consentire un aggiornamento regolare dei dati ma in questo articolo lo terremo per un solo passaggio.

L'indicatore ZigZag (7 nodi)

Fig. 6. L'indicatore ZigZag (7 nodi).

Tracciamo inoltre le sezioni trasversali delle superfici degli indicatori delle inviluppo. Per fare ciò, aggiungeremo quanto segue al metodo OnTick():

//--- PEAKS
   sumH[0]=0.0;
   maxH[0]=0.0;
   minH[0]=0.0;
   for(int i=0; i<NUMBER_MA; i++)
     {
      CopyBuffer(handle_MA_H[i],0,t[0],1,MA);
      double envelope=MA[0]+sumHi[i]/H;
      if(i==0 || envelope<minH[0])
        {
         minH[0]=envelope;
         t_min=SIZE(i);
        }
      if(envelope>maxH[0])
        {
         maxH[0]=envelope;
         t_max=SIZE(i);
        }
      sumH[0]+=envelope;
      name="H"+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjFont
      ObjCoordinates(t[0]-(NUMBER_MA-i*2)*shift,envelope)
      ObjProperty(SIZE(i),158,clrBlue)
     }
//--- TROUGHS
   sumL[0]=0.0;
   maxL[0]=0.0;
   minL[0]=0.0;
   for(int i=0; i<NUMBER_MA; i++)
     {
      CopyBuffer(handle_MA_L[i],0,t[0],1,MA);
      double envelope=MA[0]-sumLo[i]/L;
      if(i==0 || envelope<minL[0])
        {
         minL[0]=envelope;
         t_min=SIZE(i);
        }
      if(envelope>maxL[0])
        {
         maxL[0]=envelope;
         t_max=SIZE(i);
        }
      sumL[0]+=envelope;
      name="L"+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjFont
      ObjCoordinates(t[0]+(NUMBER_MA-i*2)*shift,envelope)
      ObjProperty(SIZE(i),158,clrGold)
     }
Una nota per i programmatori alle prime armi: gli operatori alla fine del blocco Peaks e Troughs non hanno ';' alla fine della stringa. Non è un errore o un refuso. Quelle sono macro (vedi la sezione dei dati dove sono dichiarate) - sono molto utili! Ti consiglio di usarli nei tuoi programmi.

Per discernere i punti di sezione della superficie formata dalle linee delle inviluppo, i punti variano di dimensione: maggiore è il periodo medio della linea principale degli indicatori delle inviluppo, più grandi sono i punti (Fig. 7). Inoltre, le sezioni trasversali vengono ruotate attorno ad un asse verticale passante per la barra corrente (zero) in diverse direzioni: i picchi sono a 90 gradi a destra e gli avvallamenti sono a 90 gradi a sinistra.

Ora possono essere visti nel piano del grafico dei prezzi. Inizialmente giacevano sul piano di taglio (Fig. 5) e non potevano essere osservati. Potevamo solo immaginarli a noi stessi, senza avere alcuna idea della loro forma. Le linee di sezione si sono rivelate di una forma molto particolare. Questo viene fatto anche per comodità di analisi grafica. Visivamente le sezioni trasversali assomigliano a due comete volanti:

Sezione trasversale del pool di indicatori Inviluppo

Fig. 7. Sezione trasversale del pool di indicatori Inviluppo.

Procediamo al calcolo delle caratteristiche della sezione d'urto: la massima e la minima, nonché il baricentro (media aritmetica). I valori risultanti verranno visualizzati come punti sulla barra corrente, con la dimensione in punti corrispondente alla dimensione della relativa caratteristica. Inoltre, li salveremo nella cronologia per ulteriori analisi. Quindi, aggiungeremo quanto segue al codice esistente:

//--- PEAKS

...

//--- midi
   string str=(string)t[0];
   name="Hmidi"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],sumH[0]/NUMBER_MA)
   ObjProperty(10,119,clrBlue)
//--- max
   name="Hmax"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],maxH[0])
   ObjProperty(t_max,158,clrBlue)
//--- min
   name="Hmin"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],minH[0])
   ObjProperty(t_min,158,clrBlue)

...

//--- TROUGHS

...

//--- midi
   name="Lmidi"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],sumL[0]/NUMBER_MA)
   ObjProperty(10,119,clrGold)
//--- max
   name="Lmax"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],maxL[0])
   ObjProperty(t_max,158,clrGold)
//--- min
   name="Lmin"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],minL[0])
   ObjProperty(t_min,158,clrGold)

Ora vediamo come appare quando viene rappresentato graficamente:

Caratteristiche della sezione

Fig. 8. Caratteristiche della sezione trasversale: il massimo e il minimo, nonché il baricentro tracciato separatamente per picchi e avvallamenti.

Abbiamo solo bisogno di aggiungere l'ultimo tocco finale trovando e tracciando i nodi ZigZag avanzati. Miglioriamo il codice aggiungendo quanto segue:

//--- ZigZag: advanced nodes
   if(Azz.zHL[0].type>0) // peak
     {
      ObjectDelete(0,"MIN");
      ObjectDelete(0,"MINfuture");
      name="MAX";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[1].time);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]);
      double price=minH[0];
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
      if(Azz.zHL[0].value>minH[0])
        {
         price=sumH[0]/NUMBER_MA;
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      if(Azz.zHL[0].value>sumH[0]/NUMBER_MA)
        {
         price=maxH[0];
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      //--- into the future
      name="MAXfuture";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,price);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,t[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,maxL[0]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]+NUMBER_MA*shift);
      if(price<maxL[0])
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,sumL[0]/NUMBER_MA);
      if(price<sumL[0]/NUMBER_MA)
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,minL[0]);
     }
   if(Azz.zHL[0].type<0) // trough
     {
      ObjectDelete(0,"MAX");
      ObjectDelete(0,"MAXfuture");
      name="MIN";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[1].time);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]);
      double price=maxL[0];
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
      if(Azz.zHL[0].value<maxL[0])
        {
         price=sumL[0]/NUMBER_MA;
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      if(Azz.zHL[0].value<sumL[0]/NUMBER_MA)
        {
         price=minL[0];
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      //--- into the future
      name="MINfuture";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,price);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,t[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,minH[0]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]+NUMBER_MA*shift);
      if(price>minH[0])
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,sumH[0]/NUMBER_MA);
      if(price>sumH[0]/NUMBER_MA)
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,maxH[0]);
     }

Quindi, abbiamo il nuovo indicatore ZigZag avanzato che prevede la posizione di nuovi nodi (Fig. 9). I nodi stessi si trovano nei punti caratteristici della sezione trasversale: il massimo, il minimo e il baricentro. Il titolo provvisorio dell'indicatore è "Due comete".

Va notato che il tempo di completamento del nodo successivo, che è futuro, è rimasto sconosciuto. Fondamentalmente, possiamo prevedere solo una coordinata del nodo: il prezzo.

Nodi ZigZag previsti

Fig. 9. L'indicatore ZigZag avanzato prevede i nodi: quello attuale e quello successivo.

 

Analisi dei risultati e raccomandazioni per gli sviluppatori

Le osservazioni degli indicatori hanno mostrato che:

  1. Le deviazioni delle coordinate del nodo ZigZag dai nodi previsti sono all'interno della regione di tolleranza. Il vasto numero di nodi giace nell'ombra della corrispondente sezione trasversale. Questa è certamente solo una valutazione qualitativa. Risultati più accurati seguiranno nei prossimi articoli.
  2. Le sezioni trasversali delle linee delle inviluppo dimostrano il comportamento del mercato e l'andamento dei prezzi previsto! Prestare attenzione alla coda della cometa che è composta da punti con il periodo medio più piccolo (il più piccolo per dimensione). È diretto nella direzione del prezzo. La coda della cometa si piega nei modi più intricati e più è girata nella direzione opposta, maggiori sono le possibilità di vedere il cambiamento di tendenza. Basta guardare il comportamento dell'indicatore su diversi intervalli di tempo con diverse ampiezze. Questo è estremamente interessante!
  3. I punti caratteristici delle sezioni trasversali formano linee che possono presentare una forte resistenza al movimento dei prezzi. Pertanto possono essere considerati come linee di supporto e resistenza.
  4. Quando i punti del baricentro della sezione lo superano (come i picchi in Fig. 9), questo è indice della presenza della tendenza al rialzo.

Quindi quello che abbiamo ottenuto è un indicatore molto interessante che può essere provato in una strategia di trading!

 

Conclusione

  • Il metodo per prevedere i nodi dell'indicatore ZigZag esaminato nell'articolo ci ha permesso di creare il nuovo indicatore - "Due comete".
  • Lo ZigZag avanzato mostra le possibili coordinate di nuovi nodi, anche se questa è solo una previsione.
  • L'algoritmo considerato nell'articolo può essere utilizzato per tracciare indicatori avanzati simili, non necessariamente indicatori ZigZag, ad esempio frattali o indicatori semaforici.
  • I programmatori MQL5 alle prime armi possono trovare interessante vedere come possono creare macro nei loro programmi per ridurre la quantità di codice ripetuto.

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

File allegati |
advancedzigzag.mqh (3.54 KB)
getextremums.mqh (5.24 KB)
two_comets.mq5 (10.16 KB)
Manuale MQL5: Sviluppo di un framework per un sistema di trading basato sulla strategia a triplo schermo Manuale MQL5: Sviluppo di un framework per un sistema di trading basato sulla strategia a triplo schermo
In questo articolo, svilupperemo un framework per un sistema di trading basato sulla strategia Triple Screen in MQL5. L'Expert Advisor non sarà sviluppato da zero. Invece, modificheremo semplicemente il programma dal precedente articolo "Manuale MQL5: Utilizzo di indicatori per impostare le condizioni di trading in Expert Advisors" che già sostanzialmente serve al nostro scopo. Quindi l'articolo dimostrerà anche come è possibile modificare facilmente i modelli di programmi già pronti.
Manuale MQL5: Utilizzo degli indicatori per impostare le condizioni di trading in Expert Advisor Manuale MQL5: Utilizzo degli indicatori per impostare le condizioni di trading in Expert Advisor
In questo articolo, continueremo a modificare l'Expert Advisor su cui abbiamo lavorato in tutti gli articoli precedenti della serie Manuale MQL5. Questa volta, l'Expert Advisor sarà arricchito con indicatori i cui valori saranno utilizzati per verificare le condizioni di apertura della posizione. Per ravvivarlo, creeremo un elenco a discesa nei parametri esterni per poter selezionare uno su tre indicatori di trading.
Manuale MQL5: Expert Advisor multivaluta: approccio semplice, accurato e rapido Manuale MQL5: Expert Advisor multivaluta: approccio semplice, accurato e rapido
Questo articolo descriverà l'implementazione di un approccio semplice, adatto a un Expert Advisor multivaluta. Ciò significa che sarai in grado di impostare l'Expert Advisor per testare/tradare in condizioni identiche ma con parametri diversi per ogni simbolo. Ad esempio creeremo un pattern per due simboli ma in modo tale da poter aggiungere ulteriori simboli, se necessario, apportando piccole modifiche al codice.
Manuale MQL5: La cronologia delle offerte e la libreria di funzioni per ottenere proprietà di posizione Manuale MQL5: La cronologia delle offerte e la libreria di funzioni per ottenere proprietà di posizione
È il momento di riassumere brevemente le informazioni fornite nei precedenti articoli sulle proprietà della posizione. In questo articolo creeremo alcune funzioni aggiuntive per ottenere le proprietà che possono essere ottenute solo dopo aver effettuato l'accesso alla cronologia delle offerte. Acquisiremo anche familiarità con le strutture dati che ci consentiranno di accedere alle proprietà di posizione e simbolo in modo più comodo.