Alguém sabe como desenvolver um indicador de múltiplas moedas ?

 
Alguém sabe como desenvolver um indicador de múltiplas moedas?

Eu quero escolher ENTRE 1 a 10 moedas diferentes e 5 barras para cada moeda.

Mas eu não sei como fazer isso.

 

Em um indicador padrão, você construiria as matrizes de proteção com dados dos parâmetros enviados através da função de evento OnCalulate( ... ). Mas, para multi-currency e/ou multi-time-frame, você terá que usar uma de duas soluções:

  • Usando o método antigo das variações "iFunction", tais como iTime(), iVolume, iOpen, iClose, etc., mas com um símbolo diferente como "EURUSD", "JPYUSD", etc. em vez do padrão _Symbol ou Symbol().
  • Usando o método mais recente da primeira variante da função ArrayCopyRates() juntamente com apontadores de array de MqlRates. Os arrays "copiados", na verdade não ocuparão nenhum espaço e serão apenas apontadores para os dados existentes dos vários símbolos e quadros de tempo.

Entretanto, para que isto funcione, uma de duas condições tem que existir para que o multi-símbolo e/ou o multi-modelo de tempo funcione:

  • Ou os respectivos gráficos para os símbolos e quadros temporais já estão abertos, de modo que nenhum erro seja gerado,
  • ou você receberá um erro 4066 (ERR_HISTORY_WILL_UPDATED) na primeira vez que solicitar os dados, e você terá que codificar um loop de sono e nova tentativa, a fim de esperar que os dados sejam baixados e então solicitar os dados novamente.

Minha solução pessoal sugerida, que considero como a mais eficiente, bem como a maneira mais fácil de lidar com o erro 4066, é o método ArrayCopyRates() e MqlRates .

Há mais informações sobre isso na documentação MQL4 e nos arquivos de ajuda.

PS! NB! Ao acessar funções indicadoras embutidas, tais como iMA(), iATR(), etc. para os vários símbolos e prazos, lembre-se também de implementar os laços de dormir e tentar novamente para não obter o erro 4066 também. Aqui está uma citação do documento 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())
 
Lembre-se, a OP está perguntando sobre um indicador. Dormir() é ignorado nos indicadores
 
GumRai:
Lembre-se, a OP está perguntando sobre um indicador. Sleep() é ignorado nos indicadores

Desculpe, mas não sabia disso! Utilizo este método bastante extensivamente nos EA, mas não nos Indicadores, portanto não sabia sobre a deficiência do sono.

Nesse caso, ele terá que construir um loop de repetição em torno de chamadas sucessivas em cada chamada para a função OnCalculate() (onde o uso do ArrayCopyRates() é a melhor solução).

Alternativamente, se funcionar na função OnInit(), pode ser o método preferido de preparação dos dados para o indicador, com uma reentrada muito longa (sem o sono) para este caso.

 
FMIC:

...

  • ou você receberá um erro 4066 (ERR_HISTORY_WILL_UPDATED) na primeira vez que solicitar os dados, e você terá que codificar um loop de sono e nova tentativa, a fim de esperar que os dados sejam baixados e então solicitar os dados novamente.

PS! NB! Ao acessar funções indicadoras embutidas, tais como iMA(), iATR(), etc. para os vários símbolos e prazos, lembre-se também de implementar os laços de dormir e tentar novamente, para não obter o erro 4066 também. Aqui está uma citação do documento MQL4:


A menos que eles tenham mudado algo recentemente, você receberá o erro 4066 toda vez desde a primeira chamada de função (e somente desde esta primeira chamada), independentemente das condições ou do progresso de atualização do histórico. Ele não tem utilidade prática.
 
Ovo:
A menos que eles tenham mudado algo recentemente, você receberá o erro 4066 toda vez desde a primeira chamada de função (e somente desde esta primeira chamada), independentemente das condições ou do progresso de atualização do histórico. Ele não tem utilidade prática.
Isso não tem sido o meu caso. Quando os dados já estão totalmente disponíveis, eu não recebo o erro 4066. Entretanto, se não estiver diretamente disponível, então sim, recebo o erro somente na primeira chamada de qualquer função para aquele símbolo e tempo.frame em particular. Depois disso, qualquer outra função que solicite esses dados, não mais me dá o erro.
 

FMIC:

Nesse caso, ele terá que construir um loop de repetição em torno de chamadas sucessivas em cada chamada para a função OnCalculate() (onde o uso do ArrayCopyRates() é a melhor solução).

Alternativamente, se funcionar na função OnInit(), pode ser o método preferido para preparar os dados para o indicador, com uma recontagem muito longa (sem o sono) para este caso.

  1. Um laço (longo ou não) no indicador não funcionará. Enquanto o indicador estiver funcionando, nada mais no terminal pode acontecer. É por isso que o Sleep não pode funcionar nos indicadores. E por que o ArrayCopyRates é assíncrono (para os indicadores.)
  2. Habilite a matriz de taxas no init. Teste-o no OnTick, e manuseie as tentativas novamente lá. Lembre-se também que gráficos diferentes criam novas barras em horários diferentes.
    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 você não quiser usar o ArrayCopyRates você não precisa, mas ainda deve carregar os outros pares substituindo [no if(inicial)] o parN[0].time pelo iTime().
 
   if(pair1[0].time == 0) return;

Isto nunca será verdade.

Se houver algum histórico carregado para o símbolo e o cronograma, a função recuperará o valor mais recente.

Se não houver nenhum histórico carregado, você obterá um Array fora do intervalo de erro.

O mesmo com o iTime, etc.

 
GumRai:

Isto nunca será verdade.

Se houver algum histórico carregado para o símbolo e o cronograma, a função recuperará o valor mais recente.

Se não houver nenhum histórico carregado, você obterá um Array fora do intervalo de erro.

O mesmo com o iTime, etc.

Eu estou inclinado a concordar!

Pessoalmente, eu apenas verifico o valor de retorno do "ArrayCopyRates()" e depois disso eu apenas acompanho o tamanho da matriz antes de acessar os dados da matriz.

Com relação ao "iTime()" e outras funções semelhantes, eu sempre verifico o "iBars()" primeiro.

 
GumRai:

Isto nunca será verdade.

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

Se houver algum histórico carregado para o símbolo e o cronograma, a função recuperará o valor mais recente.

Se não houver nenhum histórico carregado, você obterá um Array fora do intervalo de erro.

O mesmo com o iTime, etc.

Há muitos exemplos históricos (600 pré-construção) de olhar para um ACR. Não há outra maneira de fazer isso. Chamadas subsequentes ao ACR ou ao iTime NÃO retornarão 4066, então como você pode saber se os dados foram baixados?

O iTime sempre retornou zero em um erro.

 
WHRoeder:

Há muitos exemplos históricos (pré-construção 600) de verificação de um ACR. Não há outra maneira de fazer isso. Chamadas subsequentes ao ACR ou ao iTime NÃO retornarão 4066, então como você pode saber se os dados foram baixados.

O iTime sempre retornou zero em um erro.

O que você quer dizer com "não há outra maneira de fazer isso"?

Verificar a contagem de retorno do "ArrayCopyRates", e verificar o tamanho da matriz, parece ser um método mais robusto de verificação, do que fazer "par1[0].time == 0" que pode facilmente retornar umerro "Array index is out of range".

EDIT: Removi algumas de minhas declarações após ter relido seu post mais de perto.