Diferença de precedência de indicador com ou sem modo visual no backtest

 

Eu criei um indicador que chama outro indicador internamente. Os dois são chamados utilizando a função iCustom. Se eu chamar com o modo visual ativo, a função OnCalculate do indicador mais externo é chamada primeiro. Já se eu chamar com o modo visual marcado, a ordem é inversa.

Pra entender melhor, segue o código do arquivo Teste.mq5

int OnInit() {
   return(INIT_SUCCEEDED);
}

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[]) {
   Print("Teste");   
   return rates_total;
}

E abaixo o código do arquivo TesteWrapper.mq5:

#resource "Teste.ex5"

int indicadorHandler;
double indicadorBuffer[];

int OnInit() {
   indicadorHandler = iCustom(Symbol(), PERIOD_M15, "::Teste.ex5");
   return INIT_SUCCEEDED;
}

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[]) {
   CopyBuffer(indicadorHandler, 0, 0, 1, indicadorBuffer);
   Print("TesteWrapper");
   return rates_total;
}

E, por último, abaixo o código do arquivo TesteEA.mq5:

#resource "TesteWrapper.ex5"
int indicadorWrapper;
int indicadorHandler;
double indicadorBuffer[];
int OnInit() {        
   indicadorWrapper = iCustom(Symbol(), Period(), "::TesteWrapper.ex5");               
   return INIT_SUCCEEDED;         
}

void OnTick() {
   CopyBuffer(indicadorWrapper, 0, 0, 1, indicadorBuffer);
   Print("Teste EA");
}

Segue o log da execução com o modo visual ativado:

2021.09.20 00:39:59.753 2019.01.02 09:09:00   TesteWrapper
2021.09.20 00:39:59.753 2019.01.02 09:09:00   Teste
2021.09.20 00:39:59.753 2019.01.02 09:09:00   Teste EA
2021.09.20 00:39:59.772 2019.01.02 09:09:20   TesteWrapper
2021.09.20 00:39:59.772 2019.01.02 09:09:20   Teste
2021.09.20 00:39:59.772 2019.01.02 09:09:20   Teste EA
2021.09.20 00:39:59.792 2019.01.02 09:09:40   TesteWrapper
2021.09.20 00:39:59.792 2019.01.02 09:09:40   Teste
2021.09.20 00:39:59.792 2019.01.02 09:09:40   Teste EA
2021.09.20 00:39:59.811 2019.01.02 09:09:59   TesteWrapper
2021.09.20 00:39:59.811 2019.01.02 09:09:59   Teste
2021.09.20 00:39:59.811 2019.01.02 09:09:59   Teste EA
2021.09.20 00:39:59.830 2019.01.02 09:10:00   TesteWrapper
2021.09.20 00:39:59.830 2019.01.02 09:10:00   Teste
2021.09.20 00:39:59.830 2019.01.02 09:10:00   Teste EA
2021.09.20 00:39:59.851 2019.01.02 09:10:20   TesteWrapper
2021.09.20 00:39:59.851 2019.01.02 09:10:20   Teste
2021.09.20 00:39:59.851 2019.01.02 09:10:20   Teste EA
2021.09.20 00:39:59.871 2019.01.02 09:10:40   TesteWrapper
2021.09.20 00:39:59.871 2019.01.02 09:10:40   Teste
2021.09.20 00:39:59.871 2019.01.02 09:10:40   Teste EA
2021.09.20 00:39:59.890 2019.01.02 09:10:59   TesteWrapper
2021.09.20 00:39:59.890 2019.01.02 09:10:59   Teste
2021.09.20 00:39:59.890 2019.01.02 09:10:59   Teste EA
2021.09.20 00:39:59.910 2019.01.02 09:11:00   TesteWrapper
2021.09.20 00:39:59.910 2019.01.02 09:11:00   Teste
2021.09.20 00:39:59.910 2019.01.02 09:11:00   Teste EA
2021.09.20 00:39:59.929 2019.01.02 09:11:20   TesteWrapper
2021.09.20 00:39:59.929 2019.01.02 09:11:20   Teste
2021.09.20 00:39:59.929 2019.01.02 09:11:20   Teste EA
2021.09.20 00:39:59.949 2019.01.02 09:11:40   TesteWrapper
2021.09.20 00:39:59.949 2019.01.02 09:11:40   Teste
2021.09.20 00:39:59.949 2019.01.02 09:11:40   Teste EA
2021.09.20 00:39:59.968 2019.01.02 09:11:59   TesteWrapper
2021.09.20 00:39:59.968 2019.01.02 09:11:59   Teste
2021.09.20 00:39:59.968 2019.01.02 09:11:59   Teste EA

Segue o log da execução sem o modo visual ativado:

2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:00   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:00   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:00   Teste EA
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:20   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:20   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:20   Teste EA
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:40   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:40   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:40   Teste EA
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:59   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:59   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:09:59   Teste EA
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:00   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:00   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:00   Teste EA
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:20   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:20   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:20   Teste EA
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:40   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:40   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:40   Teste EA
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:59   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:59   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:10:59   Teste EA
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:00   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:00   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:00   Teste EA
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:20   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:20   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:20   Teste EA
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:40   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:40   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:40   Teste EA
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:59   Teste
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:59   TesteWrapper
2021.09.20 00:41:38.148 Core 01 2019.01.02 09:11:59   Teste EA

Vejam que na execução com o modo visual ativo, considerando o mesmo horário nas duas execuções (9:10:00), a execução com o modo visual executa o indicador principal, TesteWrapper, antes de executar o indicador interno (Teste), isso gera distorções entre os resultados do backtest ativando o modo visual ou não.

Tem uma forma de forçar no código que o método OnCalculate do indicador Teste seja executado antes do TesteWrapper? Tem como especificar uma ordem de precedência entre os indicadores? Queria que o comportamento verificado no modo sem o modo visual fosse o mesmo utilizando esse modo.

Documentação sobre MQL5: Elementos Básicos da Linguagem / Funções / Funções de Manipulação de Evento
Documentação sobre MQL5: Elementos Básicos da Linguagem / Funções / Funções de Manipulação de Evento
  • www.mql5.com
Funções de Manipulação de Evento - Funções - Elementos Básicos da Linguagem - Referência MQL5 - Referência sobre algorítimo/automatização de negociação na linguagem para MetaTrader 5
 
David Guerra:

Eu criei um indicador que chama outro indicador internamente. Os dois são chamados utilizando a função iCustom. Se eu chamar com o modo visual ativo, a função OnCalculate do indicador mais externo é chamada primeiro. Já se eu chamar com o modo visual marcado, a ordem é inversa.

Pra entender melhor, segue o código do arquivo Teste.mq5

E abaixo o código do arquivo TesteWrapper.mq5:

E, por último, abaixo o código do arquivo TesteEA.mq5:

Segue o log da execução com o modo visual ativado:

Segue o log da execução sem o modo visual ativado:

Vejam que na execução com o modo visual ativo, considerando o mesmo horário nas duas execuções (9:10:00), a execução com o modo visual executa o indicador principal, TesteWrapper, antes de executar o indicador interno (Teste), isso gera distorções entre os resultados do backtest ativando o modo visual ou não.

Tem uma forma de forçar no código que o método OnCalculate do indicador Teste seja executado antes do TesteWrapper? Tem como especificar uma ordem de precedência entre os indicadores? Queria que o comportamento verificado no modo sem o modo visual fosse o mesmo utilizando esse modo.

A ordem importa? Nao, porque voce deveria testar que seu indicador devolveu dados confiaveis para fazer o calculo. Se ele nao devolveu voce deveria sair da funcao OnCalculate e na proxima requisicao solicitar os mesmos dados. Idem pro EA, sai do OnTick e volta depois se nao tiver acabado o calculo... nao eh bug da plataforma.
 
Ricardo Rodrigues Lucca #:
A ordem importa? Nao, porque voce deveria testar que seu indicador devolveu dados confiaveis para fazer o calculo. Se ele nao devolveu voce deveria sair da funcao OnCalculate e na proxima requisicao solicitar os mesmos dados. Idem pro EA, sai do OnTick e volta depois se nao tiver acabado o calculo... nao eh bug da plataforma.

Importa sim. Detalhar melhor o cenário real. 

1. Meu EA só opera na abertura do candle, então ele só vai chamar uma vez o CopyBuffer do indicador TesteWrapper;

2. O OnCalculate do TesteWrapper chama o CopyBuffer pro indicador "Teste" e, dependendo do retorno, seta o buffer do indicador TesteWrapper com o sinal de compra ou venda, por exemplo.

2.1 Se no momento que o OnCalculate do TesteWrapper tentar ler o buffer do Teste, mas ele ainda não tiver sido calculado, o TesteWrapper pode enviar um sinal errado pro EA.

Em resumo o que estou tentando fazer é que um EA chame um indicador quando uma barra for aberta e esse indicador retorne um sinal de compra/venda/neutro baseado no  cálculo de outro indicador. Então esse indicador que vai verificar se preenche o buffer com indicação de compra ou venda depende que os dados do indicador "filho" tenham sido previamente calculados.

 
David Guerra #:

Importa sim. Detalhar melhor o cenário real. 

1. Meu EA só opera na abertura do candle, então ele só vai chamar uma vez o CopyBuffer do indicador TesteWrapper;

2. O OnCalculate do TesteWrapper chama o CopyBuffer pro indicador "Teste" e, dependendo do retorno, seta o buffer do indicador TesteWrapper com o sinal de compra ou venda, por exemplo.

2.1 Se no momento que o OnCalculate do TesteWrapper tentar ler o buffer do Teste, mas ele ainda não tiver sido calculado, o TesteWrapper pode enviar um sinal errado pro EA.

Em resumo o que estou tentando fazer é que um EA chame um indicador quando uma barra for aberta e esse indicador retorne um sinal de compra/venda/neutro baseado no  cálculo de outro indicador. Então esse indicador que vai verificar se preenche o buffer com indicação de compra ou venda depende que os dados do indicador "filho" tenham sido previamente calculados.

Você precisa trabalhar com serialização de eventos... Você não tem acesso à árvore de decisão das threads internas do MT5...
 
David Guerra #:

Importa sim. Detalhar melhor o cenário real. 

1. Meu EA só opera na abertura do candle, então ele só vai chamar uma vez o CopyBuffer do indicador TesteWrapper;

2. O OnCalculate do TesteWrapper chama o CopyBuffer pro indicador "Teste" e, dependendo do retorno, seta o buffer do indicador TesteWrapper com o sinal de compra ou venda, por exemplo.

2.1 Se no momento que o OnCalculate do TesteWrapper tentar ler o buffer do Teste, mas ele ainda não tiver sido calculado, o TesteWrapper pode enviar um sinal errado pro EA.

Em resumo o que estou tentando fazer é que um EA chame um indicador quando uma barra for aberta e esse indicador retorne um sinal de compra/venda/neutro baseado no  cálculo de outro indicador. Então esse indicador que vai verificar se preenche o buffer com indicação de compra ou venda depende que os dados do indicador "filho" tenham sido previamente calculados.

Como o flavio disse, voce nao tem como saber, dado que o copybuffer nao veio porque o calculo nao estava completo, voce precisa liberar a funcao e voltar depois se nao ele nao vai te devolver o resultado que quer. Esta no manual isso.
 
Flavio Jarabeck #:
Você precisa trabalhar com serialização de eventos... Você não tem acesso à árvore de decisão das threads internas do MT5...

Não entendi muito bem quando você falou que eu precisaria trabalhar com serialização de eventos. É possível fazer isso em MQL5? Ou você disse que não era possível quando comentou que eu não tenho acesso à árvore de decisão das threads. Se for possível, você sabe qual o caminho? Teria algum link da documentação onde fala sobre isso?

Pra complementar a motivação dessa "arquitetura", seria porque eu queria ter um indicador principal que retornaria um sinal de compra/venda/netro e dentro desse indicador eu poderia chamar vários outros, inclusive em timeframes diferentes, pra gerar o sinal. E eu chamaria esse cálculo apenas no início de cada candle.

Obrigado.

 
Ricardo Rodrigues Lucca #:
Como o flavio disse, voce nao tem como saber, dado que o copybuffer nao veio porque o calculo nao estava completo, voce precisa liberar a funcao e voltar depois se nao ele nao vai te devolver o resultado que quer. Esta no manual isso.
Sim. Eu entendi que normalmente eu teria que chamar novamente depois. Só que para esse "requisito", de chamar apenas na abertura do candle, acho que não daria certo mesmo. Pq eu não teria então como saber se o cálculo do indicador já foi processado para o candle atual ou não, é isso? Eu não teria uma forma de pegar a data que teve o último calculo em um indicador?
 
David Guerra #:

Não entendi muito bem quando você falou que eu precisaria trabalhar com serialização de eventos. É possível fazer isso em MQL5? Ou você disse que não era possível quando comentou que eu não tenho acesso à árvore de decisão das threads. Se for possível, você sabe qual o caminho? Teria algum link da documentação onde fala sobre isso?

Pra complementar a motivação dessa "arquitetura", seria porque eu queria ter um indicador principal que retornaria um sinal de compra/venda/netro e dentro desse indicador eu poderia chamar vários outros, inclusive em timeframes diferentes, pra gerar o sinal. E eu chamaria esse cálculo apenas no início de cada candle.

Obrigado.

Serialização de Eventos é uma técnica de Programação, e não instruções propriamente.

Uma das maneiras seria criar um método de comunicacão entre os indicadores usando as Variáveis Globais do Terminal MT5...

;)

 
Flavio Jarabeck #:

Serialização de Eventos é uma técnica de Programação, e não instruções propriamente.

Uma das maneiras seria criar um método de comunicacão entre os indicadores usando as Variáveis Globais do Terminal MT5...

;)

Entendi. Sou programador Java e já trabalhei muito com serialização no contexto do uso de threads, mas como acho que não temos controle da thread dos indicadores em MQL5, fiquei um pouco na dúvida sobre o que você quis dizer.

Mas vou tentar implementar algo nessa linha, apesar de, a princípio, achar que não seja uma solução muito "bonita". Teria que usar uma variável global por indicador, enfim, vou ver melhor. Mas muito obrigado pela ajuda.

 
David Guerra #:
Sim. Eu entendi que normalmente eu teria que chamar novamente depois. Só que para esse "requisito", de chamar apenas na abertura do candle, acho que não daria certo mesmo. Pq eu não teria então como saber se o cálculo do indicador já foi processado para o candle atual ou não, é isso? Eu não teria uma forma de pegar a data que teve o último calculo em um indicador?
Tem como pegar as barras calculadas, mas acredito que tu precise definir o "requisito" primeiro. Tu quer operar na abertura da vela pra ter só uma negociação ou algum outro motivo? A vela aberta normalmente não tem nada interessante já que é só um risco com tudo igual. Tem pessoal que define "abertura de nova vela" como qualquer que esteja com menos de 100 negócios e não necessariamente tempo pra ter ideia.
 
Ricardo Rodrigues Lucca #:
Tem como pegar as barras calculadas, mas acredito que tu precise definir o "requisito" primeiro. Tu quer operar na abertura da vela pra ter só uma negociação ou algum outro motivo? A vela aberta normalmente não tem nada interessante já que é só um risco com tudo igual. Tem pessoal que define "abertura de nova vela" como qualquer que esteja com menos de 100 negócios e não necessariamente tempo pra ter ideia.

A ideia de pegar os valores na abertura da vela é só pra garantir que a vela anterior já está fechada, porque eu não tenho como saber o último tick de uma vela se não quando a próxima for aberta. Na verdade não teria relação com ter apenas uma negociação.

Razão: