English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Costruire un Analizzatore di Spettro

Costruire un Analizzatore di Spettro

MetaTrader 5Esempi | 16 dicembre 2021, 11:27
176 0
Victor
Victor

Introduzione

Questo articolo ha lo scopo di far conoscere ai suoi lettori una possibile variante dell'utilizzo di oggetti grafici del linguaggio MQL5. Analizza un indicatore, che implementa un pannello di controllo di un semplice analizzatore di spettro utilizzando gli oggetti grafici.

Tre file sono allegati all'articolo:

  1. SpecAnalyzer.mq5 – l'indicatore descritto in questo articolo.
  2. SpecAnalyzer.mqh: il file di inclusione per SpecAnalyzer.mq5.
  3. SAInpData.mq5 – l'indicatore utilizzato per l'organizzazione di un accesso a dati esterni.

Per caricare normalmente l'indicatore SpecAnalyzer, è necessario posizionare tutti e tre i file nella cartella \MQL5\Indicators del terminale client. Quindi dovresti compilare i file SpecAnalyzer.mq5 e SAInpData.mq5. L'indicatore deve essere caricato nella finestra del grafico principale. Una volta caricato l'indicatore, cambia i parametri di visualizzazione di questa finestra e quando viene rimosso tutti gli oggetti grafici vengono cancellati dalla finestra. Ecco perché dovresti caricare l'indicatore in una finestra separata speciale creata per esso, per evitare la modifica accidentale della modalità di visualizzazione delle finestre esistenti del terminale.

Considerando il fatto che l'articolo non contiene il codice sorgente completo dell'indicatore, si consiglia di tenere aperto il codice nei file allegati durante la lettura dell'articolo.

L'indicatore descritto nell'articolo non pretende di essere un'applicazione già pronta. È solo un esempio di utilizzo di oggetti grafici del linguaggio. Chi è interessato può aggiornare e ottimizzare da solo il codice mostrato nell'articolo.

Coordinate

Due modi possono essere utilizzati in MQL5 per specificare le coordinate quando si disegnano oggetti grafici. Per alcuni oggetti le coordinate sono specificate come numero di pixel da un punto specificato della finestra; e per altri le coordinate sono specificate come i valori di prezzo e tempo del grafico visualizzato nella finestra.

Ad esempio, per posizionare oggetti come "Etichetta" o "Pulsante" su un grafico, è necessario specificare le loro coordinate come distanza in pixel da uno degli angoli della finestra della grafico. Con questo modo di indirizzare gli oggetti mantengono la loro posizione indipendentemente dalle proprietà della finestracorrenti e dalla scala del grafico visualizzato in essa. Anche se la dimensione della finestra cambia, tali oggetti mantengono la loro posizione e si legano tra loro. Se sposti il grafico nella finestra con il tasto sinistro del mouse, quegli oggetti mantengono la loro posizione rispetto al punto di ancoraggio scelto della finestra.

L'altro gruppo di oggetti implica l'associazione a un grafico nella finestra invece delle coordinate della finestra. Questi oggetti sono "Linea di Tendenza", "Rettangolo", ecc. Quando si creano e si posizionano tali oggetti, le coordinate sono specificate come valore di tempo e prezzo di un grafico visualizzato nella finestra. Con questa modalità di indicazione delle coordinate, gli oggetti cambiano la loro posizione rispetto alla finestra del grafico e tra loro quando la scala del grafico viene cambiata o quando viene fatta scorrere. Quando viene visualizzata una nuova barra sul grafico, anche gli oggetti cambiano la loro posizione, poiché l'asse del tempo si sposta a sinistra rispetto alla dimensione del timeframe.

Nell'indicatore SpecAnalyzer, entrambi i tipi di oggetti grafici vengono utilizzati contemporaneamente per creare il pannello di controllo dell'analizzatore di spettro. Affinché gli oggetti legati alla carta non si muovano rispetto alla finestra, impostiamo la modalità fissa di visualizzazione del grafico lungo l'asse verticale e la modalità corrispondente alla scala minima possibile di visualizzazione lungo la scala orizzontale del grafico. Inoltre, il minimo della scala verticale è impostato su 0.0; e per l'asse orizzontale impostiamo la modalità senza spostamento della barra zero dal bordo destro e senza scorrimento automatico al bordo destro del grafico. Pertanto, il punto di coordinate che corrisponde alla barra zero e al valore 0.0 del grafico sembra essere nell'angolo in basso a destra e con la scala fissa può essere utilizzato un punto di ancoraggio per oggetti come "Linea di Tendenza" e "Rettangolo". Quindi, se impostiamo lo stesso angolo in basso a destra come punto di ancoraggio degli oggetti come "Etichetta" o "Pulsante", allora entrambi i tipi di oggetti saranno definitivamente legati l'uno all'altro.

Tutte le necessarie proprietà del grafico sono impostate nella funzione SetOwnProperty() nel file SpecAnalyzer.mqh.

void GRaphChart::SetOwnProperty(void)
  {
  ChartSetInteger(m_chart_id,CHART_FOREGROUND,1);
  ChartSetInteger(m_chart_id,CHART_SHIFT,0);
  ChartSetInteger(m_chart_id,CHART_AUTOSCROLL,0);
  ChartSetInteger(m_chart_id,CHART_AUTOSCROLL,1);
  ChartSetInteger(m_chart_id,CHART_SCALE,0);
  ChartSetInteger(m_chart_id,CHART_SCALEFIX_11,1);
  ChartSetInteger(m_chart_id,CHART_SHOW_OHLC,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_BID_LINE,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_ASK_LINE,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_LAST_LINE,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_PERIOD_SEP,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_GRID,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_VOLUMES,CHART_VOLUME_HIDE);
  ChartSetInteger(m_chart_id,CHART_SHOW_OBJECT_DESCR,0);
  ChartSetInteger(m_chart_id,CHART_SHOW_TRADE_LEVELS,0);
  ChartSetInteger(m_chart_id,CHART_COLOR_BACKGROUND,Black);
  ChartSetInteger(m_chart_id,CHART_COLOR_FOREGROUND,Black);
  ChartSetDouble(m_chart_id,CHART_FIXED_MIN,0.0);
  }

Questa funzione, oltre a impostare le proprietà necessarie del grafico per fornire il binding di oggetti grafici, imposta le proprietà che consentono di assegnare un colore e limitare la visualizzazione di alcuni elementi del grafico.

Poiché l'indicatore SpecAnalyzer cambia le proprietà del grafico durante il lavoro, dovremmo fornire il salvataggio delle impostazioni precedenti del grafico al caricamento dell'indicatore e il ripristino delle impostazioni allo scaricamento. La libreria standard di MQL5 include le funzioni virtuali speciali a tale scopo - Save() e Load() della classe CChart. Queste funzioni hanno lo scopo di salvare le proprietà di un oggetto della classe CChart in un file e ripristinare quelle proprietà dal file creato. Per modificare l'insieme delle proprietà salvate ed evitare di utilizzare operazioni sui file durante il salvataggio delle proprietà di un grafico, le funzioni virtuali Save() e Load() della classe CChart vengono sovrascritte alla creazione della nuova classe GRaphChart (vedere il file SpecAnalyzer.mqh). 

class GRaphChart : public CChart
  {
  protected:
    struct ChartPropertyes
      {
      double shift_size;
      double fixed_max;
      double fixed_min;
      double points_per_bar;
      long   mode;
      bool   foreground;
      bool   shift;
      bool   autoscroll;
      long   scale;
      bool   scalefix;
      bool   scalefix_11;
      bool   scale_pt_per_bar;
      bool   show_ohls;
      bool   show_bid_line;
      bool   show_ask_line;
      bool   show_last_line;
      bool   show_period_sep;
      bool   show_grid;
      long   show_volumes;
      bool   show_object_descr;
      bool   show_trade_levels;
      long   color_background;
      long   color_foreground;
      long   color_grid;
      long   color_volume;
      long   color_chart_up;
      long   color_chart_down;
      long   color_chart_line;
      long   color_candle_bull;
      long   color_candle_bear;
      long   color_bid;
      long   color_ask;
      long   color_last;
      long   color_stop_level;
      string ch_comment;
      };
      ChartPropertyes ChProp;
  
  public:
                   GRaphChart();
                  ~GRaphChart();
                   
         void      SetOwnProperty();
  virtual void      Save();
  virtual void      Load();
  };

La classe base di GRaphChart è CChart della libreria standard di MQL5. La classe GRaphChart contiene la descrizione della struttura ChartPropertyes e la creazione dell'oggetto ChProp destinato a memorizzare le proprietà del grafico in memoria invece di un file come implementato nella classe base. La funzione Save() riempie la struttura ChProp con i dati in base alle proprietà correnti del grafico e la funzione Load() ripristina le proprietà salvate in precedenza da esso.

La funzione Save() viene chiamata nel costruttore della classe GRaphChart e la funzione Load() viene chiamata nel suo distruttore. Ecco perché il salvataggio e il ripristino dello stato precedente del grafico viene eseguito automaticamente durante la creazione e l'eliminazione dell'oggetto della classe GRaphChart. Il SetOwnProperty() menzionato sopra viene chiamato anche nel costruttore della classe.

//---------------------------------------------------- Constructor GRaphChart --
GRaphChart::GRaphChart()
  {
  m_chart_id=ChartID();
  Save();                                // Keep a original chart settings
  SetOwnProperty();                             // Set own chart settings
  }
//----------------------------------------------------- Destructor GRaphChart --
GRaphChart::~GRaphChart()
  {
  Load();                             // Restore a previous chart settings
  m_chart_id=-1;
  }

Dimostriamo l'uso della classe GRaphChart con un semplice esempio. Per farlo, creiamo un nuovo indicatore personalizzato in MetaEditor e chiamiamolo Test. Includere il file di intestazione SpecAnalyzer.mqh nel codice dell'indicatore e creare un oggetto della classe GRaphChart aggiungendo due righe.

//+------------------------------------------------------------------+
//|                                                         Test.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window

#include "SpecAnalyzer.mqh"    // <----- Including header file 

GRaphChart  MainChart; // <----- Creating object of the class GRaphChart

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
//---
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Per una corretta compilazione del suddetto codice, il file SpecAnalyzer.mqh deve essere posizionato nella cartella \MQL5\Indicators del terminale client.

Se crei un grafico nel terminale client e provi a caricare il nostro esempio di test in esso, le proprietà del grafico verranno modificate e vedrai solo una finestra vuota preparata per la visualizzazione di oggetti grafici al suo interno. Quando rimuovi il nostro indicatore di prova dal grafico, il suo aspetto iniziale verrà ripristinato con l'arrivo di un nuovo tick.

Torniamo all'indicatore SpecAnalyzer. All'inizio dell'indicatore (vedi file SpecAnalyzer.mq5), viene eseguita la creazione dell'oggetto MainChart della classe GRaphChart, che porta al caricamento dell'indicatore e al salvataggio delle proprietà del grafico.

                 button. button. button.
GRaphChart MainChart; // Create MainChart object
                 button. button. button.

Quando si scarica l'indicatore, l'oggetto MainChart viene automaticamente terminato, quindi le proprietà iniziali del grafico vengono ripristinate nel distruttore di classi. 

Pannello di controllo

L'aspetto del pannello di controllo nell'indicatore SpecAnalyzer è determinato da oggetti grafici posizionati nella finestra. La classe AllGrObject riunisce tutte le funzioni necessarie per crearle e interagire con esse; vedere il file SpecAnalyzer.mqh.

class AllGrObject : public CChart
  {
  protected:
    long      m_chart_id;                                    // chart identifier
    
  public:
              AllGrObject();
             ~AllGrObject();
                   
    void      AddLabel(string name,int fsize,string font,
                             color col,int x,int y,string text="");
    void      AddButton(string name,int xsize,int ysize,color bgcol,
                        int fsize,string font,color col,int x,int y,
                        string text="",int state=0);
    void      AddEdit(string name,int xsize,int ysize,color bgcol,int fsize,
                      string font,color col,int x,int y,string text="");
    void      AddTrendLine(string name,color col,int style=0,int width=1);
    void      AddArrowline(string name,color col,int style=0,int width=1);
    void      AddRectangle(string name,color col,int style=0,int width=1);
    void      MoveGrObject(string name,int x1,int y1,int x2,int y2);
    void      SetButtonProp(string name,bool state,color col);
    long      GetRowNumber(string name);
    void      LabelTxt(string name,string str);
    
  };

Le funzioni della classe, i cui nomi iniziano con Add, sono destinate alla creazione degli oggetti grafici. Ad esempio, AddButton() crea l'oggetto "Button".

Nell'applicazione, le coordinate per tutti gli oggetti grafici sono impostate come la distanza in pixel dall'angolo inferiore destro del grafico. Per gli oggetti “Trend Line”, “Arrowed Line” e “Rectangle” dovremmo trasformare tali coordinate nei valori di tempo e prezzo. Tale trasformazione viene eseguita nella funzione MoveGrObject() prima di assegnare le coordinate a un oggetto. Un pixel orizzontale corrisponde a una barra e un pixel verticale corrisponde a un punto.

void AllGrObject::MoveGrObject(string name,int x1,int y1,int x2,int y2)
  {
  datetime t1[1],t2[1];
  long typ;
  
  typ=ObjectGetInteger(m_chart_id,name,OBJPROP_TYPE);
  if(typ==OBJ_TREND||typ==OBJ_ARROWED_LINE||typ==OBJ_RECTANGLE)
    {
    CopyTime(_Symbol,_Period,x1,1,t1);
    CopyTime(_Symbol,_Period,x2,1,t2);
    ObjectSetInteger(m_chart_id,name,OBJPROP_TIME,0,t1[0]);
    ObjectSetDouble(m_chart_id,name,OBJPROP_PRICE,0,_Point*y1);
    ObjectSetInteger(m_chart_id,name,OBJPROP_TIME,1,t2[0]);
    ObjectSetDouble(m_chart_id,name,OBJPROP_PRICE,1,_Point*y2);
    }
  }

Tutti gli oggetti grafici vengono creati una sola volta nell'indicatore, ciò avviene chiamando gr_object_create() dalla funzione OnInit() dell'indicatore; vedere il file SpecAnalyzer.mq5. Per tutti gli oggetti, ad eccezione di “Trend Line”, “Arrowed Line” e “Rectangle”, le coordinate vengono impostate immediatamente. Per oggetti come "Trend Line", "Arrowed Line" e "Rectangle" le coordinate vengono impostate chiamando la funzione gr_object_coordinate() che utilizza la funzione MoveGrObject() sopra menzionata, che trasforma la modalità di indirizzamento. 

void gr_object_coordinate()
  {
  GObj.MoveGrObject("Trdline1",48,150,48,360);
  GObj.MoveGrObject("Trdline2",176,150,176,360);
  GObj.MoveGrObject("Trdline3",304,150,304,360);
  GObj.MoveGrObject("Trdline4",432,150,432,360);
  GObj.MoveGrObject("Trdline5",42,350,560,350);
  GObj.MoveGrObject("Trdline6",42,300,560,300);
  GObj.MoveGrObject("Trdline7",42,250,560,250);
  GObj.MoveGrObject("Trdline8",42,200,560,200);
  GObj.MoveGrObject("Arrline1",560,150,28,150);
  GObj.MoveGrObject("Arrline2",560,150,560,370);
  GObj.MoveGrObject("Rect1",0,1,208,110);
  GObj.MoveGrObject("Rect2",208,1,416,110);
  GObj.MoveGrObject("Rect3",416,1,624,110);
  GObj.MoveGrObject("Rect4",0,1,624,400);
  GObj.MoveGrObject("Rect5",20,10,195,80);
  }

La chiamata della funzione gr_object_coordinate() è inclusa nella funzione OnCalculate() dell'indicatore. Fornisce un corretto ricalcolo delle coordinate quando si forma una nuova barra sul grafico, poiché la funzione viene chiamata ad ogni arrivo di un nuovo tick.

I pulsanti sul pannello dell'indicatore sono divisi in tre gruppi. Il primo gruppo è composto da quattro pulsanti posti sulla sinistra; consentono di selezionare una modalità di visualizzazione del risultato della stima dello spettro della sequenza di input da parte dell'indicatore. Sono supportate quattro modalità di visualizzazione (in base al numero di pulsanti):

  1. Ampiezza/Riga- visualizza il modulo della trasformata di Fourier su una scala lineare lungo l'asse Y.
  2. Ampiezza/dB - visualizzazione del modulo della trasformata di Fourier in scala logaritmica lungo l'asse Y.
  3. Potenza/Riga- visualizza il quadrato del modulo della trasformata di Fourier su una scala lineare lungo l'asse Y.
  4. Potenza/dB - visualizzazione del quadrato del modulo della trasformata di Fourier in scala logaritmica lungo l'asse Y.

Per elaborare facendo clic sui pulsanti di questo gruppo, il seguente codice è incluso nella funzione OnChartEvent() dell'indicatore: 

  if(id==CHARTEVENT_OBJECT_CLICK)                       // Click on the gr. object
    {
    if(sparam=="Butt1")                                   // Click on the button
      {
      GObj.SetButtonProp("Butt1",1,Chocolate);
      GObj.SetButtonProp("Butt2",0,SlateGray);
      GObj.SetButtonProp("Butt3",0,SlateGray);
      GObj.SetButtonProp("Butt4",0,SlateGray);
      YPowerFlag=0;YdBFlag=0;
      }
    if(sparam=="Butt2")                                   // Click on the button
      {
      GObj.SetButtonProp("Butt1",0,SlateGray);
      GObj.SetButtonProp("Butt2",1,Chocolate);
      GObj.SetButtonProp("Butt3",0,SlateGray);
      GObj.SetButtonProp("Butt4",0,SlateGray);
      YPowerFlag=0;YdBFlag=1;
      }
    if(sparam=="Butt3")                                   // Click on the button
      {
      GObj.SetButtonProp("Butt1",0,SlateGray);
      GObj.SetButtonProp("Butt2",0,SlateGray);
      GObj.SetButtonProp("Butt3",1,Chocolate);
      GObj.SetButtonProp("Butt4",0,SlateGray);
      YPowerFlag=1;YdBFlag=0;
      }
    if(sparam=="Butt4")                                   // Click on the button
      {
      GObj.SetButtonProp("Butt1",0,SlateGray);
      GObj.SetButtonProp("Butt2",0,SlateGray);
      GObj.SetButtonProp("Butt3",0,SlateGray);
      GObj.SetButtonProp("Butt4",1,Chocolate);
      YPowerFlag=1;YdBFlag=1;
      }

Quando viene rilevato un click su uno dei pulsanti, lo stato degli altri pulsanti viene modificato in non premuto, il che impedisce la pressione simultanea di più pulsanti in un gruppo. Contemporaneamente vengono impostati i valori corrispondenti per i flag YPowerFlag e YdBFlag che determinano la modalità di visualizzazione corrente.

Il secondo gruppo composto da quattro pulsanti offre la possibilità di selezionare una fonte di dati di input. Possono essere dati esterni ottenuti chiamando l'indicatore SAInpData.mq5 o tre sequenze di test generate dall'applicazione stessa. L'ultimo gruppo di pulsanti include due pulsanti utilizzati per scorrere l'elenco nel campo di immissione delle informazioni di testo. La gestione del clic su tutti questi pulsanti viene eseguita anche nella funzione OnChartEvent() dell'indicatore proprio come i pulsanti del primo gruppo; vedere il file SpecAnalyzer.mq5.

Mostriamo un esempio di utilizzo della classe AllGrObject utilizzando l'indicatore di test precedentemente creato Test.mq5. Per farlo, aggiungi diverse righe al suo codice sorgente e includi le funzioni gr_object_create() e gr_object_coordinate() menzionate in precedenza dal file SpecAnalyzer.mq5.

//+------------------------------------------------------------------+
//|                                                         Test.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window

#include "SpecAnalyzer.mqh" 

GRaphChart  MainChart;

AllGrObject GObj;        // <----- Creating object of the class AllGrObject

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//---

  gr_object_create();          // <----- creating graphical objects

   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
//---

  MainChart.SetOwnProperty();    // <----- restoring current properties of the chart
  gr_object_coordinate();     // <----- setting coordinates for the graphical objects


//--- return value of prev_calculated for next call
   return(rates_total);
  }

//----------------------------------------------- Create all graphical objects --
void gr_object_create()
  {
  GObj.AddLabel("Title",10,"Arial",DarkGray,256,367,"Spectrum Analyzer");
  GObj.AddLabel("Label1",9,"Arial",LightSteelBlue,557,128,"0");
  GObj.AddLabel("Label2",9,"Arial",LightSteelBlue,422,128,"128");
  GObj.AddLabel("Label3",9,"Arial",LightSteelBlue,294,128,"256");
  GObj.AddLabel("Label4",9,"Arial",LightSteelBlue,166,128,"384");
  GObj.AddLabel("Label5",9,"Arial",LightSteelBlue,40,128,"512");
  GObj.AddLabel("Label6",9,"Arial",LightSteelBlue,28,156,"N");
  GObj.AddLabel("Label7",9,"Arial",LightSteelBlue,569,141,"0.00");
  GObj.AddLabel("Label8",9,"Arial",LightSteelBlue,569,191,"0.25");
  GObj.AddLabel("Label9",9,"Arial",LightSteelBlue,569,241,"0.50");
  GObj.AddLabel("Label10",9,"Arial",LightSteelBlue,569,291,"0.75");
  GObj.AddLabel("Label11",9,"Arial",LightSteelBlue,569,341,"1.00");
  GObj.AddLabel("Label12",9,"Arial",LightSteelBlue,569,358,"U");
  GObj.AddLabel("Label13",9,"Arial",DarkGray,490,86,"Y-axis Mode");
  GObj.AddLabel("Label14",9,"Arial",DarkGray,285,86,"Input Data");
  GObj.AddLabel("Label15",9,"Arial",DarkGray,75,86,"Level");
  GObj.AddLabel("Label16",9,"Arial",DarkGray,185,86,"N");
  GObj.AddLabel("Label17",8,"Courier",DarkOliveGreen,64,64);
  GObj.AddLabel("Label18",8,"Courier",DarkOliveGreen,64,51);
  GObj.AddLabel("Label19",8,"Courier",DarkOliveGreen,64,38);
  GObj.AddLabel("Label20",8,"Courier",DarkOliveGreen,64,25);
  GObj.AddLabel("Label21",8,"Courier",DarkOliveGreen,64,12);
  GObj.AddButton("Butt1",185,18,C'32,32,32',8,"Arial",SlateGray,612,79,"Amplitude (line)",0);
  GObj.AddButton("Butt2",185,18,C'32,32,32',8,"Arial",Chocolate,612,61,"Amplitude (log)",1);
  GObj.AddButton("Butt3",185,18,C'32,32,32',8,"Arial",SlateGray,612,43,"Power (line)",0);
  GObj.AddButton("Butt4",185,18,C'32,32,32',8,"Arial",SlateGray,612,25,"Power (log)",0);
  GObj.AddButton("Butt5",185,18,C'32,32,32',8,"Arial",SlateGray,403,79,"External Data",0);
  GObj.AddButton("Butt6",185,18,C'32,32,32',8,"Arial",SlateGray,403,61,"Test 1. SMA(3)",0);
  GObj.AddButton("Butt7",185,18,C'32,32,32',8,"Arial",Chocolate,403,43,"Test 2. SMA(32)",1);
  GObj.AddButton("Butt8",185,18,C'32,32,32',8,"Arial",SlateGray,403,25,"Test 3. LWMA(12)",0);
  GObj.AddButton("Butt9",14,34,C'32,32,32',8,"Wingdings",SlateGray,36,78,"\x0431",0);
  GObj.AddButton("Butt10",14,34,C'32,32,32',8,"Wingdings",SlateGray,36,44,"\x0432",0);
  GObj.AddEdit("Edit1",35,18,Black,9,"Arial",SlateGray,180,102);
  GObj.AddTrendLine("Trdline1",C'32,32,32');
  GObj.AddTrendLine("Trdline2",C'32,32,32');
  GObj.AddTrendLine("Trdline3",C'32,32,32');
  GObj.AddTrendLine("Trdline4",C'32,32,32');
  GObj.AddTrendLine("Trdline5",C'32,32,32');
  GObj.AddTrendLine("Trdline6",C'32,32,32');
  GObj.AddTrendLine("Trdline7",C'32,32,32');
  GObj.AddTrendLine("Trdline8",C'32,32,32');
  GObj.AddArrowline("Arrline1",LightSteelBlue);
  GObj.AddArrowline("Arrline2",LightSteelBlue);
  GObj.AddRectangle("Rect1",C'72,72,72');
  GObj.AddRectangle("Rect2",C'72,72,72');
  GObj.AddRectangle("Rect3",C'72,72,72');
  GObj.AddRectangle("Rect4",DarkGray);
  GObj.AddRectangle("Rect5",C'72,72,72');
  }
//---------- Set object coordinate for Trend Line, Arroved Line and Rectangle --
void gr_object_coordinate()
  {
  GObj.MoveGrObject("Trdline1",48,150,48,360);
  GObj.MoveGrObject("Trdline2",176,150,176,360);
  GObj.MoveGrObject("Trdline3",304,150,304,360);
  GObj.MoveGrObject("Trdline4",432,150,432,360);
  GObj.MoveGrObject("Trdline5",42,350,560,350);
  GObj.MoveGrObject("Trdline6",42,300,560,300);
  GObj.MoveGrObject("Trdline7",42,250,560,250);
  GObj.MoveGrObject("Trdline8",42,200,560,200);
  GObj.MoveGrObject("Arrline1",560,150,28,150);
  GObj.MoveGrObject("Arrline2",560,150,560,370);
  GObj.MoveGrObject("Rect1",0,1,208,110);
  GObj.MoveGrObject("Rect2",208,1,416,110);
  GObj.MoveGrObject("Rect3",416,1,624,110);
  GObj.MoveGrObject("Rect4",0,1,624,400);
  GObj.MoveGrObject("Rect5",20,10,195,80);
  }
//+------------------------------------------------------------------+

Per fornire l'accesso alle funzioni della classe AllGrObject creare l'oggetto GObj di questa classe. Nella funzione OnInit() dell'indicatore includere la chiamata della funzione gr_object_create(), che crea tutti gli oggetti grafici necessari che determinano l'aspetto e la funzionalità del pannello di controllo dell'indicatore.

Nella funzione OnCalculate aggiungi le chiamate delle funzioni MainChart.SetOwnProperty() e gr_object_coordinate(); così, le proprietà del grafico e le coordinate degli oggetti disegnati su di esso verranno ripristinate all'arrivo di ogni nuovo tick. Tale ripristino è necessario quando viene formata una nuova barra in corrispondenza del grafico iniziale o il grafico viene spostato utilizzando il tasto sinistro del mouse o quando un utente modifica le proprietà del grafico. Dopo aver compilato e caricato questo esempio di test, vedremo le interfacce del pannello di controllo; vedi fig. 1.

Fig. 1. Interfaccia del pannello di controllo. 

Fig. 1. Interfaccia del pannello di controllo.

 Per mostrarti visivamente la posizione del pannello di controllo rispetto al grafico, abilita la visualizzazione della scala del grafico nell'esempio sopra; vedi fig. 2.

 Fig. 2. La scala del grafico.

Fig. 2. La scala del grafico 

L'Analizzatore di Spettro

L'analisi di uno spettro nell'indicatore viene eseguita mediante la graduazione 1024 della sequenza di input. L'analisi dello spettro viene eseguita utilizzando l'algoritmo di trasformazione di fast Fourier . La funzione che implementa l'algoritmo FFT è tratta dalle pubblicazioni del sito www.mql4.com. Per i calcoli usiamo la funzione FFT della sequenza in tempo reale in ingresso; il suo codice viene inserito nel file SpecAnalyzer.mqh. Tutte le azioni necessarie per l'analisi dello spettro sono implementate nella funzione fft_calc(). 

void fft_calc()
  {
  int i,k;

  realfastfouriertransform(InpData,ArraySize(InpData),false);          // FFT
  for(i=1;i<ArraySize(Spectrum);i++)
    {
    k=i*2;
    Spectrum[i]=InpData[k]*InpData[k]+InpData[k+1]*InpData[k+1];    
    }
  Spectrum[0]=0.0;                             // Clear constant component level
  }

Quando viene chiamata la funzione fft_calc(), l'array InpData[] deve contenere una sequenza di input da analizzare. Dopo l'esecuzione di realfastfouriertransform(), il risultato di FFT verrà inserito in quell’array. Inoltre, il quadrato del modulo viene calcolato per ciascuna armonica dalla parte reale e immaginaria delle stime dello spettro; il risultato viene scritto nell'array Spectrum[]. L'indice dell'elemento nell'array Spectrum[] corrisponde al numero armonico. Poiché il valore calcolato della componente costante non viene utilizzato nell'indicatore, il valore zero viene sempre assegnato all'elemento Spectrum[0] dell'array.

A seconda del valore della variabile InputSource, l'array InpData[] può essere riempito con sequenze di test o con dati ottenuti da un indicatore esterno. I dati di input sono formati nella funzione get_input_data().

void get_input_data()
  {
  int i;
  
  ArrayInitialize(InpData,0.0);
  switch(InputSource)
    {
    case 0:                                                    // External Data
      if(ExtHandle!=INVALID_HANDLE)
        CopyBuffer(ExtHandle,0,0,ArraySize(InpData),InpData);
      break;
    case 1:                                                    // Test 1. SMA(3)
      for(i=0;i<3;i++)InpData[i]=1;
      break;
    case 2:                                                   // Test 2. SMA(32)
      for(i=0;i<32;i++)InpData[i]=1;
      break;
    case 3:                                                  // Test 3. LWMA(12)
      for(i=0;i<12;i++)InpData[i]=12-i;
      break;
    }
  }

Se il valore di InputSource è uguale a zero, 1024 valori verranno copiati nella matrice di input InpData[] dal buffer zero dell'indicatore SAInpData.mq5. I dati per l'analisi possono essere formati sia nell'indicatore stesso, sia richiamando altri indicatori da esso. Per fornire l'accesso all'indicatore SAInpData.mq5, alla funzione OnInit() viene aggiunta la riga seguente che determina il valore della variabile ExtHandle.

int OnInit() 
 {
 button. button. button.

 ExtHandle=iCustom(NULL,0,"SAInpData");  // External indicator Handle

 return(0);
 }

L'indicatore SAInpData.mq5 deve essere posizionato nella directory \MQL5\Indicators del terminale client. L'indicatore SAInpData.mq5 allegato a questo articolo come esempio passa una sequenza casuale all'analizzatore. Per fare in modo che SAInpData.mq5 passi un'altra sequenza all'analizzatore, modificarne il codice sorgente.

Come sequenze di test per le funzioni get_input_data(), vengono generate le caratteristiche di impulso delle medie mobili SMA(3), SMA(32) e LWMA(12). Considerando che la trasformazione di Fourier di una caratteristica di impulso di un filtro corrisponde alle caratteristiche di ampiezza-frequenza di quel filtro, possiamo osservare le caratteristiche di ampiezza-frequenza delle medie mobili se le selezioniamo come sequenze di test.

Per normalizzare il risultato della stima dello spettro memorizzato nell'array Spectrum[] e prepararlo alla visualizzazione nella modalità specificata, viene utilizzata la funzione norm_and_draw(); vedere il file SpecAnalyzer.mq5. A seconda della modalità di visualizzazione scelta, questa funzione sostituisce la marcatura del testo dell'asse Y.

Il risultato della stima dello spettro della sequenza di input viene visualizzato non solo in forma grafica, ma anche in forma testuale. Per la rappresentazione dei risultati in forma testuale vengono creati cinque oggetti grafici del tipo “Etichetta”; corrispondono a cinque righe di testo visualizzate. La funzione list_levels() esegue il riempimento di queste righe con le informazioni. 

void list_levels()
  {
  int m;
  string str;
  
  if(YdBFlag==0) str="%3u    %.5f";                     // If Y-axis mode = Line
  else str="%3u  %6.1f dB";                               // If Y-axis mode = dB
  m=ArraySize(ListArray)-5;
  if(ListPointer<1)ListPointer=1;
  if(ListPointer>m)ListPointer=m;
  GObj.LabelTxt("Label17",StringFormat(str,ListPointer,ListArray[ListPointer]));
  GObj.LabelTxt("Label18",StringFormat(str,ListPointer+1,ListArray[ListPointer+1]));
  GObj.LabelTxt("Label19",StringFormat(str,ListPointer+2,ListArray[ListPointer+2]));
  GObj.LabelTxt("Label20",StringFormat(str,ListPointer+3,ListArray[ListPointer+3]));
  GObj.LabelTxt("Label21",StringFormat(str,ListPointer+4,ListArray[ListPointer+4]));
  }

Le righe visualizzano i valori dei livelli dall'array ListArray[] formattato utilizzando la funzione StringFormat(). Secondo l'attuale modalità di visualizzazione, questo array è pieno di informazioni all'interno della funzione norm_and_draw(); vedere il file SpecAnalyzer.mq5. Le informazioni dell'array ListArray[] vengono visualizzate a partire dall'indice dell'array uguale al valore memorizzato nella variabile ListPointer. È possibile modificare il valore della variabile ListPointer, e quindi l'indice iniziale delle righe da visualizzare, premendo i pulsanti posti a destra del campo di output o specificando l'indice necessario nel campo di immissione. Gli eventi relativi alla pressione di quei pulsanti e al completamento delle modifiche sul campo di immissione sono gestiti nella funzione OnChartEvent() dell'indicatore; vedere il file SpecAnalyzer.mq5.

L'aspetto dell'indicatore SpecAnalyzer è mostrato nella figura seguente.

 Fig. 3. L'aspetto dell'indicatore SpecAnalyzer.

Fig. 3. L'aspetto dell'indicatore SpecAnalyzer.  

Conclusione

Come già accennato, l'indicatore SpecAnalyzer.mq5 è solo un prototipo di un analizzatore di spettro completo; nell'articolo viene utilizzato come esempio di utilizzo degli oggetti grafici. Per creare un indicatore completo, probabilmente dovrai migliorarne l'aspetto, implementare un'interfaccia più funzionale e migliorare l'algoritmo di stima dello spettro.

È possibile migliorare significativamente l'interfaccia dell'indicatore utilizzando l'oggetto grafico "Bitmap" per la sua decorazione, creando un'immagine per il suo pannello di controllo frontale in un editor grafico e utilizzandolo come sottostrato, su cui verranno visualizzati gli elementi di controllo. Tale approccio può essere utilizzato per creare indicatori con skin intercambiabili.

Letteratura

  1. Yukio Sato. Introduzione alla Gestione del Segnale.
  2. L. Rabiner, B. Gold. Teoria e Applicazione dell'Elaborazione Digitale dei Segnali.
  3. S.L. Marple, Jr. Analisi Spettrale Digitale con Applicazioni.

File

  1. SpecAnalyzer.mq5 – l'indicatore descritto in questo articolo.
  2. SpecAnalyzer.mqh: il file di inclusione per SpecAnalyzer.mq5.
  3. SAInpData.mq5 – l'indicatore utilizzato per l'organizzazione di un accesso a dati esterni.

 

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

File allegati |
SAInpData.mq5 (3.29 KB)
SpecAnalyzer.mq5 (15.39 KB)
SpecAnalyzer.mqh (20.79 KB)
Indicatori e Sistemi di Trading di William Blau in MQL5. Parte 1: Indicatori Indicatori e Sistemi di Trading di William Blau in MQL5. Parte 1: Indicatori
L'articolo presenta gli indicatori, descritti nel libro di William Blau "Momentum, Direction, and Divergence". L'approccio di William Blau ci consente di approssimare tempestivamente e accuratamente le fluttuazioni della curva dei prezzi, di determinare l'andamento dei movimenti dei prezzi e dei punti di svolta ed eliminare il rumore dei prezzi. Nel frattempo, siamo anche in grado di rilevare gli stati di ipercomprato/ipervenduto del mercato e segnali, che indicano la fine di una tendenza e l'inversione del movimento dei prezzi.
Media delle Serie di Prezzi per i Calcoli Intermedi Senza Utilizzare Buffer Aggiuntivi Media delle Serie di Prezzi per i Calcoli Intermedi Senza Utilizzare Buffer Aggiuntivi
Questo articolo riguarda gli algoritmi di media tradizionali e insoliti racchiusi in classi più semplici e di singolo tipo. Sono destinati all'uso universale in quasi tutti gli sviluppi degli indicatori. Spero che le lezioni suggerite siano una buona alternativa alle chiamate "ingombranti" di indicatori personalizzati e tecnici.
Uso delle Risorse in MQL5 Uso delle Risorse in MQL5
I programmi MQL5 non solo automatizzano i calcoli di routine, ma possono anche creare un ambiente grafico completo. Le funzioni per la creazione di controlli realmente interattivi sono ora virtualmente altrettanto ricche, come quelle nei classici linguaggi di programmazione. Se vuoi scrivere un programma autonomo completo in MQL5, utilizzare le risorse al loro interno. I programmi con risorse sono più facili da mantenere e distribuire.
Crea il tuo Market Watch usando le Classi Standard della Libreria Crea il tuo Market Watch usando le Classi Standard della Libreria
Il nuovo terminale client MetaTrader 5 e il linguaggio MQL5 offrono nuove opportunità per presentare informazioni visive al trader. In questo articolo, proponiamo un insieme di classi universale ed estensibile, che gestisce tutto il lavoro di organizzazione della visualizzazione delle informazioni di testo arbitrarie sul grafico. Viene presentato l'esempio dell'indicatore Market Watch.