Qualcuno sa come sviluppare un indicatore multicurrency?

 
Qualcuno sa come sviluppare un indicatore multicurrency?

Voglio scegliere da 1 a 10 valute diverse e 5 barre per ogni valuta.

Ma non so come farlo.

 

In un indicatore standard, costruireste gli array di buffer con i dati dei parametri inviati tramite la funzione evento OnCalulate( ... ). Ma, per multi-valuta e/o multi-time-frame, dovrete usare una delle due soluzioni:

  • Utilizzando il vecchio metodo delle varianti "iFunction", come iTime(), iVolume, iOpen, iClose, ecc. ma con un simbolo diverso come "EURUSD", "JPYUSD", ecc. invece del predefinito _Symbol o Symbol().
  • Utilizzando il metodo più recente della prima variante della funzione ArrayCopyRates() insieme a puntatori di array di MqlRates. Gli array "copiati", in realtà non occuperanno alcuno spazio e saranno solo puntatori ai dati esistenti dei vari simboli e time-frames.

Tuttavia, perché questo funzioni, deve esistere una delle due condizioni per far funzionare il multi-simbolo e/o il multi-frame di tempo:

  • O i rispettivi grafici dei simboli e dei time-frame sono già aperti, in modo che non venga generato alcun errore,
  • o si otterrà un errore 4066 (ERR_HISTORY_WILL_UPDATED) la prima volta che si richiedono i dati, e si dovrà codificare un ciclo sleep & retry, per aspettare che i dati vengano scaricati e poi richiedere nuovamente i dati.

La soluzione da me suggerita, che trovo la più efficiente e la più semplice per gestire l'errore 4066, è il metodo ArrayCopyRates() e MqlRates .

Ci sono più informazioni su questo nella documentazione e nei file di aiuto di MQL4.

PS! NB! Quando si accede a funzioni di indicatori incorporati, come iMA(), iATR(), ecc. per i vari simboli e time-frames, ricordarsi di implementare anche i cicli di sleep e retry per non ottenere l'errore 4066. Ecco una citazione dalla documentazione di MQL4:

Any indicator can be calculated on the data of not only current chart, but also on the data of any available symbol/period. If data (symbol name and/or timeframe differ from the current ones) are requested from another chart, the situation is possible that the corresponding chart was not opened in the client terminal and the necessary data must be requested from the server. In this case, error ERR_HISTORY_WILL_UPDATED (4066 - the requested history data are under updating) will be placed in the last_error variable, and one will has to re-request (see example of ArrayCopySeries())
 
Ricordate che l'OP sta chiedendo di un indicatore. Sleep() è ignorato negli indicatori
 
GumRai:
Ricordate che l'OP sta chiedendo di un indicatore. Sleep() è ignorato negli indicatori

Scusa, non lo sapevo! Uso questo metodo abbastanza estesamente negli EA ma non negli indicatori, quindi non sapevo dell'handicap del sonno.

In questo caso, dovrà costruire un ciclo di ripetizione intorno a chiamate successive su ogni chiamata di tick alla funzione OnCalculate() (dove l'uso di ArrayCopyRates() è la soluzione migliore).

In alternativa, se funziona nella funzione OnInit(), potrebbe essere il metodo preferito per preparare i dati per l'indicatore, con un conteggio dei tentativi molto lungo (senza lo sleep) per questo caso.

 
FMIC:

...

  • o otterrete un errore 4066 (ERR_HISTORY_WILL_UPDATED) la prima volta che richiederete i dati, e dovrete codificare un ciclo sleep & retry, per aspettare che i dati vengano scaricati e poi richiedere nuovamente i dati.

PS! NB! Quando si accede a funzioni di indicatori incorporati, come iMA(), iATR(), ecc. per i vari simboli e time-frames, ricordarsi di implementare anche i cicli di sleep e retry per non ottenere l'errore 4066. Ecco una citazione dalla documentazione di MQL4:


A meno che non abbiano cambiato qualcosa di recente, otterrete l'errore 4066 ogni volta dalla prima chiamata della funzione (e solo da questa prima chiamata), indipendentemente dalle condizioni o dal progresso dell'aggiornamento della cronologia. Non ha alcuna utilità pratica.
 
Ovo:
A meno che non abbiano cambiato qualcosa di recente, otterrete l'errore 4066 ogni volta dalla prima chiamata della funzione (e solo da questa prima chiamata), indipendentemente dalle condizioni o dal progresso dell'aggiornamento della storia. Non ha alcuna utilità pratica.
Questo non è stato il mio caso. Quando i dati sono già completamente disponibili, non ottengo l'errore 4066. Tuttavia, se non è direttamente disponibile, allora sì, ottengo l'errore solo alla prima chiamata di qualsiasi funzione per quel particolare simbolo e time.frame. Dopo di che qualsiasi altra funzione che richiede quei dati, non dà più l'errore.
 

FMIC:

In questo caso, dovrà costruire un ciclo di ripetizione intorno alle chiamate successive su ogni tick alla funzione OnCalculate() (dove l'uso di ArrayCopyRates() è la soluzione migliore).

In alternativa, se funziona nella funzione OnInit(), potrebbe essere il metodo preferito per preparare i dati per l'indicatore, con un conteggio dei tentativi molto lungo (senza lo sleep) per questo caso.

  1. Un ciclo (lungo o altro) nell'indicatore non funzionerà. Mentre l'indicatore è in esecuzione non può accadere nient 'altro nel terminale. Questo è il motivo per cui Sleep non può funzionare negli indicatori. E perché ArrayCopyRates è asincrono (per gli indicatori).
  2. Abilitare l'array di tassi in init. Testatelo in OnTick e gestite lì i tentativi. Ricorda anche che diversi grafici creano nuove barre in tempi diversi.
    string pairs[] = {"EURUSD", "GBPUSD" ...}
    MqlRates pair0[], pair1[], ...
    bool initial;
    OnInit(){ initial=true;
       ArrayCopyRates(pair0, pairs[0], _Period);   
       ArrayCopyRates(pair1, pairs[1], _Period);
       :
    }
    OnCalculate( ... ){
       int count = IndicatorCounted();
       if(initial){
          if(pair1[0].time == 0) return;
          if(pair2[0].time == 0) return;
          :
          initial=false; count = 0; // process all bars
       }
       for(int i = Bars - 1 - MathMax(lookback, count); i >= 0; --i){
          int shift0 = iBarsShift(pairs[0], _Period, Time[i]);
          int shift1 = iBarsShift(pairs[1], _Period, Time[i]);
          buffer[i] = pair0[shift0].close - pair1[shift1].close;

  3. Se non volete usare ArrayCopyRates non siete obbligati, ma dovete comunque caricare le altre coppie sostituendo [nell'if(initial)] la coppiaN[0].time con iTime().
 
   if(pair1[0].time == 0) return;

Questo non sarà mai vero.

Se c'è uno storico caricato per il simbolo e il timeframe, la funzione recupererà il valore più recente.

Se non c'è nessuna cronologia caricata, si otterrà un errore di Array out of range.

Lo stesso vale per iTime ecc.

 
GumRai:

Questo non sarà mai vero.

Se c'è uno storico caricato per il simbolo e il timeframe, la funzione recupererà il valore più recente.

Se non c'è nessuna cronologia caricata, si otterrà un errore di Array out of range.

Lo stesso vale per iTime ecc.

Sono d'accordo!

Personalmente, controllo solo il valore di ritorno di "ArrayCopyRates()" e dopo di che tengo traccia della dimensione dell'array prima di accedere ai dati dell'array.

Per quanto riguarda "iTime()" e altre funzioni simili, controllo sempre prima "iBars()".

 
GumRai:

Questo non sarà mai vero.

  if(pair1[0].time == 0) return;

Se c'è uno storico caricato per il simbolo e il timeframe, la funzione recupererà il valore più recente.

Se non c'è nessuna cronologia caricata, si otterrà un errore Array out of range.

Lo stesso vale per iTime ecc.

Ci sono molti esempi storici (pre-costruzione 600) di guardare un ACR. Non c'è altro modo per farlo. Le chiamate successive ad ACR o iTime NON restituiranno 4066, quindi come si può sapere se i dati sono stati scaricati.

iTime ha sempre restituito zero in caso di errore.

 
WHRoeder:

Ci sono molti esempi storici (pre-build 600) di guardare un ACR. Non c'è altro modo per farlo. Le chiamate successive ad ACR o iTime NON restituiranno 4066, quindi come si può sapere se i dati sono stati scaricati.

iTime ha sempre restituito zero in caso di errore.

Cosa intendi per "non c'è altro modo per farlo"?

Controllare il conteggio di ritorno da "ArrayCopyRates", e controllare la dimensione dell'array, sembra essere un metodo di controllo più robusto che fare "pair1[0].time == 0" che può facilmente restituire unerrore "Array index is out of range".

EDIT: rimosso alcune delle mie affermazioni dopo aver riletto meglio il tuo post.