MQR - Manual Completo

Referência prática da linguagem MQR com foco em backtest, eventos, ordens, posições, loops de gestão e exportação para MT5.

Responsável: Vinicius Fávero
Site: rikdomchart.com.br
Conteúdo
  1. Visão Geral
  2. Arquivos e Pipeline
  3. Estrutura do Programa e Eventos
  4. Tipos, Inputs, Enums e Operadores
  5. Timeframes e Multi-Timeframe (MTF)
  6. Trade: Ordens, Posições e Tickets
  7. Loops e Métricas de Posição/Ordem (avançado)
  8. Backtest, Spread e Critério SL-first
  9. MQR x MT5 (o que o conversor resolve)
  10. Checklist de Robustez
  11. Apêndice: ENUM_TIMEFRAMES completo

1) Visão Geral

MQR é uma DSL para estratégias de trading com sintaxe inspirada em C++/MQL5. O fluxo padrão é: escrever estratégia, rodar backtest, ajustar parâmetros e, quando necessário, exportar para MT5.

Ponto-chave: mesmo sem OnBarCloseM1(), o motor mantém precisão de execução de TP/SL e pendentes em M1 quando há posições/ordens abertas no modo M1 OHLC.

2) Arquivos e Pipeline

ExtensãoFinalidade
.mqrCódigo-fonte da estratégia
.exrEstratégia compilada para execução pela engine.
Pipeline recomendado
1) Escrever a estratégia em MQR
2) Validar no backtest interno
3) Otimizar parâmetros
4) Revalidar em M1 OHLC
5) Exportar para MT5 quando fizer sentido

3) Estrutura do Programa e Eventos

EventoQuando disparaUso comum
OnInit()Uma vez no inícioSetTimeFrame, estado inicial, buffers
OnBarCloseM1()Fechamento de cada M1Gestão, horário, trailing, limpeza
OnBarClose()Close do timeframe principalSinais de entrada e filtros
Modelo base
input ENUM_TIMEFRAMES inpTF = PERIOD_M5;

void OnInit() {
  SetTimeFrame(inpTF);
}

void OnBarCloseM1() {
  if (Hour() >= 17 && Minute() >= 30 && PositionsTotal() > 0) {
    CloseAll();
  }
}

void OnBarClose() {
  if (BarIndex() < 30) return;
  if (PositionsTotal() > 0) return;

  double ema = EMA(21, 0);
  if (Close[0] > ema) {
    Buy(1.0, Close[0], Close[0] - 80, Close[0] + 120);
  }
}

4) Tipos, Inputs, Enums e Operadores

Tipos base

  • double, int, bool
  • ENUM_TIMEFRAMES
  • enum customizado

Operadores

  • Aritméticos: + - * / %
  • Comparação: == != < > <= >=
  • Lógicos: && || !
  • Atribuição: = += -= *= /= ++ --
Enum + inputs
enum ENUM_DIRECAO {
  COMPRA = 0,
  VENDA  = 1,
  AMBOS  = 2
};

input group "Risco"
input double TP = 120.0 [60, 10, 300];
input double SL = 90.0  [30, 10, 250];

input group "Execucao"
input ENUM_DIRECAO Direcao = AMBOS;
input ENUM_TIMEFRAMES TF = PERIOD_M5;

5) Timeframes e Multi-Timeframe (MTF)

O timeframe principal é definido em OnInit() com SetTimeFrame(). Leituras MTF usam funções *TF sem perder o contexto do candle principal.

5.1) Dados do timeframe do backtest (contexto principal)

As séries Open[], High[], Low[], Close[], Volume[] e Time[] sempre refletem o timeframe principal configurado na estratégia. Esse é o contexto onde OnBarClose() toma decisão de entrada.

Função/SérieDescrição
Open[n], High[n], Low[n], Close[n]OHLC do timeframe principal (n=0 atual, n=1 anterior)
Volume[n], Time[n]Volume e timestamp do candle do contexto principal
BarIndex(), BarCount()Índice atual e quantidade de barras carregadas
Leitura do contexto principal
void OnBarClose() {
  if (BarIndex() < 30) return;

  double c0 = Close[0];
  double c1 = Close[1];
  double rangeAtual = High[0] - Low[0];

  // Exemplo: aceleração simples no candle atual
  if (c0 > c1 && rangeAtual > TickSize() * 20) {
    Print("Sinal no TF principal");
  }
}

5.2) Dados de outros timeframes

Para consultar contexto externo (H1, H4, D1 etc.), use família *TF: OpenTF, CloseTF, EMATF, RSITF, etc. Isso evita reconstruir candles manualmente.

CategoriaFunções
OHLC/volume/tempoOpenTF, HighTF, LowTF, CloseTF, VolumeTF, TimeTF
IndicadoresSMATF, EMATF, RSITF, ATRTF
Estado da barraBarCountTF, IsBarCompleteTF, IsNewBarTF
Entrada em M5 com filtro estrutural de H1
void OnBarClose() {
  // Contexto do backtest (M5, por exemplo)
  double closeLocal = Close[0];

  // Contexto externo (H1)
  double closeH1 = CloseTF(PERIOD_H1, 0);
  double emaH1 = EMATF(PERIOD_H1, 34, 0);

  if (closeH1 > emaH1 && closeLocal > EMA(9, 0) && PositionsTotal() == 0) {
    Buy(1.0, closeLocal, closeLocal - 90, closeLocal + 180);
  }
}

5.3) Como trabalhar com indicadores no mesmo código

Uma abordagem prática é separar: contexto local para gatilho e contexto externo para direção. Exemplos comuns:

Combinação prática: tendência H1 + timing local + stop por ATR
void OnBarClose() {
  if (BarIndex() < 60 || PositionsTotal() > 0) return;

  double trend = EMATF(PERIOD_H1, 50, 0);
  double closeH1 = CloseTF(PERIOD_H1, 0);
  double rsiLocal = RSI(14, 0);
  double atrLocal = ATR(14, 0);
  double p = Close[0];

  if (closeH1 > trend && rsiLocal < 35) {
    Buy(1.0, p, p - atrLocal * 1.5, p + atrLocal * 3.0);
  }
}

5.4) Diferença prática: dado local vs dado externo

Regra rápida: Close[0] é sempre do timeframe da estratégia. CloseTF(PERIOD_H1, 0) é do H1, mesmo que sua estratégia rode em M1/M5.
Filtro de tendência H1 em estratégia M5
void OnBarClose() {
  double trendH1 = EMATF(PERIOD_H1, 34, 0);
  double closeH1 = CloseTF(PERIOD_H1, 0);

  if (closeH1 > trendH1 && RSI(14, 0) < 35 && PositionsTotal() == 0) {
    double p = Close[0];
    Buy(1.0, p, p - 90, p + 180);
  }
}

5.5) Confluência tripla de timeframe (M5 + H1 + H4)

Exemplo de entrada local no timeframe do backtest com dupla confirmação externa. Esse padrão reduz sinais contra a direção macro.

Confluência de tendência em três horizontes
void OnBarClose() {
  if (PositionsTotal() > 0 || BarIndex() < 80) return;

  double p = Close[0];                   // TF do backtest
  double emaM5 = EMA(21, 0);             // indicador local
  double emaH1 = EMATF(PERIOD_H1, 34, 0);
  double closeH1 = CloseTF(PERIOD_H1, 0);
  double emaH4 = EMATF(PERIOD_H4, 55, 0);
  double closeH4 = CloseTF(PERIOD_H4, 0);

  bool macroAlta = (closeH1 > emaH1) && (closeH4 > emaH4);
  bool gatilhoLocal = p > emaM5 && RSI(14, 0) < 45;

  if (macroAlta && gatilhoLocal) {
    Buy(1.0, p, p - 100, p + 220);
  }
}

5.6) RSI local com RSI externo (evitar entrada em exaustão)

Neste padrão, o gatilho acontece no TF principal, mas o RSI de H1 valida se o movimento externo já está esticado.

RSI local + RSI H1
void OnBarClose() {
  if (PositionsTotal() > 0 || BarIndex() < 50) return;

  double rsiM5 = RSI(14, 0);                    // local
  double rsiH1 = RSITF(PERIOD_H1, 14, 0);       // externo
  double p = Close[0];

  // Exemplo de leitura: compra apenas com pullback local e H1 ainda saudável
  if (rsiM5 < 35 && rsiH1 > 45 && rsiH1 < 70) {
    Buy(1.0, p, p - 90, p + 170);
  }
}

5.7) Sincronização por nova barra de outro timeframe

Use IsNewBarTF() para atualizar variáveis de contexto somente quando fechar barra do TF externo, evitando recalcular tudo em todo candle local.

Atualização de contexto H1 apenas no fechamento H1
double contextoH1 = 0.0;

void OnBarCloseM1() {
  if (IsNewBarTF(PERIOD_H1)) {
    double cH1 = CloseTF(PERIOD_H1, 0);
    double eH1 = EMATF(PERIOD_H1, 34, 0);
    contextoH1 = cH1 - eH1; // positivo = acima da média
  }
}

void OnBarClose() {
  if (PositionsTotal() > 0) return;
  if (contextoH1 > 0 && RSI(14, 0) < 40) {
    double p = Close[0];
    Buy(1.0, p, p - 80, p + 160);
  }
}

5.8) ATR externo para stop dinâmico

Quando o TF principal é muito curto, usar ATR de H1/H4 pode estabilizar o tamanho de stop em cenários de ruído intraday.

Stop baseado em ATR de H1
input double FatorSL = 1.2;
input double FatorTP = 2.4;

void OnBarClose() {
  if (PositionsTotal() > 0 || BarIndex() < 80) return;

  double atrH1 = ATRTF(PERIOD_H1, 14, 0);
  double p = Close[0];

  if (CloseTF(PERIOD_H1, 0) > EMATF(PERIOD_H1, 50, 0) && RSI(14, 0) < 38) {
    double sl = p - atrH1 * FatorSL;
    double tp = p + atrH1 * FatorTP;
    Buy(1.0, p, sl, tp);
  }
}

5.9) Exemplo de leitura combinada de OHLC em TF externo

Exemplo simples de padrão de candle em H1 usado como filtro para entrada local no timeframe do backtest.

Filtro de candle H1 (força de fechamento)
bool CandleForteH1() {
  double o = OpenTF(PERIOD_H1, 0);
  double h = HighTF(PERIOD_H1, 0);
  double l = LowTF(PERIOD_H1, 0);
  double c = CloseTF(PERIOD_H1, 0);

  double corpo = Abs(c - o);
  double range = h - l;
  if (range <= 0) return false;

  return (c > o) && (corpo / range >= 0.6);
}

void OnBarClose() {
  if (PositionsTotal() > 0) return;
  if (CandleForteH1() && RSI(14, 0) < 45) {
    double p = Close[0];
    Buy(1.0, p, p - 85, p + 170);
  }
}

6) Trade: Ordens, Posições e Tickets

GrupoFunções principais
AberturaBuy, Sell, BuyLimit, SellLimit, BuyStop, SellStop
GestãoPositionModify, OrderModify, ClosePosition, CloseAll, OrderDelete
Consulta posiçãoPositionsTotal, PositionTicket, PositionEntry, PositionSL, PositionTP, PositionLots, PositionProfit, PositionType
Consulta ordemOrdersTotal, OrderTicket, OrderPrice, OrderSL, OrderTP, OrderLots, OrderType

7) Loops e Métricas de Posição/Ordem (avançado)

Esta seção cobre exatamente os padrões de loop para percorrer ordens/posições abertas e extrair métricas úteis de gestão.

7.1) Loop de posições com PnL total e exposição

Somatório por loop
void OnBarCloseM1() {
  double pnlTotal = 0.0;
  double lotsTotal = 0.0;

  for (int i = 0; i < PositionsTotal(); i++) {
    double tk = PositionTicket(i);
    pnlTotal += PositionProfit(tk);
    lotsTotal += PositionLots(tk);
  }

  Print("PnL=" + pnlTotal + " | Lots=" + lotsTotal);
}

7.2) Preço médio ponderado de entrada (todas as posições)

Preço médio por lotes
double PrecoMedioPosicoes() {
  double somaPxLots = 0.0;
  double somaLots = 0.0;

  for (int i = 0; i < PositionsTotal(); i++) {
    double tk = PositionTicket(i);
    double lots = PositionLots(tk);
    double px = PositionEntry(tk);

    somaPxLots += px * lots;
    somaLots += lots;
  }

  if (somaLots <= 0) return 0.0;
  return somaPxLots / somaLots;
}

void OnBarCloseM1() {
  if (PositionsTotal() > 0) {
    double pm = PrecoMedioPosicoes();
    Print("Preco medio carteiras=" + pm);
  }
}

7.3) Preço médio separado por direção (compra/venda)

Médias por lado
void MediasPorLado(double &pmBuy, double &pmSell, double &lotsBuy, double &lotsSell) {
  double somaBuy = 0.0;
  double somaSell = 0.0;
  lotsBuy = 0.0;
  lotsSell = 0.0;

  for (int i = 0; i < PositionsTotal(); i++) {
    double tk = PositionTicket(i);
    double tp = PositionType(tk);   // 0 compra, 1 venda
    double lt = PositionLots(tk);
    double pe = PositionEntry(tk);

    if (tp == 0) {
      somaBuy += pe * lt;
      lotsBuy += lt;
    } else {
      somaSell += pe * lt;
      lotsSell += lt;
    }
  }

  pmBuy = (lotsBuy > 0) ? (somaBuy / lotsBuy) : 0.0;
  pmSell = (lotsSell > 0) ? (somaSell / lotsSell) : 0.0;
}

7.4) Break-even em lote (ajuste de SL por ticket)

Loop com PositionModify
void OnBarCloseM1() {
  for (int i = 0; i < PositionsTotal(); i++) {
    double tk = PositionTicket(i);
    double lucro = PositionProfit(tk);

    if (lucro >= 120.0) {
      double entrada = PositionEntry(tk);
      double tp = PositionTP(tk);
      PositionModify(tk, entrada, tp); // move SL para break-even
    }
  }
}

7.5) Loop de ordens pendentes e preço médio de ativação

Média de gatilho por pendentes
void OnBarCloseM1() {
  double somaPx = 0.0;
  double somaLots = 0.0;

  for (int i = 0; i < OrdersTotal(); i++) {
    double tk = OrderTicket(i);
    double px = OrderPrice(tk);
    double lt = OrderLots(tk);

    somaPx += px * lt;
    somaLots += lt;
  }

  if (somaLots > 0) {
    double precoMedioPendentes = somaPx / somaLots;
    Print("Preco medio pendentes=" + precoMedioPendentes);
  }
}

7.6) Cancelar pendentes longe do preço atual

Higiene de book de ordens
input double DistMaxTicks = 120.0;

void OnBarCloseM1() {
  double p = Close[0];
  double lim = DistMaxTicks * TickSize();

  for (int i = OrdersTotal() - 1; i >= 0; i--) {
    double tk = OrderTicket(i);
    double op = OrderPrice(tk);

    if (Abs(op - p) > lim) {
      OrderDelete(tk);
    }
  }
}

7.7) Fechamento agregado por alvo de carteira

CloseAll por PnL consolidado
input double AlvoCarteira = 500.0;
input double StopCarteira = -300.0;

void OnBarCloseM1() {
  double pnl = 0.0;

  for (int i = 0; i < PositionsTotal(); i++) {
    double tk = PositionTicket(i);
    pnl += PositionProfit(tk);
  }

  if (pnl >= AlvoCarteira || pnl <= StopCarteira) {
    CloseAll();
  }
}
Observação importante: quando for remover itens em loop de ordens/posições, prefira iterar de trás para frente (for i = total-1; i >= 0; i--) para evitar inconsistência de índice após exclusões.

8) Backtest, Spread e Critério SL-first

M1 OHLC

  • Granularidade por candle M1
  • Mais fiel para validação
  • TP/SL e pendentes avaliados continuamente em M1 quando há posições/ordens

Timeframe do input

  • Mais rápido para otimização
  • Menos detalhe intrabar
  • Use para triagem; valide final em M1 OHLC
Simulação de spread: no backtest, é possível configurar spread em pontos. Esse custo afeta entradas/saídas conforme a lógica Bid/Ask simulada.
Critério SL-first: quando SL e TP poderiam ser tocados na mesma barra, a engine assume SL primeiro (postura conservadora).

9) MQR x MT5 (o que o conversor resolve)

PontoMQRMT5Status
DivisãoSemântica em doubleint/int pode truncarConversor ajusta
MóduloCompatível com double% é inteiroConversor usa fmod
EventosOnBarCloseM1 + OnBarCloseOnTickConversor monta fluxo equivalente
Preço de execuçãoSimulação da engineBid/Ask real do testerDiferença inerente

10) Checklist de Robustez

11) Apêndice: ENUM_TIMEFRAMES completo

ConstanteMinutos
PERIOD_CURRENT0
PERIOD_M11
PERIOD_M22
PERIOD_M33
PERIOD_M44
PERIOD_M55
PERIOD_M66
PERIOD_M1010
PERIOD_M1212
PERIOD_M1515
PERIOD_M2020
PERIOD_M3030
PERIOD_H160
PERIOD_H2120
PERIOD_H3180
PERIOD_H4240
PERIOD_H6360
PERIOD_H8480
PERIOD_H12720
PERIOD_D11440
PERIOD_W110080
PERIOD_MN143200