English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Creazione di Indicatori di Tick in MQL5

Creazione di Indicatori di Tick in MQL5

MetaTrader 5Indicatori | 9 dicembre 2021, 13:28
229 0
Denis Zyatkevich
Denis Zyatkevich

Introduzione

Nel trading, sarebbe auspicabile avere quante più informazioni possibili per avere un quadro dettagliato delle variazioni di prezzo. Puoi usare il grafico tick. Proviamo a creare un grafico tick in MQL5.

Questo articolo, descrive la creazione di due indicatori: un grafico del prezzo tick e un grafico "Tick Candles", che disegna le candele che contengono un numero specificato di tick. Ciascuno degli indicatori considerati scrive i valori di prezzo ricevuti nel file per la costruzione dei dati dell'indicatore dopo il riavvio del client terminal (questi dati possono essere utilizzati anche dagli altri programmi).

Creazione dell'Indicatore Tick

Scriviamo un indicatore in MQL5 che disegna i dati tick sul grafico. Un esempio di questo indicatore viene mostrato in Fig.1:

Figura 1. Esempio di grafico tick

L'indicatore traccia due linee: Prezzi Bid e Ask. Il disegno di ciascuno di essi può essere disattivato nelle opzioni dell'indicatore.

L'indicatore salva i prezzi del simbolo corrente, ricevuti dal broker in un file di testo con il seguente formato: Server time, prezzo Bid e prezzo Ask:

2010.03.26 19:43:02 1.33955 1.33968

Il nome del file corrisponde al nome dello strumento finanziario (ad esempio, EURUSD.txt). I file si trovano nel seguente percorso: MT5_Folder\MQL5\Files. La directory aggiuntiva per un file e il prefisso del nome file possono essere specificati nelle opzioni dell'indicatore (può essere utile se ci sono più indicatori associati ai grafici con lo stesso simbolo).

Per creare un indicatore, avvia il client terminal MetaTrader 5 e avvia MetaQuotes Language Editor premendo il tasto F4. Iniziamo a scrivere il codice di un programma.

Specifichiamo che l'indicatore deve essere tracciato in una finestra separata sotto il grafico dei prezzi:

// indicator in a separate window
#property indicator_separate_window

Si devono disegnare le due linee dell’indicatore (rispettivamente, prezzi Bid e Ask), quindi dobbiamo utilizzare due grafici:

// two graphic plots are used: for Bid and Ask lines
#property indicator_plots 2

Dobbiamo specificare due buffer di indicatori, contenenti i dati da tracciare sul grafico:

// two indicator's buffers
#property indicator_buffers 2

Per ciascuna delle linee dell'indicatore, definiamo il tipo di disegno DRAW_LINE (linea), lo stile di disegno STYLE_SOLID (linea continua) e le etichette di testo "Bid" e "Ask":

// drawing type of a Bid line
#property indicator_type1 DRAW_LINE
// drawing color of a Bid line
#property indicator_color1 Red
// drawing style of a Bid line
#property indicator_style1 STYLE_SOLID
// text label of a Bid line
#property indicator_label1 "Bid"
// drawing type of an Ask line
#property indicator_type2 DRAW_LINE
// drawing color of an Ask line
#property indicator_color2 Blue
// drawing style of an Ask line
#property indicator_style2 STYLE_SOLID
// text label of an Ask line
#property indicator_label2 "Ask"

 Specifichiamo le variabili di input, i cui valori possono essere modificati dall'utente nel menu delle opzioni dell'indicatore.

// the BidLineEnable indicates showing of a Bid line
input bool BidLineEnable=true; // Show Bid Line
// the AskLineEnable indicates showing of an Ask line
input bool AskLineEnable=true; // Show Ask Line
// the path_prefix defines a path and file name prefix
input string path_prefix=""; // FileName Prefix

Le variabili BidLineEnable e AskLineEnable consentono di abilitare e disabilitare la visualizzazione delle linee Bid e Ask nell'indicatore. La variabile path_prefix consente di specificare il prefisso del nome del file che si trova prima del nome del file. Utilizzando questa variabile, puoi anche specificare il percorso di una sottodirectory, ad esempio, se path_prefix = "MyBroker/test_", il percorso dei file sarà il seguente: "MetaTrader5_Folder\MQL5\Files\MyBroker", per il simbolo "EURUSD" il nome del file sarà "test_EURUSD.txt".

A livello globale, dichiariamo le variabili che verranno utilizzate in varie funzioni dell'indicatore, i valori di queste variabili vengono salvati tra le chiamate dell'indicatore:

// the tick_stored variable is a number of served quotes
int ticks_stored;
// the BidBuffer[] and AskBuffer[] arrays - are indicator's buffers
double BidBuffer[],AskBuffer[];

La variabile tick_stored verrà utilizzata per memorizzare il numero di quotazioni disponibili. BidBuffer[] e AskBuffer[] sono array dinamici, utilizzati come buffer indicatori, i dati sui prezzi tracciati sul grafico come linee Bid e Ask, sono memorizzati in questi buffer.

La funzione OnInit indica che gli array BidBuffer[] e AskBuffer[] contengono i dati per il tracciato. Specifichiamo che i dati con valori dell'indicatore buffer, pari a zero, non devono essere tracciati sul grafico.

void OnInit()
  {
   // the BidBuffer[] is an indicator buffer
   SetIndexBuffer(0,BidBuffer,INDICATOR_DATA);
   // the AskBuffer[] is an indicator buffer
   SetIndexBuffer(1,AskBuffer,INDICATOR_DATA);
   // setting EMPTY_VALUE for a Bid line
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0);
   // setting EMPTY_VALUE for an Ask line
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0);
  }

Ora creiamo la funzione OnCalculate ed elenchiamo tutti i parametri passati alla funzione quando è stata chiamata: 

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[])

Dichiariamo le variabili:

// the file_handle variable is a file handle
// the BidPosition and AskPosition - are positions of Bid and Ask prices in the string;
// the line_string_len is a length of a string, read from the file, i is a loop counter;
int file_handle,BidPosition,AskPosition,line_string_len,i;
// the last_price_bid is the last Bid quote
double last_price_bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
// the last_price_ask is the last Ask quote
double last_price_ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
// the filename is a name of a file, the file_buffer is a string, 
// used as a buffer for reading and writing of string data
string filename,file_buffer;

La variabile file_handle di tipo intero verrà utilizzata per memorizzare l'handle del file nelle operazioni sui file, le BidPosition e AskPosition - verranno utilizzate per la memorizzazione dei prezzi Bid e Ask delle posizioni iniziali nella stringa, verrà utilizzata la line_string_len - per la lunghezza della stringa, letta dal file, la variabile i sarà utilizzata come contatore di loop. I valori degli ultimi prezzi Bid e Ask ricevuti sono memorizzati nelle variabili last_price_bid e last_price_ask. La variabile stringa nome file viene utilizzata per memorizzare il nome del file, il file_bufferè una stringa utilizzata per la lettura e la scrittura sul file.

Il nome del file è costituito dalla variabile path_prefix, nome dello strumento finanziario ed estensione del file ".txt". L'uso della funzione StringConcatenate è più conveniente rispetto alla concatenazione di stringhe utilizzando l'operatore di addizione, perché funziona più velocemente ed è più economico sulla memoria.

// File name formation from the path_prefix variable, name
// of financial instrument and ".Txt" symbols
StringConcatenate(filename,path_prefix,Symbol(),".txt");

Apriamo il file utilizzando la funzione FileOpen per un suo ulteriore utilizzo:

// Opening a file for reading and writing, codepage ANSI, shared reading mode
file_handle=FileOpen(filename,FILE_READ|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ);

Usiamo i flag FILE_READ e FILE_WRITE, perché leggeremo e scriveremo i dati nel file, il flag FILE_ANSI indica che verrà utilizzata la codepage ANSI (l'impostazione predefinita è Unicode), il flag FILE_SHARE_READ significa che l'accesso condiviso è consentito per la lettura dalle altre applicazioni mentre si lavora con esso.

Al primo avvio dell'indicatore non ci sono dati (o il periodo del grafico è stato modificato):

 // At first execution of OnCalculate function, we are reading the quotes from a file
 if(prev_calculated==0)
  {
   // Reading the first line from the file and determine the length of a string
   line_string_len=StringLen(FileReadString(file_handle))+2;
   // if file is large (contains more quotes than rates_total/2)
   if(FileSize(file_handle)>(ulong)line_string_len*rates_total/2)
     {
      // Setting file pointer to read the latest rates_total/2 quotes
      FileSeek(file_handle,-line_string_len*rates_total/2,SEEK_END);
      // Moving file pointer to the beginning of the next line
      FileReadString(file_handle);
     }
   // if file size is small
   else
     {
      // Moving file pointer at the beginning of a file
      FileSeek(file_handle,0,SEEK_SET);
     }
   // Reset the counter of stored quotes
   ticks_stored=0;
   // Reading until the end of the file
   while(FileIsEnding(file_handle)==false)
    {
      // Reading a string from the file
      file_buffer=FileReadString(file_handle);
      // Processing of string if its length is larger than 6 characters
      if(StringLen(file_buffer)>6)
        {
         // Finding the start position of Bid price in the line
         BidPosition=StringFind(file_buffer," ",StringFind(file_buffer," ")+1)+1;
         // Finding the start position of Ask price in the line
         AskPosition=StringFind(file_buffer," ",BidPosition)+1;
         // If the Bid line should be plotted, adding this value to BidBuffer[] array
         if(BidLineEnable) 
         BidBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,BidPosition,AskPosition-BidPosition-1));
         // If the Ask line should be plotted, adding this value to AskBuffer[] array
         if(AskLineEnable) 
         AskBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,AskPosition));
         // Increasing the counter of stored quotes
         ticks_stored++;
        }
     }
  }

Limiteremo il numero di quotazioni, che dovrebbero essere lette dal file alla metà di un numero di barre sul grafico. Innanzitutto, leggiamo la stringa dal file e ne determiniamo la lunghezza. Alla fine di una riga ci sono due caratteri aggiuntivi con i codici 10 e 13 ("newline" e "carriage return"), quindi dobbiamo aumentare la lunghezza della riga di 2.

Assumiamo che la lunghezza media delle righe rimanenti del file sia la stessa. Se la lunghezza del file è maggiore del prodotto della lunghezza di una riga sul numero di rate_total/2 (cioè, se il file contiene più virgolette di rate_total/2), leggeremo solo le ultime quotazioni rate_total/2 Per farlo, impostiamo il puntatore del file alla distanza uguale al prodotto di una lunghezza di stringa per rate_total/2 (dalla fine del file) e leggiamo una riga dal file per allineare il puntatore del file all'inizio di una riga .

Notare che confrontiamo due valori usando l'operatore if, hanno tipi diversi: la lunghezza del file è di tipo ulong, l'espressione a destra ha il tipo int. Pertanto eseguiamo il typecasting esplicito dell'espressione del lato destro al tipo ulong.

Se il file contiene meno quotazioni, rispetto a rates_total/2, spostiamo il puntatore del file all'inizio del file. 

Impostiamo il contatore delle quotazioni a zero e leggiamo le righe da un file, fino a raggiungere la fine di un file. L'elaborazione delle stringhe viene eseguita per le stringhe la cui lunghezza è maggiore di sei caratteri - è una lunghezza minima della stringa, che contiene un carattere per la data, ora, bid e ask e i separatori tra di loro. Estraiamo i valori Bid e Ask da una stringa, leggiamo dal file se la riga corrispondente deve essere tracciata e aumentiamo il contatore delle quotazioni.

Se i dati sono stati letti in precedenza, spostiamo il puntatore del file alla fine del file utilizzando la funzione FileSeek (i nuovi dati vengono scritti nel file). Utilizzando la funzione StringConcatenate, generiamo la stringa che verrà scritta in un file utilizzando la funzione FileWrite. Aggiungiamo i nuovi valori dei prezzi Bid e Ask agli array BidBuffer[] e AskBuffer[], se la riga corrispondente deve essere tracciata e aumentiamo il contatore delle quotazioni.

  // If the data have been read before
else
  {
   // Moving file pointer at the end of the file
   FileSeek(file_handle,0,SEEK_END);
   // Forming a string, that should be written to the file
   StringConcatenate(file_buffer,TimeCurrent()," ",DoubleToString(last_price_bid,_Digits)," ",DoubleToString(last_price_ask,_Digits));
   // Writing a string to the file
   FileWrite(file_handle,file_buffer);
   // If the Bid line should be plotted, adding the last Bid price to the BidBuffer[] array
   if(BidLineEnable) BidBuffer[ticks_stored]=last_price_bid;
   // If the Ask line should be plotted, adding the last Ask price to the AskBuffer[] array
   if(AskLineEnable) AskBuffer[ticks_stored]=last_price_ask;
   // Increasing the quotes counter
   ticks_stored++;
  }

Ci si potrebbe chiedere: perché non leggi i dati da un file all'interno della funzione OnInit? Il motivo è il seguente: la lunghezza degli array dinamici BidBuffer[] e AskBuffer[] non è stata definita, è stata specificata quando viene chiamata la funzione OnCalculate.

Chiudiamo il file aperto in precedenza :

// Closing the file
FileClose(file_handle);

Nel caso in cui il contatore delle quotazioni sarà uguale o maggiore del numero di barre sul grafico, dopo la lettura da file o dopo l'aggiunta agli array BidBuffer[] e AskBuffer[], la metà delle vecchie quotazioni verrà rimossa e le restanti verranno spostate al loro posto.

// If number of quotes is more or equal than number of bars in the chart
if(ticks_stored>=rates_total)
  {
   // Removing the first tick_stored/2 quotes and shifting remaining quotes
   for(i=ticks_stored/2;i<ticks_stored;i++)
     {
      // If the Bid line should be plotted, shifting the values of BidBuffer[] array on tick_stored/2
      if(BidLineEnable) BidBuffer[i-ticks_stored/2]=BidBuffer[i];
      // If the Ask line should be plotted, shifting the values of AskBuffer[] array on tick_stored/2
      if(AskLineEnable) AskBuffer[i-ticks_stored/2]=AskBuffer[i];
     }
   // Changing the value of a counter
   ticks_stored-=ticks_stored/2;
  }

Gli array BidBuffer[] e AskBuffer[] dei buffer degli indicatori non sono serie temporali, quindi l'elemento recente ha indice uguale a ticks_stored-1, il grafico recente ba ha indice uguale a rates_total-1. Per combinarli allo stesso livello, spostiamo la linea dell'indicatore utilizzando la funzione PlotIndexSetInteger:

// Shifting the Bid line to align with the price chart
PlotIndexSetInteger(0,PLOT_SHIFT,rates_total-ticks_stored);
// Shifting the Ask line to align with the price chart
PlotIndexSetInteger(1,PLOT_SHIFT,rates_total-ticks_stored);

I valori dei prezzi recenti ricevuti vengono memorizzati in BidBuffer[] e AskBuffer[] con l’ indice uguale a rate_total-1 (se le linee corrispondenti devono essere tracciate) per mostrarli nell'angolo in alto a sinistra della finestra dell’indicatore.

// If the Bid line should be plotted, placing the value to the last element 
// of BidBuffer [] array to show the last Bid price in the indicator's window  
if(BidLineEnable) BidBuffer[rates_total-1]=last_price_bid;
// If the Ask line should be plotted, placing the value to the last element 
// of AskBuffer [] array to show the last Ask price in the indicator's window
if(AskLineEnable) AskBuffer[rates_total-1]=last_price_ask;

L'esecuzione della funzione OnCalculate viene completata dalla restituzione di rate_total (puoi restituire qualsiasi numero diverso da zero), il codice della funzione termina con una parentesi graffa.

// Return from OnCalculate(), return a value, different from zero   
return(rates_total);
}

L'indicatore Tick è stato scritto. Il codice sorgente completo dell'indicatore può essere scaricato al link che si trova alla fine dell'articolo.

Creazione dell'indicatore "Tick Candle"

Ora scriviamo un indicatore che traccia le cosiddette "tick candle". A differenza del grafico a candele convenzionale, dove ogni candela corrisponde al periodo di tempo specificato, il grafico "Tick Candle" ha una struttura diversa: ogni candela ha un numero predefinito di tick, ricevuti dal broker (candele equivolume). Questo indicatore appare come mostrato nella Figura 2:


Figura 2. L'indicatore "Tick Candle"

L'indicatore "Tick Candle", così come l'indicatore tick, considerato sopra, scrive tutte le quotazioni in arrivo nel file. Il formato dei dati e i dettagli sulla posizione del file sono gli stessi. Il percorso del file, il prefisso del nome, il numero di tick per una candela e il tipo di prezzo (Bid o Ask) possono essere specificati nelle opzioni dell'indicatore.

Per creare un indicatore, avvia il client terminal MetaTrader 5 e avvia MetaQuotes Language Editor premendo il tasto F4.

Specifichiamo che dovrebbe essere tracciato in una finestra separata:

// Indicator is plotted in a separate window
#property indicator_separate_window

L'indicatore ha un solo grafico: le candele colorate.

// One graphic plot is used, color candles
#property indicator_plots 1

Abbiamo bisogno di quattro buffer per la visualizzazione delle candele colorate e per la memorizzazione dei valori dei dati di prezzo (apertura, massima, minima e chiusura) del prezzo di ciascuna candela. Inoltre, abbiamo bisogno di un buffer aggiuntivo per memorizzare gli indici di colore delle candele.

// We need 4 buffers for OHLC prices and one - for the index of color
#property indicator_buffers 5

Specifichiamo il tipo di disegno: DRAW_COLOR_CANDLES - candele colorate.

// Specifying the drawing type - color candles
#property indicator_type1 DRAW_COLOR_CANDLES

Specifichiamo i colori che verranno utilizzati per le candele:

// Specifying the colors for the candles
#property indicator_color1 Gray,Red,Green

Creiamo il price_types del tipo di enumerazione contenente uno dei seguenti valori: Bid o Ask:

/ / Declaration of the enumeration
enum price_types
  (
   Bid,
   Ask
  )

Specifichiamo i parametri di input che possono essere modificati dall'utente dal menu delle opzioni dell'indicatore:

// The ticks_in_candle input variable specifies the number of ticks,
// corresponding to one candle
input int ticks_in_candle=16; //Tick Count in Candles
// The applied_price input variable of price_types type indicates 
// the type of the data, that is used in the indicator: Bid or Ask prices.
input price_types applied_price=0; // Price
// The path_prefix input variable specifies the path and prefix to the file name
input string path_prefix=""; // FileName Prefix

La variabile ticks_in_candle specifica il numero di tick corrispondenti a una candela. La variabile apply_price indica il tipo di prezzo utilizzato per la costruzione delle candele: Bid o Ask. La directory e il prefisso del nome file del file per i dati cronologici dei tick possono essere specificati nella variabile path_prefix.

Le variabili con valori, che dovrebbero essere salvate tra le chiamate dell'indicatore, sono dichiarate a livello globale.

// The ticks_stored variable contains the number of stored quotes
int ticks_stored;
// The TicksBuffer [] array is used to store the incoming prices
// The OpenBuffer [], HighBuffer [], LowBuffer [] and CloseBuffer [] arrays
// are used to store the OHLC prices of the candles
// The ColorIndexBuffer [] array is used to store the index of color candles
double TicksBuffer[],OpenBuffer[],HighBuffer[],LowBuffer[],CloseBuffer[],ColorIndexBuffer[];

La variabile ticks_stored viene utilizzata per memorizzare il numero di quotazioni disponibili. L'array TicksBuffer[] viene utilizzato per memorizzare le quotazioni ricevute, gli array OpenBuffer[], HighBuffer[], LowBuffer[] e CloseBuffer[] vengono utilizzati per memorizzare i prezzi delle candele (apertura, massimo, minimo e chiusura), che verrà tracciato sul grafico. L'array ColorIndexBuffer[] viene utilizzato per memorizzare l'indice di colore delle candele.

La funzione OnInit indica che gli array OpenBuffer[], HighBuffer[], LowBuffer[] e CloseBuffer[] vengono utilizzati come buffer di un indicatore, l'array ColorIndexBuffer[] contiene un indice di colore delle candele, l'array TicksBuffer[] viene utilizzato per calcoli intermedi:

void OnInit()
  {
   // The OpenBuffer[] array is an indicator buffer
   SetIndexBuffer(0,OpenBuffer,INDICATOR_DATA);
   // The HighBuffer[] array is an indicator buffer
   SetIndexBuffer(1,HighBuffer,INDICATOR_DATA);
   // The LowBuffer[] array is an indicator buffer
   SetIndexBuffer(2,LowBuffer,INDICATOR_DATA);
   // The CloseBuffer[] array is an indicator buffer
   SetIndexBuffer(3,CloseBuffer,INDICATOR_DATA);
   // The ColorIndexBuffer[] array is the buffer of the color index
   SetIndexBuffer(4,ColorIndexBuffer,INDICATOR_COLOR_INDEX);
   // The TicksBuffer[] array is used for intermediate calculations
   SetIndexBuffer(5,TicksBuffer,INDICATOR_CALCULATIONS);

Successivamente, specifichiamo gli array OpenBuffer[], HighBuffer[], LowBuffer[], CloseBuffer[] e ColorIndexBuffer[] come serie temporali (cioè i dati più recenti hanno indice 0):

   // The indexation of OpenBuffer[] array as timeseries
   ArraySetAsSeries(OpenBuffer,true);
   // The indexation of HighBuffer[] array as timeseries
   ArraySetAsSeries(HighBuffer,true);
   // The indexation of LowBuffer[] array as timeseries
   ArraySetAsSeries(LowBuffer,true);
   // The indexation of CloseBuffer[] array as timeseries
   ArraySetAsSeries(CloseBuffer,true);
   // The indexation of the ColorIndexBuffer [] array as timeseries
   ArraySetAsSeries(ColorIndexBuffer,true);

I valori dei buffer dell'indicatore pari a 0, non devono essere tracciati sul grafico:

   // The null values of Open prices (0th graphic plot) should not be plotted
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0);
   // The null values of High prices (1st graphic plot) should not be plotted
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0);
   // The null values of Low prices (2nd graphic plot) should not be plotted
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,0);
   // The null values of Close prices (3rd graphic plot) should not be plotted
   PlotIndexSetDouble(3,PLOT_EMPTY_VALUE,0);

Completata la scrittura della funzione OnInitchiudiamo la funzione utilizzando una parentesi graffa.

È ora di scrivere la funzione OnCalculate. Specifichiamo tutti i parametri passati alla funzione:

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[])
  {

Dichiariamo le variabili che verranno utilizzate nella funzione OnInit.

// the file_handle variable is a file handle
// the BidPosition and AskPosition - are positions of Bid and Ask prices in the string;
// the line_string_len is a length of a string, read from the file, 
// CandleNumber - number of candle, for which the prices OHLC are determined,
// i - loop counter;
int file_handle,BidPosition,AskPosition,line_string_len,CandleNumber,i;
// The last_price_bid variable is the recent received Bid price
double last_price_bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
// The last_price_ask variable is the recent received Ask price
double last_price_ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
// the filename is a name of a file, the file_buffer is a string, 
// used as a buffer for reading and writing of string data
string filename,file_buffer;

La variabile file_handle di tipo intero viene utilizzata per memorizzare l'handle del file nelle operazioni sui file, la BidPosition e AskPosition vengono utilizzate per memorizzare le posizioni iniziali dei prezzi Bid e Ask nella stringa, la line_string_len è una lunghezza di stringa, letta da un file , il CandleNumber - è l'indice della candela calcolata, la variabile i viene utilizzata come contatore di loop.

I prezzi Bid e Ask ricevuti di recente vengono memorizzati nelle variabili last_price_bid e last_price_ask di tipo doppio. La variabile filename di un tipo stringa viene utilizzata per memorizzare il nome di un file, il file_buffer è una stringa utilizzata nelle operazioni sui file.

La dimensione dell'array TicksBuffer[] non viene impostata automaticamente, a differenza degli array OpenBuffer[], HighBuffer[], LowBuffer[], CloseBuffer[] e ColorIndexBuffer[] che sono buffer dell'indicatore, quindi impostiamo la dimensione di un array TicksBuffer [] uguale alla dimensione degli array OpenBuffer[], HighBuffer[], LowBuffer[], CloseBuffer[] e ColorIndexBuffer[]:

// Setting the size of TicksBuffer[] array
ArrayResize(TicksBuffer,ArraySize(CloseBuffer));

Preparare il nome del file dalla variabile path_prefix, nome dello strumento finanziario ed estensione ".txt":

// File name formation from the path_prefix variable, name
// of financial instrument and ".Txt" symbols
StringConcatenate(filename,path_prefix,Symbol(),".txt");

Apriamo il file con i parametri, descritto sopra per l'indicatore precedente.

// Opening a file for reading and writing, codepage ANSI, shared reading mode
file_handle=FileOpen(filename,FILE_READ|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ);

Se la funzione OnCalculate viene chiamata la prima volta e non ci sono dati nell'array TicksBuffer[], li leggiamo dal file:

if(prev_calculated==0)
  {
   // Reading the first line from the file and determine the length of a string
   line_string_len=StringLen(FileReadString(file_handle))+2;
   // if file is large (contains more quotes than rates_total/2)
   if(FileSize(file_handle)>(ulong)line_string_len*rates_total/2)
     {
      // Setting file pointer to read the latest rates_total/2 quotes
      FileSeek(file_handle,-line_string_len*rates_total/2,SEEK_END);
      // Moving file pointer to the beginning of the next line
      FileReadString(file_handle);
     }
   // if file size is small
   else
     {
      // Moving file pointer at the beginning of a file
      FileSeek(file_handle,0,SEEK_SET);
     }
   // Reset the counter of stored quotes
   ticks_stored=0;
   // Reading until the end of the file
   while(FileIsEnding(file_handle)==false)
     {
      // Reading a string from thefile
      file_buffer=FileReadString(file_handle);
      // Processing of string if its length is larger than 6 characters
      if(StringLen(file_buffer)>6)
        {
         // Finding the start position of Bid price in the line
         BidPosition=StringFind(file_buffer," ",StringFind(file_buffer," ")+1)+1;
          //Finding the start position of Ask price in the line
         AskPosition=StringFind(file_buffer," ",BidPosition)+1;
         // If the Bid prices are used, adding the Bid price to TicksBuffer[] array
         if(applied_price==0)
         TicksBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,BidPosition,AskPosition-BidPosition-1));
         // If the Ask prices are used, adding the Ask price to TicksBuffer[] array
         if(applied_price==1)
         TicksBuffer[ticks_stored]=StringToDouble(StringSubstr(file_buffer,AskPosition));
         // Increasing the counter of stored quotes
         ticks_stored++;
        }
     }
  }

La lettura delle quotazioni dal file è stata descritta sopra in modo più dettagliato, è la stessa dell'indicatore precedente.

Se le quotazioni sono state lette in precedenza nell'array TicksBuffer[], scriviamo un nuovo valore di prezzo nel file, posizioniamo un nuovo prezzo nell'array TicksBuffer[] e aumentiamo il contatore delle quotazioni:

// If the data have been read before
else
  {
   // Moving file pointer at the end of the file
   FileSeek(file_handle,0,SEEK_END);
   // Forming a string, that should be written to the file
   StringConcatenate(file_buffer,TimeCurrent()," ",DoubleToString(last_price_bid,_Digits)," ",DoubleToString(last_price_ask,_Digits));
   // Writing a string to the file
   FileWrite(file_handle,file_buffer);
   // If the Bid prices are used, adding the last Bid price to TicksBuffer[] array
   if(applied_price==0) TicksBuffer[ticks_stored]=last_price_bid;
   // If the Ask prices are used, adding the last Ask price to TicksBuffer[] array
   if(applied_price==1) TicksBuffer[ticks_stored]=last_price_ask;
   // Increasing the quotes counter
   ticks_stored++;
  }

Chiusura del file:

// Closing the file
FileClose(file_handle);

Se il numero di quotazioni memorizzate raggiunge il numero di barre sul grafico dei prezzi o diventa più alto, rimuoviamo la metà dei dati più vecchi e spostiamo i dati rimanenti:

// If number of quotes is more or equal than number of bars in the chart
if(ticks_stored>=rates_total)
  {
   // Removing the first tick_stored/2 quotes and shifting remaining quotes
   for(i=ticks_stored/2;i<ticks_stored;i++)
     {
      // Shifting the data to the beginning in the TicksBuffer[] array on tick_stored/2
      TicksBuffer[i-ticks_stored/2]=TicksBuffer[i];
     }
   // Changing the quotes counter
   ticks_stored-=ticks_stored/2;
  }

Calcoliamo i valori OHLC per ogni candela e posizioniamo questi valori nei corrispondenti buffer indicatori:

   // We assign the CandleNumber with a number of invalid candle
   CandleNumber=-1;
   // Search for all the price data available for candle formation
   for(i=0;i<ticks_stored;i++)
     {
      // If this candle is forming already
      if(CandleNumber==(int)(MathFloor((ticks_stored-1)/ticks_in_candle)-MathFloor(i/ticks_in_candle)))
        {
         // The current quote is still closing price of the current candle
         CloseBuffer[CandleNumber]=TicksBuffer[i];
         // If the current price is greater than the highest price of the current candle,
          // it will be a new highest price of the candle
         if(TicksBuffer[i]>HighBuffer[CandleNumber]) HighBuffer[CandleNumber]=TicksBuffer[i];
         // If the current price is lower than the lowest price of the current candle, 
          // it will be a new lowest price of the candle
         if(TicksBuffer[i]<LowBuffer[CandleNumber]) LowBuffer[CandleNumber]=TicksBuffer[i];
         // If the candle is bullish, it will have a color with index 2 (green)
         if(CloseBuffer[CandleNumber]>OpenBuffer[CandleNumber]) ColorIndexBuffer[CandleNumber]=2;
         // If the candle is bearish, it will have a color with index 1 (red)
         if(CloseBuffer[CandleNumber]<OpenBuffer[CandleNumber]) ColorIndexBuffer[CandleNumber]=1;
         // If the opening and closing prices are equal, then the candle will have a color with index 0 (grey)
         if(CloseBuffer[CandleNumber]==OpenBuffer[CandleNumber]) ColorIndexBuffer[CandleNumber]=0;
        }
      // If this candle hasn't benn calculated yet
      else
        {
         // Let's determine the index of a candle
         CandleNumber=(int)(MathFloor((ticks_stored-1)/ticks_in_candle)-MathFloor(i/ticks_in_candle));
         // The current quote will be the opening price of a candle
         OpenBuffer[CandleNumber]=TicksBuffer[i];
         // The current quote will be the highest price of a candle
         HighBuffer[CandleNumber]=TicksBuffer[i];
         // The current quote will be the lowest price of a candle
         LowBuffer[CandleNumber]=TicksBuffer[i];
         // The current quote will be the closing price of a candle
         CloseBuffer[CandleNumber]=TicksBuffer[i];
         // The candle will have a color with index 0 (gray)
         ColorIndexBuffer[CandleNumber]=0;
        }
     }

L'esecuzione della funzione OnCalculate viene completata ripristinando un valore diverso da zero, il che significa che l’array TicksBuffer[] ha già i dati e non è necessario leggerli alla prossima chiamata della funzione. Mettiamo la parentesi graffa di chiusura alla fine della funzione

 // Return from OnCalculate(), return a value, different from zero   
 return(rates_total);
}

Alla fine dell'articolo, c'è un link che può essere utilizzato per scaricare il codice sorgente completo dell'indicatore.

Conclusione

In questo articolo, abbiamo considerato la creazione di due indicatori tick: l'indicatore grafico tick e l'indicatore "tick candles".

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

File allegati |
tickindicator.mq5 (8.28 KB)
Nuove Opportunità con MetaTrader 5 Nuove Opportunità con MetaTrader 5
MetaTrader 4 ha guadagnato la sua popolarità tra i trader di tutto il mondo e sembrava che non si potesse desiderare di più. Con la sua elevata velocità di elaborazione, stabilità, ampia gamma di possibilità per la scrittura di indicatori, Expert Advisor e sistemi di trading informativo, e la possibilità di scegliere tra oltre un centinaio di broker diversi, - il terminale si è notevolmente distinto dal resto. Tuttavia, il tempo non si ferma e ci troviamo di fronte a una scelta da compiere tra MetaTrade 4 e MetaTrade 5. In questo articolo, descriveremo le principali differenze del terminale di 5a generazione dal nostro attuale favore.
Gli stili di Disegno in MQL5 Gli stili di Disegno in MQL5
Ci sono 6 stili di disegno in MQL4 e 18 stili di disegno in MQL5. Pertanto, potrebbe valere la pena scrivere un articolo per inserire gli stili di disegno di MQL5. In questo articolo, considereremo i dettagli degli stili di disegno in MQL5. Inoltre, creeremo un indicatore per dimostrare come utilizzare questi stili di disegno e per perfezionare la stampa.
Guida Step-By-Step alla scrittura di un Expert Advisor in MQL5 per Principianti Guida Step-By-Step alla scrittura di un Expert Advisor in MQL5 per Principianti
La programmazione di Expert Advisors in MQL5 è semplice e puoi impararla facilmente. In questa guida step by step, vedrai i passaggi fondamentali necessari per scrivere un semplice Expert Advisor basato su una strategia di trading sviluppata. Vengono presentati la struttura di un Expert Advisor, l'uso di indicatori tecnici integrati e funzioni di trading, i dettagli della modalità Debug e l'uso dello Strategy Tester.
Come chiamare gli indicatori in MQL5 Come chiamare gli indicatori in MQL5
Con la nuova versione del linguaggio di programmazione MQL disponibile non solo è cambiato l'approccio alla gestione degli indicatori, ma ci sono anche nuovi modi di creare gli indicatori. Inoltre, hai una maggiore flessibilità lavorando con i buffer dell'indicatore: ora puoi specificare la direzione di indicizzazione desiderata e ottenere esattamente tutti i valori dell'indicatore che desideri. Questo articolo spiega i metodi di base per chiamare gli indicatori e recuperare i dati dai buffer dell'indicatore.