English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Calcolo delle caratteristiche integrali delle emissioni degli indicatori

Calcolo delle caratteristiche integrali delle emissioni degli indicatori

MetaTrader 5Esempi | 11 gennaio 2022, 16:35
162 0
Sergey Pavlov
Sergey Pavlov

Introduzione

Le emissioni degli indicatori rappresentano una direzione nuova e piuttosto promettente nello studio delle serie temporali. Si caratterizza per il fatto che l'analisi non è focalizzata sugli indicatori in quanto tali ma sulle loro emissioni nel futuro o nel passato in base alle quali possiamo effettivamente fare una previsione del contesto di mercato:

  • livelli di supporto e resistenza in futuro;
  • direzione del trend (movimento dei prezzi);
  • forza di movimento accumulata nel passato.

Il mio precedente articolo intitolato "Disegno delle emissioni dell'indicatore in MQL5" trattava dell'algoritmo di disegno delle emissioni e ne specificava le caratteristiche chiave. Lascia che ti rinfreschi la memoria:

L'emissione è un insieme di punti situati alle intersezioni di linee peculiari degli indicatori in esame.

I punti di emissione, a loro volta, presentano alcune peculiarità:

  • I punti di emissione dello stesso tipo tendono a raggrupparsi.
  • I cluster di punti densi possono attrarre o, al contrario, respingere il prezzo.

Galleria emissioni:

Emissione di DCMV Emissione di iMA e iEnvelopes
Emissione di DCMV Emissione di iMA e iEnvelopes

Fig. 1. Esempi di grafici di emissione degli indicatori. A sinistra: emissione dell'indicatore DCMV. A destra: emissione degli indicatori iMA e indicatori iEnvelopes.

Nell'illustrazione del calcolo delle caratteristiche integrali delle emissioni, prenderemo gli inviluppi di media mobile (Envelopes) e le medie mobili (Moving Average) stessi con i seguenti parametri di input:

//--- external variable for storing averaging period of the iEnvelopes indicator
input int   ma_period=140; // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double      ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing iMA indicator periods
int         MA[]={4,7,11,19,31,51,85};

Quindi, cercheremo intersezioni di linee peculiari degli indicatori selezionati. Il numero di linee e le loro caratteristiche (periodi medi e deviazioni) sono scelti a caso. L'emissione può infatti essere tracciata utilizzando qualsiasi insieme di parametri per questi indicatori (purché si intersechino nello spazio).

Ora che abbiamo scelto gli indicatori, procediamo alla creazione di un Expert Advisor che fungerà da programma di base per l'analisi delle emissioni. Avremo bisogno di ottenere i dati calcolati dagli indicatori tecnici iMA e iEnvelopes. Propongo di utilizzare un metodo descritto nella Guida all'uso degli indicatori tecnici negli Expert Advisor.

Per tracciare le linee di cui dobbiamo trovare le intersezioni, abbiamo solo bisogno di impostare due punti per ciascuna delle linee. Pertanto, è sufficiente ottenere i valori dell'indicatore solo per due barre (es. corrente e precedente). Il prezzo sulla barra precedente è statico, mentre il prezzo sulla barra attuale è dinamico e quindi nuovi punti continuano a essere generati ad ogni nuovo tick. Ecco il codice:

//+------------------------------------------------------------------+
//|                                      emission_of_MA_envelope.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 <GetIndicatorBuffers.mqh>
#include <Emission.mqh>
//--- external variable for storing averaging period of the iEnvelopes indicator
input int   ma_period=140;      // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double      ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing the iMA indicator periods
int         MA[]={4,7,11,19,31,51,85};
//--- array for storing pointers to the iMA and iEnvelopes indicators
int         handle_MA[];
int         handle_Envelopes[];
//--- market data
datetime    T[],prevTimeBar=0;
double      H[],L[];
#define     HL(a, b) (a+b)/2
//--- class instances
CEmission      EnvMa(0,300);
PointEmission  pEmission;
//--- drawing styles for points of emission
#define     COLOR_UPPER  C'51,255,255'
#define     COLOR_LOWER  C'0,51,255'
#define     COLOR_MA     C'255,51,255'
color       colorPoint[]={COLOR_UPPER,COLOR_LOWER,COLOR_MA};
CodeColor   styleUpper={158,COLOR_UPPER,SMALL};
CodeColor   styleLower={158,COLOR_LOWER,SMALL};
CodeColor   styleMA={158,COLOR_MA,SMALL};
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArraySetAsSeries(T,true);
   ArraySetAsSeries(H,true);
   ArraySetAsSeries(L,true);
//---
   int size=ArraySize(MA);
   ArrayResize(handle_MA,size);
//--- create a pointer to the object - the iMA indicator
   for(int i=0; i<size; i++)
     {
      handle_MA[i]=iMA(NULL,0,MA[i],0,MODE_SMA,PRICE_MEDIAN);
      //--- if an error occurs when creating the object, print the message
      if(handle_MA[i]<0)
        {
         Print("The iMA object[",MA[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   size=ArraySize(ENV);
   ArrayResize(handle_Envelopes,size);
//--- create a pointer to the object - the iEnvelopes indicator
   for(int i=0; i<size; i++)
     {
      handle_Envelopes[i]=iEnvelopes(NULL,0,ma_period,0,MODE_SMA,PRICE_MEDIAN,ENV[i]);
      //--- if an error occurs when creating the object, print the message
      if(handle_Envelopes[i]<0)
        {
         Print("The iEnvelopes object[",ENV[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- market data
   CopyTime(NULL,0,0,2,T);
   CopyHigh(NULL,0,0,2,H);
   CopyLow(NULL,0,0,2,L);
//--- fill the declared arrays with current values from all indicator buffers
   string name;
   uint GTC=GetTickCount();
//---- indicator buffers
   double   ibMA[],ibMA1[];      // arrays for the iMA indicator
   double   ibEnvelopesUpper[];  // array for the iEnvelopes indicator (UPPER_LINE)
   double   ibEnvelopesLower[];  // array for the iEnvelopes indicator (LOWER_LINE)
   for(int i=ArraySize(handle_MA)-1; i>=0; i--)
     {
      if(!CopyBufferAsSeries(handle_MA[i],0,0,2,true,ibMA))
         return;
      //---
      for(int j=ArraySize(handle_Envelopes)-1; j>=0; j--)
        {
         if(!GetEnvelopesBuffers(handle_Envelopes[j],0,2,ibEnvelopesUpper,ibEnvelopesLower,true))
            return;
         //--- find the intersection point of the iEnvelopes(UPPER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesUpper[1],ibEnvelopesUpper[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, draw it in the chart
           {
            name="iEnvelopes(UPPER_LINE)"+(string)j+"=iMA"+(string)i+(string)GTC;
            EnvMa.CreatePoint(name,pEmission,styleUpper);
           }
         //--- find the intersection point of the iEnvelopes(LOWER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesLower[1],ibEnvelopesLower[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, draw it in the chart
           {
            name="iEnvelopes(LOWER_LINE)"+(string)j+"=iMA"+(string)i+(string)GTC;
            EnvMa.CreatePoint(name,pEmission,styleLower);
           }
        }
      //---
      for(int j=ArraySize(handle_MA)-1; j>=0; j--)
        {
         if(i!=j)
           {
            if(!CopyBufferAsSeries(handle_MA[j],0,0,2,true,ibMA1))
               return;
            //--- find the intersection point of the iMA and iMA indicators
            pEmission=EnvMa.CalcPoint(ibMA1[1],ibMA1[0],ibMA[1],ibMA[0],T[0]);
            if(pEmission.real) // if the intersection point is found, draw it in the chart
              {
               name="iMA"+(string)j+"=iMA"+(string)i+(string)GTC;
               EnvMa.CreatePoint(name,pEmission,styleMA);
              }
           }
        }
     }
//--- deletion of the graphical objects of emission not to stuff the chart
   if(T[0]>prevTimeBar) // delete once per bar
     {
      int  total=ObjectsTotal(0,0,-1);
      prevTimeBar=T[0];
      for(int obj=total-1;obj>=0;obj--)
        {
         string obj_name=ObjectName(0,obj,0,OBJ_TEXT);
         datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
         if(obj_time<T[0])
            ObjectDelete(0,obj_name);
        }
      Comment("Emission © DC2008       Objects = ",total);
     }
//---
  }

Non mi soffermerò su ogni dettaglio di questo Expert Advisor. La cosa principale da notare qui è che per tracciare l'emissione, usiamo un'istanza di classe CEmission responsabile del calcolo e della visualizzazione dei punti di intersezione di due linee qualsiasi.

//+------------------------------------------------------------------+
//|                                                     Emission.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"
#define  BIG   7    // point size
#define  SMALL 3    // point size
//+------------------------------------------------------------------+
//| pMABB structure                                                  |
//+------------------------------------------------------------------+
struct PointEmission
  {
   double            x;       // X-coordinate of the time point
   double            y;       // Y-coordinate of the price point
   datetime          t;       // t-coordinate of the point's time
   bool              real;    // whether the point exists
  };
//+------------------------------------------------------------------+
//| CodeColor structure                                              |
//+------------------------------------------------------------------+
struct CodeColor
  {
   long              Code;    // point symbol code 
   color             Color;   // point color
   int               Width;   // point size
  };
//+------------------------------------------------------------------+
//| Base class for emissions                                         |
//+------------------------------------------------------------------+
class CEmission
  {
private:
   int               sec;
   int               lim_Left;   // limiting range of visibility in bars
   int               lim_Right;  // limiting range of visibility in bars

public:
   PointEmission     CalcPoint(double   y1,  // Y-coordinate of straight line 1 on bar [1]
                               double   y0,  // Y-coordinate of straight line 1 on bar [0]
                               double   yy1, // Y-coordinate of straight line 2 on bar [1] 
                               double   yy0, // Y-coordinate of straight line 2 on bar [0]
                               datetime t0   // t-coordinate of the current bar Time[0]
                               );
   bool              CreatePoint(string name,            // point name
                                 PointEmission &point,   // coordinates of the point
                                 CodeColor &style);      // point drawing style
                                 CEmission(int limitLeft,int limitRight);
                    ~CEmission();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CEmission::CEmission(int limitLeft,int limitRight)
  {
   sec=PeriodSeconds();
   lim_Left=limitLeft;
   lim_Right=limitRight;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CEmission::~CEmission()
  {
  }
//+------------------------------------------------------------------+
//| The CalcPoint method of the CEmission class                      |
//+------------------------------------------------------------------+
PointEmission CEmission::CalcPoint(double   y1, // Y-coordinate of straight line 1 on bar [1]
                                   double   y0, // Y-coordinate of straight line 1 on bar [0]
                                   double   yy1,// Y-coordinate of straight line 2 on bar [1]
                                   double   yy0,// Y-coordinate of straight line 2 on bar [0]
                                   datetime t0  // t-coordinate of the current bar Time[0]
                                   )
  {
   PointEmission point={NULL,NULL,NULL,false};
   double y0y1=y0-y1;
   double y1yy1=y1-yy1;
   double yy0yy1=yy0-yy1;
   double del0=yy0yy1-y0y1;
   if(MathAbs(del0)>0)
     {
      point.x=y1yy1/del0;
      if(point.x<lim_Left || point.x>lim_Right) return(point);
      point.y=y1+y0y1*y1yy1/del0;
      if(point.y<0) return(point);
      point.t=t0+(int)(point.x*sec);
      point.real=true;
      return(point);
     }
   return(point);
  }
//+------------------------------------------------------------------+
//| The CreatePoint method of the CEmission class                    |
//+------------------------------------------------------------------+
bool CEmission::CreatePoint(string name,            // point name
                            PointEmission &point,  // coordinates of the point
                            CodeColor &style)      // point drawing style
  {
   if(ObjectCreate(0,name,OBJ_TEXT,0,0,0))
     {
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,style.Width);
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString((uchar)style.Code));
      ObjectSetDouble(0,name,OBJPROP_PRICE,point.y);
      ObjectSetInteger(0,name,OBJPROP_TIME,point.t);
      ObjectSetInteger(0,name,OBJPROP_COLOR,style.Color);
      return(true);
     }
   return(false);
  }

Va notato che i punti di emissione sono rappresentati mediante oggetti grafici come Testo. Prima di tutto, deriva dal fatto che le ancore degli oggetti dovrebbero essere allineate al centro del simbolo. In secondo luogo, è possibile variare le dimensioni dell'oggetto in un'ampia gamma. Queste proprietà puntuali offrono un grande potenziale per ottenere emissioni complesse.

Fig. 2. Emissione originale degli indicatori iMA e iEnvelopes

Fig. 2. Emissione originale degli indicatori iMA e iEnvelopes

 

Caratteristiche Integrali delle Emissioni

Quindi, dopo aver posizionato l'Expert Advisor proposto sul grafico, abbiamo ottenuto molti punti in diversi colori (vedi Fig. 2):

  • Aqua - intersezioni di iMA e iEnvelopes, buffer UPPER_LINE.
  • Blu - intersezioni di iMA e iEnvelopes, buffer LOWER_LINE.
  • Magenta - intersezioni di iMA e iMA.

Questo caos non può essere utilizzato nel trading automatico. Abbiamo bisogno di segnali, livelli e altre caratteristiche quantitative del mercato, mentre qui otteniamo solo immagini visive per la meditazione e la chiromanzia e nessun numero.

Le caratteristiche integrali delle emissioni servono a generalizzare i dati ottenuti come risultato delle emissioni degli indicatori. 

La necessità di caratteristiche integrali delle emissioni è anche guidata dal fatto che offrono opportunità per ricerche di mercato utilizzando nuovi tipi di indicatori: canali integrali, linee, livelli, segnali, ecc. Per determinare i valori di emissione più tipici, inizieremo in piccolo e calcoleremo il prezzo medio per ogni tipo di punto per tracciare ulteriormente linee orizzontali attraverso di essi come mostrato di seguito:

Fig. 3. Linee orizzontali del prezzo medio per ogni tipo di punto

Fig. 3. Linee orizzontali del prezzo medio per ogni tipo di punto

A tal fine, aggiungeremo alcuni blocchi di codice aggiuntivi al codice esistente. Alla sezione dati:

//--- arrays for calculation and display of integral characteristics of emissions
#define     NUMBER_TYPES_POINT   3
double      sum[NUMBER_TYPES_POINT],sumprev[NUMBER_TYPES_POINT];
datetime    sum_time[NUMBER_TYPES_POINT];
int         n[NUMBER_TYPES_POINT],W[NUMBER_TYPES_POINT];
color       colorLine[]={clrAqua,clrBlue,clrMagenta};

Al modulo OnTick():

//--- calculation of integral characteristics of emissions
   ArrayInitialize(n,0);
   ArrayInitialize(sum,0.0);
   ArrayInitialize(sum_time,0.0);
   for(int obj=total-1;obj>=0;obj--)
     {
      string   obj_name=ObjectName(0,obj,0,OBJ_TEXT);
      datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
      if(obj_time>T[0])
        {
         color    obj_color=(color)ObjectGetInteger(0,obj_name,OBJPROP_COLOR);
         double   obj_price=ObjectGetDouble(0,obj_name,OBJPROP_PRICE);
         for(int i=ArraySize(n)-1; i>=0; i--)
            if(obj_color==colorPoint[i])
              {
               n[i]++;
               sum[i]+=obj_price;
               sum_time[i]+=obj_time;
              }
        }
     }
//--- displaying integral characteristics of emissions
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      if(n[i]>0)
        {
         name="H.line."+(string)i;
         ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
        }
     }

Andiamo avanti. Calcoliamo ora il valore del tempo medio per ogni set di punti e segniamolo sulla riga corrispondente del prezzo medio (vedi Fig. 4). Abbiamo così ottenuto le prime caratteristiche quantitative di emissioni mai statiche, sempre in movimento nello spazio.

Il grafico mostra solo le loro posizioni momentanee. Dobbiamo in qualche modo mantenerli fissi nella storia per poterli studiare in seguito. Finora non è ancora chiaro come ciò possa essere fatto e dobbiamo dargli un'attenta considerazione... Nel frattempo, apporteremo ulteriori miglioramenti e visualizzeremo il numero di punti coinvolti nel calcolo accanto ai marker nel grafico. Questi sono una sorta di pesi delle caratteristiche ottenute che saranno utili anche in ulteriori analisi.

Fig. 4. Indicatori nei punti di intersezione del prezzo medio e del tempo medio

Fig. 4. Indicatori nei punti di intersezione del prezzo medio e del tempo medio

Tuttavia, per comodità dell'analisi, useremo i loro rapporti percentuali. Poiché i principali punti di emissione sono quelli risultanti dalle intersezioni degli indicatori iMA e iEnvelopes, considereremo la loro somma pari al 100%. Vediamo cosa abbiamo adesso:

Fig. 5. Rapporto percentuale per ogni tipo di punto di emissione

Fig. 5. Rapporto percentuale per ogni tipo di punto di emissione

Se sommiamo i tre valori, daranno più del 100% in totale. Il valore di 34,4 visualizzato in magenta è proprietà dei punti di intersezione di iMA e iMA in un determinato momento, ovvero l'indicatore si è incrociato, ma con dati di input diversi. In questo caso si tratta di un valore di riferimento e si potrebbe pensare in seguito al modo in cui può essere utilizzato nell'analisi di mercato.

Tuttavia, un altro problema sorge quando otteniamo rapporti percentuali sul numero di punti: come possiamo fissare anche i valori percentuali delle caratteristiche di emissione nella storia, tanto più che anch'essi variano?!

 

Analisi grafica

Sebbene ora abbiamo le caratteristiche integrali delle emissioni, non siamo ancora abbastanza vicini all'analisi e allo sviluppo di una strategia commerciale basata sui dati ottenuti. Tuttavia, un lettore attento deve aver già individuato una soluzione a questo problema (vedi Fig. 1). La soluzione è la seguente: Propongo di disegnare curve integrali utilizzando spessori diversi che sarebbero proporzionali al rapporto percentuale dei principali punti di emissione.

La porzione corrente della curva verrà tracciata lungo la linea del prezzo medio tra la barra attuale e quella precedente, tenendo presente che queste coordinate sono di fatto prese dal futuro. È una sorta di principale canale integrale di emissioni di indicatori. So che suona davvero molto confuso... E devi pensare se dovresti continuare a leggere. Ma spero che questo diventi sempre più interessante man mano che procediamo.

Fig. 6. Canale integrale delle emissioni degli indicatori

Fig. 6. Canale integrale delle emissioni degli indicatori

Quindi sembra che abbiamo trovato un uso per l'emissione "iMA & iMA" (visualizzata in magenta nel grafico). E abbiamo ottenuto un nuovo indicatore: la media mobile integrata.

Ora torniamo al codice dell'Expert Advisor per vedere quali modifiche sono avvenute nel modulo OnTick():

//--- displaying integral characteristics of emissions
   ArrayInitialize(W,10);
   W[ArrayMaximum(n)]=20;
   W[ArrayMinimum(n)]=3;
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      if(n[i]>0)
        {
         //--- horizontal lines of mean prices
         name="H.line."+(string)i;
         ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
         //--- markers
         name="P."+(string)i;
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,17);
         ObjectSetString(0,name,OBJPROP_TEXT,CharToString(163));
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
         ObjectSetInteger(0,name,OBJPROP_TIME,sum_time[i]/n[i]);
         //--- integral curves
         name="T"+(string)i+".line"+(string)T[1];
         ObjectCreate(0,name,OBJ_TREND,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,W[i]);
         if(sumprev[i]>0)
           {
            ObjectSetDouble(0,name,OBJPROP_PRICE,0,sumprev[i]);
            ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
            ObjectSetDouble(0,name,OBJPROP_PRICE,1,(sum[i]/n[i]));
            ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
           }
         //--- numerical values of integral characteristics
         name="Text"+(string)i+".control";
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,30);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         string str=DoubleToString((double)n[i]/(double)(n[0]+n[1])*100,1);
         ObjectSetString(0,name,OBJPROP_TEXT,str);
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,(sum[i]/n[i]));
         ObjectSetInteger(0,name,OBJPROP_TIME,0,sum_time[i]/n[i]);
        }
     }

Continuiamo la nostra analisi grafica. Ma manca qualcosa... Sembra che abbiamo perso un'altra importante caratteristica di emissione. Le curve integrali sono state tracciate solo sulla base dei prezzi medi. Tuttavia dobbiamo considerare la coordinata del tempo medio. Dai un'occhiata alla figura sottostante e presta particolare attenzione ai limiti del canale:

  • La linea dell'acqua è il limite superiore del canale.
  • La linea blu è il limite inferiore del canale.

Dobbiamo identificare l'indicatore più vicino nel tempo alla barra zero.

Limite superiore iniziale del canale
Limite inferiore iniziale del canale

Fig. 7. Caratteristiche integrali costanti nel tempo. Sinistra: limite superiore iniziale del canale. A destra: limite inferiore iniziale del canale.

Questo problema può essere risolto come segue: aggiungiamo la linea del prezzo (PRICE_MEDIAN) al grafico dei prezzi e facciamo cambiare colore alla linea a seconda del colore del marker (acqua o blu) che è più vicino all'ultima barra (vedi Fig. 7). Inoltre, inseriamo il seguente blocco di codice nel codice esistente:

//---
   if(n[ArrayMinimum(n)]>0)
     {
      datetime d[2];
      for(int j=0;j<2;j++)
        {
         d[j]=sum_time[j]/n[j];
        }
      int i=ArrayMinimum(d);

      name="Price.line"+(string)T[1];
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,8);
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,HL(H[1],L[1]));
      ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,HL(H[0],L[0]));
      ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine1[i]);
     }
//---

Ora preparati per il passaggio successivo. E se provassimo a tracciare le emissioni in base alle caratteristiche integrali delle emissioni originali, tipo delle emissioni di secondo ordine? Dopotutto, anche quelle linee si intersecano tra loro e dovrebbero, di conseguenza, avere punti di emissione. Vediamo cosa può venirne fuori. Migliora il blocco di codice precedente aggiungendo le seguenti righe di codice:

      //--- emissions of integral characteristics of the original emissions
      pEmission=EnvMa.CalcPoint(sumprev[0],sum[0]/n[0],sumprev[2],sum[2]/n[2],T[0]);
      if(pEmission.real) // if the intersection point is found, draw it in the chart
        {
         name="test/up"+(string)GTC;
         EnvMa.CreatePoint(name,pEmission,styleUpper2);
        }
      pEmission=EnvMa.CalcPoint(sumprev[1],sum[1]/n[1],sumprev[2],sum[2]/n[2],T[0]);
      if(pEmission.real) // if the intersection point is found, draw it in the chart
        {
         name="test/dn"+(string)GTC;
         EnvMa.CreatePoint(name,pEmission,styleLower2);
        }

E inserisci le seguenti righe nella sezione dati:

#define     COLOR_2_UPPER  C'102,255,255'
#define     COLOR_2_LOWER  C'51,102,255'
CodeColor   styleUpper2={178,COLOR_2_UPPER,BIG};
CodeColor   styleLower2={178,COLOR_2_LOWER,BIG};

Puoi controllare i risultati nella figura sottostante. Possiamo vedere nuovi punti che per ora non suggeriscono nulla.

Fig. 8. Emissioni di linee integrali

Fig. 8. Emissioni di linee integrali

Le caratteristiche integrali possono ovviamente essere calcolate anche per nuovi punti (vedi Fig. 9) con le loro emissioni riportate nel grafico e così via fino a quando non diventa irrealizzabile!

Emissione Emissione
Emissione Emissione

Fig. 9. Caratteristiche integrali delle emissioni

Quindi abbiamo tracciato tutto ciò di cui avevamo bisogno e ottenuto le caratteristiche integrali delle emissioni. Possiamo ora procedere alla loro analisi e allo sviluppo di una strategia di trading. Ma sembra ancora impossibile! Cosa ci sta bloccando adesso?

 

Serie temporale delle emissioni

L'analisi grafica ci consente di studiare le caratteristiche integrali delle emissioni, ma è troppo dispendiosa in termini di risorse. Se proviamo a eseguire il codice proposto nella modalità visiva del tester di strategia, la velocità del test scenderà presto a zero! Ciò è dovuto al gran numero di oggetti grafici nel grafico.

Quindi si vorrebbe naturalmente sbarazzarsi di tutta quell'abbondanza di punti e lasciare solo le curve integrali. Per risolvere questo problema, utilizzeremo array speciali (buffer).

Le serie temporali delle emissioni sono array appositamente organizzati in cui vengono accumulate le informazioni sulle emissioni.

Differiscono dalle serie temporali standard in quanto i dati che contengono non sono sequenziati in base all'ora, anche se l'ora è il campo chiave.

Serie temporali di emissioni

Fig. 10. Serie temporale delle caratteristiche di emissione

Questi array sono disposti in modo tale che i nuovi elementi vengano memorizzati in celle vuote o in celle piene di vecchi valori. A questo scopo utilizzeremo la classe CTimeEmission. Ecco come è implementato nel codice:

//+------------------------------------------------------------------+
//|                                                 TimeEmission.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"
//---
#include <Emission.mqh>
#define ARRMAX       64
#define ARRDELTA     8
//+------------------------------------------------------------------+
//| pIntegral structure                                              |
//+------------------------------------------------------------------+
struct pIntegral
  {
   double            y;       // Y-coordinate of the price point (mean price of the points with the same time)
   datetime          t;       // t-coordinate of the point's time
   int               n;       // n-number of points with the same time
  };
//+------------------------------------------------------------------+
//| Base class for time series of emissions                          |
//+------------------------------------------------------------------+
class CTimeEmission
  {
private:
   pIntegral         time_series_Emission[]; // time series of emission
   int               size_ts; // number of elements in time series 
   datetime           t[1];
public:
   //--- method of writing new elements to time series of emission
   void              Write(PointEmission &point);
   //--- method of reading integral characteristics of emissions
   pIntegral         Read();
                     CTimeEmission();
                    ~CTimeEmission();
  };

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTimeEmission::CTimeEmission()
  {
   ArrayResize(time_series_Emission,ARRMAX,ARRMAX);
   size_ts=ArraySize(time_series_Emission);
   for(int i=size_ts-1; i>=0; i--)
      time_series_Emission[i].t=0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTimeEmission::~CTimeEmission()
  {
  }
//+------------------------------------------------------------------+
//| The Write method of the CTimeEmission class                      |
//+------------------------------------------------------------------+
void CTimeEmission::Write(PointEmission &point)
  {
   CopyTime(NULL,0,0,1,t);
   size_ts=ArraySize(time_series_Emission);
   for(int k=0;k<size_ts;k++)
     {
      if(time_series_Emission[k].t<t[0]) // find the first empty cell
        {
         if(k>size_ts-ARRDELTA)
           {   // increase the array size, if necessary
            int narr=ArrayResize(time_series_Emission,size_ts+ARRMAX,ARRMAX);
            for(int l=size_ts-1;l<narr;l++)
               time_series_Emission[l].t=0;
           }
         time_series_Emission[k].y=point.y;
         time_series_Emission[k].t=point.t;
         time_series_Emission[k].n=1;
         return;
        }
      if(time_series_Emission[k].t==point.t) // find the first similar cell
        {
         time_series_Emission[k].y=(time_series_Emission[k].y*time_series_Emission[k].n+point.y)/(time_series_Emission[k].n+1);
         time_series_Emission[k].n++;
         return;
        }
     }
  }
//+------------------------------------------------------------------+
//| The Read method of the CTimeEmission class                       |
//+------------------------------------------------------------------+
pIntegral CTimeEmission::Read()
  {
   CopyTime(NULL,0,0,1,t);
   pIntegral property_Emission={0.0,0,0};
   size_ts=ArraySize(time_series_Emission);
   for(int k=0;k<size_ts;k++)
     {
      if(time_series_Emission[k].t>=t[0])
        {
         property_Emission.y+=time_series_Emission[k].y*time_series_Emission[k].n;
         property_Emission.t+=(time_series_Emission[k].t-t[0])*time_series_Emission[k].n;
         property_Emission.n+=time_series_Emission[k].n;
        }
     }
   if(property_Emission.n>0)
     {
      property_Emission.y=property_Emission.y/property_Emission.n;
      property_Emission.t=property_Emission.t/property_Emission.n+t[0];
     }
   return(property_Emission);
  }

Qui possiamo vedere l'implementazione di due metodi di classe: scrivere i punti di emissione in serie temporali e leggere i valori delle caratteristiche integrali delle emissioni.

 

Calcolo parsimonioso delle caratteristiche integrali

Ora che abbiamo le serie temporali delle emissioni, possiamo iniziare a creare un algoritmo parsimonioso per il calcolo delle caratteristiche integrali per sviluppare ulteriormente una strategia di trading. Aggiorniamo l'Expert Advisor originale:

//+------------------------------------------------------------------+
//|                                   emission_of_MA_envelope_ts.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 <GetIndicatorBuffers.mqh>
#include <Emission.mqh>
#include <TimeEmission.mqh>
//--- number of point types
#define     NUMBER_TYPES_POINT   3
//--- array for storing the iMA indicator periods
int      MA[]={4,7,11,19,31,51,85};
//--- external variable for storing averaging period of the iEnvelopes indicator
input int ma_period=140; // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double   ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing pointers to the iMA indicator
int      handle_MA[];
//--- array for storing pointers to the iEnvelopes indicator
int      handle_Envelopes[];
//--- market data
datetime    T[],prevTimeBar=0;
double      H[],L[];
#define     HL(a, b) (a+b)/2
//--- class instances
CEmission      EnvMa(0,200);
PointEmission  pEmission;
CTimeEmission  tsMA[NUMBER_TYPES_POINT];
pIntegral      integral[NUMBER_TYPES_POINT];
//--- drawing styles for points of emission
#define     DEL            500
//--- arrays for calculation and display of integral characteristics of emissions
double      sumprev[NUMBER_TYPES_POINT];
int         n[NUMBER_TYPES_POINT],W[NUMBER_TYPES_POINT];
color       colorLine[]={clrAqua,clrBlue,clrMagenta};
int         fontPoint[]={30,30,30};
int         fontMarker[]={16,16,16};
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArraySetAsSeries(T,true);
   ArraySetAsSeries(H,true);
   ArraySetAsSeries(L,true);
   ArrayInitialize(sumprev,0.0);
//---
   int size=ArraySize(MA);
   ArrayResize(handle_MA,size);
//--- create a pointer to the object - the iMA indicator
   for(int i=0; i<size; i++)
     {
      handle_MA[i]=iMA(NULL,0,MA[i],0,MODE_SMA,PRICE_MEDIAN);
      //--- if an error occurs when creating the object, print the message
      if(handle_MA[i]<0)
        {
         Print("The iMA object[",MA[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//+------------------------------------------------------------------+
   size=ArraySize(ENV);
   ArrayResize(handle_Envelopes,size);
//--- create a pointer to the object - the iEnvelopes indicator
   for(int i=0; i<size; i++)
     {
      handle_Envelopes[i]=iEnvelopes(NULL,0,ma_period,0,MODE_SMA,PRICE_MEDIAN,ENV[i]);
      //--- if an error occurs when creating the object, print the message
      if(handle_Envelopes[i]<0)
        {
         Print("The iEnvelopes object[",ENV[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- market data
   CopyTime(NULL,0,0,2,T);
   CopyHigh(NULL,0,0,2,H);
   CopyLow(NULL,0,0,2,L);
//--- fill the declared arrays with current values from all indicator buffers
   string name;
   uint GTC=GetTickCount();
//---- indicator buffers
   double   ibMA[],ibMA1[];      // arrays for the iMA indicator
   double   ibEnvelopesUpper[];  // array for the iEnvelopes indicator (UPPER_LINE)
   double   ibEnvelopesLower[];  // array for the iEnvelopes indicator (LOWER_LINE)
   for(int i=ArraySize(handle_MA)-1; i>=0; i--)
     {
      if(!CopyBufferAsSeries(handle_MA[i],0,0,2,true,ibMA))
         return;
      //---
      for(int j=ArraySize(handle_Envelopes)-1; j>=0; j--)
        {
         if(!GetEnvelopesBuffers(handle_Envelopes[j],0,2,ibEnvelopesUpper,ibEnvelopesLower,true))
            return;
         //--- find the intersection point of the iEnvelopes(UPPER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesUpper[1],ibEnvelopesUpper[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, add it to the time series of emission
            tsMA[0].Write(pEmission);
         //--- find the intersection point of the iEnvelopes(LOWER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesLower[1],ibEnvelopesLower[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, add it to the time series of emission
            tsMA[1].Write(pEmission);
        }
      //---
      for(int j=ArraySize(handle_MA)-1; j>=0; j--)
        {
         if(i!=j)
           {
            if(!CopyBufferAsSeries(handle_MA[j],0,0,2,true,ibMA1))
               return;
            //--- find the intersection point of the iMA and iMA indicators
            pEmission=EnvMa.CalcPoint(ibMA1[1],ibMA1[0],ibMA[1],ibMA[0],T[0]);
            if(pEmission.real) // if the intersection point is found, add it to the time series of emission
               tsMA[2].Write(pEmission);
           }
        }
     }
//--- deletion of the graphical objects of emission not to stuff the chart
   if(T[0]>prevTimeBar)
     {
      prevTimeBar=T[0];
      //---
      for(int i=ArraySize(n)-1; i>=0; i--)
         sumprev[i]=integral[i].y;
      //---
      for(int obj=ObjectsTotal(0,0,-1)-1;obj>=0;obj--)
        {
         string obj_name=ObjectName(0,obj,0,OBJ_TREND);
         datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
         if(obj_time<T[0]-DEL*PeriodSeconds())
            ObjectDelete(0,obj_name);
        }
      Comment("Emission © DC2008   Graphical objects = ",ObjectsTotal(0,0,-1));
     }
//--- calculation of integral characteristics of emission
   for(int i=ArraySize(n)-1; i>=0; i--)
      integral[i]=tsMA[i].Read();
//--- displaying integral characteristics of emission
   ArrayInitialize(W,5);
   if(integral[0].n>integral[1].n)
     {
      W[0]=20;
      W[1]=10;
     }
   else
     {
      W[0]=10;
      W[1]=20;
     }
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      //--- horizontal lines of mean prices
      name="H.line."+(string)i;
      ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
      ObjectSetDouble(0,name,OBJPROP_PRICE,integral[i].y);
      //--- markers
      name="P."+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontMarker[i]);
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(163));
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,integral[i].y);
      ObjectSetInteger(0,name,OBJPROP_TIME,integral[i].t);
      //--- integral curves
      name="T"+(string)i+".line"+(string)T[1];
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,W[i]);
      if(sumprev[i]>0)
        {
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,sumprev[i]);
         ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,integral[i].y);
         ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
        }
      //--- numerical values of integral characteristics
      if(integral[0].n+integral[1].n>0)
        {
         name="Text"+(string)i+".control";
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontPoint[i]);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         string str=DoubleToString((double)integral[i].n/(double)(integral[0].n+integral[1].n)*100,1);
         ObjectSetString(0,name,OBJPROP_TEXT,str);
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,integral[i].y);
         ObjectSetInteger(0,name,OBJPROP_TIME,0,integral[i].t);
        }
     }
  }

Il codice si è accorciato, mentre la velocità di calcolo è aumentata. Ora puoi testare e ottimizzare i tuoi robot di trading senza visualizzazione! 

 

Uso delle caratteristiche integrali nel trading

Le caratteristiche integrali possono essere utilizzate come generatore di segnali per:

  • svolta del canale,
  • intersezione tra loro o il prezzo,
  • cambiare direzione.
Ad esempio, la figura seguente mostra come le caratteristiche integrali delle emissioni possono essere ipoteticamente utilizzate alle intersezioni con il prezzo. I segnali di vendita vengono generati quando il prezzo viene incrociato al rialzo dalla curva blu e i segnali di acquisto vengono generati all'incrocio al ribasso del prezzo con la curva aqua.

Fig. 11. Segnali di trading agli incroci delle caratteristiche integrali delle emissioni

Fig.  11. Segnali di scambio agli incroci delle caratteristiche integrali delle emissioni

 

Conclusione

  1. Il calcolo delle caratteristiche integrali delle emissioni degli indicatori fornisce nuovi strumenti e metodi per l'analisi di mercato (serie temporali).
  2. Utilizzando le serie temporali, siamo riusciti ad aumentare la velocità dei calcoli delle caratteristiche integrali.
  3. E ci ha aperto la possibilità di sviluppare strategie di trading automatizzate che utilizzano le emissioni.

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

Informazioni generali sui segnali di trading per MetaTrader 4 e MetaTrader 5 Informazioni generali sui segnali di trading per MetaTrader 4 e MetaTrader 5
MetaTrader 4 / MetaTrader 5 Trading Signals è un servizio che consente ai trader di copiare le operazioni di trading di un fornitore di segnali. Il nostro obiettivo era quello di sviluppare il nuovo servizio di largo utilizzo, per proteggere gli abbonati e facendo risparmiare loro costi inutili.
Forum sulla programmazione MQL5 Ora Forum sulla programmazione MQL5 Ora
L'articolo si concentra sulle funzioni MQL5 standard per lavorare con il tempo, nonché sulle tecniche di programmazione e sulle funzioni praticamente utili per lavorare con il tempo richiesto durante la creazione di Expert Advisor e indicatori. Particolare attenzione è rivolta alla teoria generale della misurazione del tempo. Questo articolo dovrebbe essere di interesse principalmente per i programmatori MQL5 alle prime armi.
Widget dei segnali di trading MetaTrader 4 e MetaTrader 5 Widget dei segnali di trading MetaTrader 4 e MetaTrader 5
Recentemente gli utenti MetaTrader 4 e MetaTrader 5 hanno ricevuto l'opportunità di diventare fornitori di segnali e di guadagnare ulteriori profitti. Ora puoi mostrare tuoi successi di trading sul tuo sito web, blog o pagina di social network utilizzando i nuovi widget. I vantaggi dell'utilizzo dei widget sono evidenti: aumentano la popolarità dei fornitori di segnali, stabiliscono la loro reputazione di trader di successo e attirano nuovi abbonati. Tutti i trader che inseriscono widget su altri siti Web possono godere di questi vantaggi.
Come diventare un fornitore di segnali per MetaTrader 4 e MetaTrader 5 Come diventare un fornitore di segnali per MetaTrader 4 e MetaTrader 5
Vuoi offrire i tuoi segnali di trading e realizzare profitti? Registrati sul sito MQL5.com come Venditore e specifica il tuo conto di trading per offrire i tuoi segnali ai trader.