- Direzione di Indicizzazione negli Array, Buffers e TimeSeries
- Organizzazione di Accesso ai Dati
- SeriesInfoInteger
- Bars
- BarsCalculated
- IndicatorCreate
- IndicatorParameters
- IndicatorRelease
- CopyBuffer
- CopyRates
- CopySeries
- CopyTime
- CopyOpen
- CopyHigh
- CopyLow
- CopyClose
- CopyTickVolume
- CopyRealVolume
- CopySpread
- CopyTicks
- CopyTicksRange
- iBars
- iBarShift
- iClose
- iHigh
- iHighest
- iLow
- iLowest
- iOpen
- iTime
- iTickVolume
- iRealVolume
- iVolume
- iSpread
Organizzazione di Accesso ai Dati
In this section questions connected with obtaining, storing and requesting price data (timeseries) are considered.
Ricezione dei Dati da un Trade Server
Prima che i dati sui prezzi saranno disponibili nel terminale MetaTrader 5, devono essere ricevuti ed elaborati. Per ricevere i dati, deve essere stabilita la connessione al trade server MetaTrader 5. I dati vengono ricevuti sotto forma di blocchi compatti di barre minute, dal server su richiesta del terminale.
Il meccanismo di riferimento server per i dati non dipende da come la richiesta è stata avviata - da un utente durante la navigazione nel grafico o in modo con il programma nella linguaggio MQL5.
Memorizzazione di Dati Intermedi
I dati ricevuti da un server vengono automaticamente decompressi e salvati nella formato intermedio HCC. I dati su ogni simbolo vengono scritti in una cartella separata: terminal_directory\bases\server_name\history\symbol_name. Per esempio, i dati relativi ad EURUSD ricevuti dal server MetaQuotes-Demo verranno memorizzati in terminal_directory\bases\MetaQuotes-Demo\history\EURUSD\.
I dati vengono scritti in file con estensione .hcc . Ogni file memorizza i dati delle barre minute per un anno. Ad esempio, il file denominato 2009.hcc nella cartella EURUSD contiene barre minute di EURUSD per l'anno 2009. Questi file vengono utilizzati per la preparazione di dati sui prezzi per tutti i timeframes e non sono destinati per l'accesso diretto.
Recupero dei Dati in un Timeframe Necessario su Dati Intermedi
File intermedi HCC vengono utilizzati come fonte di dati per la creazione di dati sui prezzi per i timeframe richiesti nel formato HCC. I dati di formato HCC sono timeseries che sono preparate massimalmente per un accesso rapido. Essi vengono creati su richiesta di un grafico o di un programma MQL5. Il volume dei dati non deve superare il valore del parametro "Max barre nei grafici". I dati sono conservati per un ulteriore utilizzo in file con estensione hcc.
Per risparmiare le risorse, i dati su un timeframe vengono memorizzati e salvati nella RAM solo se necessario. Se non vengono chiamati per lungo tempo, vengono rilasciati dalla RAM e salvati in un file. Per ogni timeframe, i dati vengono preparati indipendentemente dal fatto che ci sono dati pronti per altri timeframes o meno. Le regole di formazione ed accesso ai dati sono gli stessi per tutti i timeframes. Significa, che nonostante il fatto che i dati memorizzati in unità HCC siano nn minuto, la disponibilità di dati HCC non significa la disponibilità di dati sulla tempistica M1 come HC nello stesso volume.
La ricezione di nuovi dati da un server chiama l'aggiornamento automatico dei dati sui prezzi utilizzati in formato HC di tutti i timeframes. Essa comporta anche il ricalcolo di tutti gli indicatori che implicitamente li utilizzano come dati di input per i calcoli.
Parametro "Max barre nel grafico"
Il parametro "Max barre nei grafici" limita il numero di barre in formato HC a disposizione di grafici, indicatori e programmi MQL5. Questo è valido per tutti i timeframe disponibili e serve, prima di tutto, per risparmiare risorse informatiche.
Quando si imposta un valore elevato di questo parametro, va ricordato, che se sono disponibili dati storici in profondità per piccoli timeframes, la memoria utilizzata per la memorizzazione dei buffers di timeseries ed indicatori, possono diventare centinaia di megabyte e raggiungere la restrizione RAM per il programma del terminale client (2Gb per applicazioni a 32 bit di MS Windows).
La modifica di "Max barre nei grafici" avrà effetto dopo che il terminale client viene riavviato. Il cambio di questo parametro causa né il riferimento automatico ad un server per i dati aggiuntivi, né formazione di barre aggiuntive di di timeseries. Dati relativi ai prezzi aggiuntivi vengono richiesti dal server, e le timeseries vengono aggiornate tenendo conto della nuova limitazione, in caso di uno scorrimento del grafico all'area senza dati, o quando i dati vengono richiesti da un programma MQL5.
Volume dei dati richiesti dal server corrisponde al numero di barre richiesto di questo timeframe con il parametro "Max barre nel grafico" preso in considerazione. La restrizione impostata da questo parametro non è rigida, e in alcuni casi il numero di barre disponibili per un periodo di tempo può essere un po' di più del valore corrente del parametro.
Disponibilità dati
La presenza di dati su formato HCC o anche in preparazione per l'utilizzo del formato HC, non sempre denota la disponibilità assoluta di tali dati da visualizzare nel chart o da utilizzare in programmi MQL5.
Quando si accede ai dati sui prezzi o valori degli indicatori da un programma MQL5 va ricordato che la loro disponibilità in un certo istante di tempo o a partire da un certo momento di tempo non è garantita. E' collegato con il fatto che con il fine di risparmiare risorse, la copia completa di dati necessari per un programma MQL5 non è memorizzata in MetaTrader 5; viene dato solo l'accesso diretto al database terminale.
La cronistoria dei prezzi per tutti i timeframes è costruita a partire da dati comuni di formato HCC, e qualsiasi aggiornamento dei dati da un server conduce all'aggiornamento dei dati per tutti i timeframes e al ricalcolo degli indicatori. A causa di tale accesso ai dati, può essere chiusa, anche se questi dati erano disponibili poc'anzi.
Sincronizzazione dei Dati Terminale e Dati Server #
Sicchè un programma MQL5 può richiamare dati da qualsiasi simbolo e timeframe, vi è la possibilità che i dati di una timeseries necessari non sono ancora formati nel terminale o i dati sui prezzi necessari non sono sincronizzati con il trade server. In questo caso è difficile prevedere il tempo di latenza.
Gli algoritmi con cicli di latenza non sono la soluzione migliore. L'unica eccezione in questo caso sono gli script, perché non hanno nessun algoritmo alternativo a causa di non avere la gestione degli eventi (event handling). Per gli indicatori personalizzati, tali algoritmi, nonché eventuali altri cicli di latenza sono fortemente sconsigliati, perché portano alla cessazione del calcolo di tutti gli indicatori e qualsiasi altra manipolazione dei dati sui prezzi del simbolo.
Per Expert Advisors ed indicatori, è meglio utilizzare il modello di eventi di handling. Se durante l'handling di eventi OnTick() o OnCalculate(), la ricezione di dati per le serie temporali richieste è fallita, è necessario uscire dall'event handler, facendo affidamento sulla disponibilità di accesso durante la chiamata successiva dell'handler.
Esempio di script per l'Aggiunta di Storico
Consideriamo l'esempio di uno script che esegue una richiesta per ricevere lo storico per il simbolo selezionato da un trade server. Lo script è destinato all'esecuzione in un grafico di un simbolo selezionato; non importa il timeframe, perché, come è stato detto sopra, i dati sui prezzi sono ricevuti da un trade server come dei dati confezionati da 1 minuto, da cui tutte le timeseriespredefiniti, vengono costruite poi .
Scriviamo tutte le azioni riguardanti la ricezione di dati come una funzione separata CheckLoadHistory (simbolo, timeframe , start_date):
int CheckLoadHistory(string symbol,ENUM_TIMEFRAMES period,datetime start_date)
|
La funzione CheckLoadHistory() è concepita come una funzione universale che può essere chiamata da qualsiasi programma (Expert Advisor, Script o Indicatore), e pertanto richiede tre parametri di input: nome simbolo, periodo e la data di inizio per indicare l'inizio dello storico prezzi di cui si bisogno.
Inserire i necessari controlli nel codice della funzione prima di richiedere la storia mancante. Prima di tutto, dobbiamo fare in modo che il nome del simbolo ed il valore del periodo siano corretti:
if(symbol==NULL || symbol=="") symbol=Symbol();
|
Quindi facciamo in modo che il simbolo sia disponibile nella finestra di MarketWatch, vale a dire, la storia del simbolo sarà disponibile quando si invia una richiesta ad un trade server. Se non vi è un tale simbolo in MarketWatch, aggiungerlo utilizzando la funzione SymbolSelect().
if(!SymbolInfoInteger(symbol,SYMBOL_SELECT))
|
Ora dobbiamo ricevere la data di inizio dello storico disponibile per la coppia simbolo/periodo indicata. Forse, il valore del parametro di input startdate, passato a CheckLoadHistory(), è all'interno dello storico disponibile; quindi la richiesta ad un trade server non è necessaria. Per ottenere la prima data per il simbolo-periodo del momento, viene utilizzata la funzione SeriesInfoInteger() con il modificatore SERIES_FIRSTDATE.
SeriesInfoInteger(symbol,period,SERIES_FIRSTDATE,first_date);
|
Il prossimo importante controllo sta controllando il tipo di programma, da cui la funzione viene chiamata. Nota, inviando la richiesta per aggiornare le timeseries con lo stesso periodo di quello dell'indicatore, che chiama l'aggiornamento, è indesiderabile. La non desiderabilità della richiesta dei dati sullo stesso simbolo-periodo come quello dell'indicatore, è condizionata dal fatto che l'aggiornamento dei dati storici viene eseguito nello stesso thread in cui opera l'indicatore. Quindi, la possibilità di insorgenza di un punto morto è alta. Per controllare ciò, usare la funzione MQL5InfoInteger() con il modificatore MQL5_PROGRAM_TYPE.
if(MQL5InfoInteger(MQL5_PROGRAM_TYPE)==PROGRAM_INDICATOR && Period()==period && Symbol()==symbol)
|
Se tutti i controlli hanno dato risultati positivi, fa l'ultimo tentativo senza fare riferimento al server commercio. Prima cerchiamo di scoprire la data di inizio, per i quali sono disponibili dati minute in formato HCC. Richiediamo questo valore utilizzando la funzione SeriesInfoInteger() con il modificatore SERIES_TERMINAL_FIRSTDATE e ancora confrontandolo con il valore del parametro start_date.
if(SeriesInfoInteger(symbol,PERIOD_M1,SERIES_TERMINAL_FIRSTDATE,first_date))
|
Se dopo tutti i controlli il thread di esecuzione è ancora nel corpo della funzione CheckLoadHistory(), significa che vi è una necessità di richiedere i dati mancanti dei prezzi da un trade server. In primo luogo, viene restituito il valore di "Max barre nel chart" utilizzando la funzione TerminalInfoInteger():
int max_bars=TerminalInfoInteger(TERMINAL_MAXBARS); |
Avremo bisogno per impedire la richiesta di dati aggiuntivi. Poi trovare la prima vera data nello storico del simbolo sul trade server (indipendentemente dal periodo) utilizzando la già nota funzione SeriesInfoInteger() con il modificatore SERIES_SERVER_FIRSTDATE.
datetime first_server_date=0;
|
Dal momento che la richiesta è un'operazione asincrona, la funzione viene richiamata nel ciclo con un piccolo ritardo di 5 millisecondi fino a quando la variabile first_server_date riceve un valore, o l'esecuzione del ciclo viene interrotta da un utente (IsStopped() restituirà true in questo caso). Indichiamo un valore corretto della data di inizio, a partire dalla quale richiediamo i dati sui prezzi da un trade server.
if(first_server_date>start_date) start_date=first_server_date;
|
Se la data di inizio first_server_date del server è inferiore alla data di inizio first_date del simbolo in formato HCC, la voce corrispondente viene emessa nel Journal.
Ora siamo pronti a fare una richiesta ad un trade server per chiedere dati mancanti di prezzi. Effettuare la richiesta sotto forma di un ciclo ed iniziare a riempire il suo corpo:
while(!IsStopped())
|
I primi tre punti sono attuati tramite i mezzi già noti.
while(!IsStopped())
|
L'ultimo quarto punto viene lasciato - richiesta storico. Non possiamo fare riferimento ad un server direttamente, ma qualsiasi funzione-Copy inizia automaticamente la richiesta di invio ad un server, se lo storico in formato HCC non è sufficiente. Siccome il tempo della primissima data di inizio nella variabile first_date è il criterio semplice e naturale per valutare il grado richiesta di esecuzione, allora il modo ancor più semplice è quello di utilizzare la funzione CopyTime().
Quando si chiamano funzioni che copiano i dati provenienti da timeseries, si deve rilevare che il parametro start (numero della barra, a partire dal quale i dati di prezzo dovrebbero essere copiati) deve essere sempre all'interno dello storico disponibile del terminale. Se si hanno solo 100 barre, è privo di senso provare a copiare 300 barre partendo dalla barra con l'indice 500. Tale richiesta sarà intesa come erronea e non sarà trattata, cioè nessuna storia supplementare sarà caricata da un trade server.
Ecco perché si copierà dala barra 100 a partire dalla barra con indice bars (l'index). Ciò fornirà il corretto caricamento dello storico mancante, da un trade server. In realtà verrà caricato un po' di più rispetto alle 100 barre richieste, mentre il server invia lo storico di dimensioni più grandi.
int copied=CopyTime(symbol,period,bars,100,times); |
Dopo l'operazione di copia, dobbiamo analizzare il numero di elementi copiati. Se il tentativo fallisce, allora il valore di copied sarà uguale a null ed il valore del contatore fail_cnt sarà aumentato di 1. Dopo 100 tentativi di fallimento, l'operazione della funzione viene interrotta.
int fail_cnt=0;
|
Così, non solo viene implementato nella funzione il corretto handling della situazione attuale in qualsiasi fase di esecuzione, ma viene restituito anche il codice di terminazione, che può essere gestito dopo la chiamata della funzione CheckLoadHistory() per ottenere ulteriori informazioni. Ad esempio, in questo modo:
int res=CheckLoadHistory(InpLoadedSymbol,InpLoadedPeriod,InpStartDate);
|
Il codice completo della funzione può essere trovato nel esempio di uno script che mostra la corretta organizzazione di accesso ai dati con l'handling dei risultati della richiesta.
Codice:
//+--------------------------------------------------------------------------------+
|