
Abra o capô do robô MME200 e Z-Score, entenda cada função do Expert Advisor no MT5
Se você leu o artigo anterior sobre o robô de reversão à média Z-Score, já sabe a lógica da estratégia. Agora é hora de abrir o capô. Vamos percorrer o código do EA MQL5 reversão à média Z-Score bloco a bloco, explicando o que cada parte faz e por que ela foi escrita dessa forma.
Não precisa ser programador experiente para acompanhar. A ideia é que, ao final, você entenda o que está acontecendo quando esse robô opera na sua conta.
A estrutura geral do EA
Todo Expert Advisor no MT5 tem três funções principais que o MetaTrader chama automaticamente:
| OnInit() → roda uma vez quando o EA é carregado no gráfico OnTick() → roda a cada novo tick de preço (o coração do robô) OnDeinit() → roda quando o EA é removido ou o MT5 fecha |
O EA MQL5 reversão à média Z-Score também usa funções auxiliares próprias que organizam a lógica: CheckEntryConditions, CheckExitConditions, CheckCycleDrawdown e ExecuteTrade.
OnInit: configurando os indicadores
No OnInit, o robô cria dois handles de indicadores, um para a MME200 e outro para o Desvio Padrão. Pense no handle como um canal direto para os dados do indicador:
handleMME = iMA(_Symbol, _Period, InpMAPeriod, 0, InpMAMethod, PRICE_CLOSE);
handleStdDev = iStdDev(_Symbol, _Period, InpZScorePeriod, 0, InpMAMethod, PRICE_CLOSE);
if(handleMME == INVALID_HANDLE || handleStdDev == INVALID_HANDLE)
return(INIT_FAILED);
A verificação de INVALID_HANDLE é importante: se o indicador não carregar por qualquer motivo, o EA para antes de operar. Isso evita que o robô tome decisões sem dados.
Handle é um identificador numérico que o MT5 usa para acessar os dados de um indicador. Sem ele, não é possível ler os valores da MME ou do desvio padrão em tempo real.
OnTick: o coração do EA MQL5 reversão à média Z-Score
A cada tick, o robô recalcula tudo. As funções GetMAValue e GetStdDevValue usam CopyBuffer para puxar os dados dos indicadores:
double GetMAValue(int index) {
double buffer[1];
if(CopyBuffer(handleMME, 0, index, 1, buffer) < 0) return 0;
return buffer[0];
}
double GetStdDevValue(int index) {
double buffer[1];
if(CopyBuffer(handleStdDev, 0, index, 1, buffer) < 0) return 0;
return buffer[0];
}
CopyBuffer é a função do MT5 que copia os valores de um indicador para um array. O segundo parâmetro é o buffer (linha do indicador), o terceiro é a posição inicial e o quarto é a quantidade de valores a copiar.
Com os dados em mãos, o Z-Score é calculado assim:
double currentZScore = (currentPrice - mmeValue) / stdDevValue;
Essa linha é o núcleo do EA MQL5 reversão à média Z-Score. Se o resultado for +2.2, o preço está 2.2 desvios padrão acima da média, o que é sinal potencial de venda. Se for -1.9, está abaixo, o que é sinal potencial de compra.
CheckEntryConditions: quando e como entrar
Essa é a função mais complexa. Ela verifica três condições antes de abrir qualquer posição no EA MQL5 reversão à média Z-Score:
- O Z-Score atingiu algum dos 6 níveis configurados, que são 1.5, 1.9, 2.2, 2.6, 3.5 ou 4.4?
- Já existe posição aberta para esse nível específico, evitando entrada duplicada?
- O preço já começou a reverter do extremo, respeitando o filtro InpWaitReversal?

O controle de posição por nível é feito pela função IsPositionOpenForLevel, que usa o comentário da ordem como chave de identificação:
bool IsPositionOpenForLevel(string comment) {
for(int i = PositionsTotal() - 1; i >= 0; i--) {
if(PositionSelectByTicket(PositionGetTicket(i))) {
if(PositionGetInteger(POSITION_MAGIC) == InpMagicNumber &&
PositionGetString(POSITION_COMMENT) == comment)
return true;
}
}
return false;
}
Isso garante que cada nível de Z-Score abre no máximo uma posição, independentemente de quantos ticks passem.
O terceiro ponto é o mais refinado. O robô rastreia o Z-Score máximo atingido na variável highestZReached e só entra depois que o preço recuou pelo menos o valor de InpReversalBuffer desse topo:
if(InpWaitReversal && (highestZReached - zScore) < InpReversalBuffer)
continue; // ainda não reverteu o suficiente, aguarda
ExecuteTrade: abrindo a posição
Quando todas as condições são satisfeitas, a ordem é enviada pela função ExecuteTrade. Repare que compras usam o preço Ask e vendas usam o Bid, o que é obrigatório no MT5:
bool ExecuteTrade(ENUM_POSITION_TYPE type, double price, string comment) {
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(type == POSITION_TYPE_BUY)
return trade.Buy(InpLotSize, _Symbol, ask, 0, 0, comment);
else
return trade.Sell(InpLotSize, _Symbol, bid, 0, 0, comment);
}
Ask e Bid são os dois preços de mercado. O Ask é o preço de compra (você paga mais), e o Bid é o preço de venda (você recebe menos). A diferença entre eles é o spread, que é o custo implícito de cada operação.
CheckExitConditions: hora de sair
A saída do EA MQL5 reversão à média Z-Score é simples por design: fecha quando o preço retorna à MME ou o Z-Score se aproxima de zero:
if(type == POSITION_TYPE_BUY && (price >= mme || zScore >= -0.1))
trade.PositionClose(ticket);
if(type == POSITION_TYPE_SELL && (price <= mme || zScore <= 0.1))
trade.PositionClose(ticket);
CheckCycleDrawdown: a proteção mais importante
Essa função calcula o lucro e prejuízo de todas as posições abertas e compara com o saldo da conta. Se a perda superar o percentual configurado em InpMaxDrawdownPct, o EA fecha tudo imediatamente com a função CloseAllPositions:
void CloseAllPositions() {
for(int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket)) {
if(PositionGetInteger(POSITION_MAGIC) == InpMagicNumber &&
PositionGetString(POSITION_SYMBOL) == _Symbol)
trade.PositionClose(ticket);
}
}
}
Note que o loop percorre as posições de trás para frente (de PositionsTotal()-1 até 0). Isso é necessário porque fechar uma posição altera o índice das demais, e percorrer ao contrário evita pular posições.
Honestidade técnica: o EA não tem stop loss por operação individual. A proteção acontece no ciclo inteiro. Em mercados com gaps grandes ou tendências prolongadas, o drawdown pode crescer antes do stop de ciclo ser acionado. Teste sempre em conta demo antes de usar na conta real. Veja mais sobre gestão de risco em nossa categoria de Gestão de Risco.
Um detalhe que passa despercebido: lastTradeTime
O EA usa a variável lastTradeTime para garantir que só executa uma entrada por candle. Isso evita que múltiplos ticks dentro do mesmo candle gerem ordens duplicadas, um detalhe pequeno mas essencial para a estabilidade do EA MQL5 reversão à média Z-Score.
O código completo está disponível para estudo e adaptação. Quer ter acesso? Deixa um comentário ou entre em contato pelo site. No próximo conteúdo vamos mostrar como rodar o backtesting desse EA no Strategy Tester do MT5. Se quiser se aprofundar em backtesting antes, confira nossa categoria de Backtesting e Estatística.







