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.
Site: rikdomchart.com.br
- Visão Geral
- Arquivos e Pipeline
- Estrutura do Programa e Eventos
- Tipos, Inputs, Enums e Operadores
- Timeframes e Multi-Timeframe (MTF)
- Trade: Ordens, Posições e Tickets
- Loops e Métricas de Posição/Ordem (avançado)
- Backtest, Spread e Critério SL-first
- MQR x MT5 (o que o conversor resolve)
- Checklist de Robustez
- 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.
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ão | Finalidade |
|---|---|
.mqr | Código-fonte da estratégia |
.exr | Estratégia compilada para execução pela engine. |
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
| Evento | Quando dispara | Uso comum |
|---|---|---|
OnInit() | Uma vez no início | SetTimeFrame, estado inicial, buffers |
OnBarCloseM1() | Fechamento de cada M1 | Gestão, horário, trailing, limpeza |
OnBarClose() | Close do timeframe principal | Sinais de entrada e filtros |
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,boolENUM_TIMEFRAMESenumcustomizado
Operadores
- Aritméticos:
+ - * / % - Comparação:
== != < > <= >= - Lógicos:
&& || ! - Atribuição:
= += -= *= /= ++ --
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érie | Descriçã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 |
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.
| Categoria | Funções |
|---|---|
| OHLC/volume/tempo | OpenTF, HighTF, LowTF, CloseTF, VolumeTF, TimeTF |
| Indicadores | SMATF, EMATF, RSITF, ATRTF |
| Estado da barra | BarCountTF, IsBarCompleteTF, IsNewBarTF |
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:
- Direção macro em H1/H4 com
EMATF. - Timing de entrada no TF principal com
RSIou cruzamento de médias locais. - Dimensionamento de stop por volatilidade com
ATR(local) ouATRTF(externo).
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
Close[0] é sempre do timeframe da estratégia. CloseTF(PERIOD_H1, 0) é do H1, mesmo que sua estratégia rode em M1/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.
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.
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.
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.
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.
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
| Grupo | Funções principais |
|---|---|
| Abertura | Buy, Sell, BuyLimit, SellLimit, BuyStop, SellStop |
| Gestão | PositionModify, OrderModify, ClosePosition, CloseAll, OrderDelete |
| Consulta posição | PositionsTotal, PositionTicket, PositionEntry, PositionSL, PositionTP, PositionLots, PositionProfit, PositionType |
| Consulta ordem | OrdersTotal, 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
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)
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)
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)
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
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
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
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();
}
}
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
9) MQR x MT5 (o que o conversor resolve)
| Ponto | MQR | MT5 | Status |
|---|---|---|---|
| Divisão | Semântica em double | int/int pode truncar | Conversor ajusta |
| Módulo | Compatível com double | % é inteiro | Conversor usa fmod |
| Eventos | OnBarCloseM1 + OnBarClose | OnTick | Conversor monta fluxo equivalente |
| Preço de execução | Simulação da engine | Bid/Ask real do tester | Diferença inerente |
10) Checklist de Robustez
- Separar entrada (
OnBarClose) de gestão (OnBarCloseM1) - Controlar risco por ticket e por carteira (PnL agregado)
- Medir preço médio por lote e exposição total
- Limpar pendentes antigas/longe do preço atual
- Otimizar em modo rápido e validar em M1 OHLC
- Comparar resultados MQR x MT5 considerando diferenças inerentes de execução
11) Apêndice: ENUM_TIMEFRAMES completo
| Constante | Minutos |
|---|---|
| PERIOD_CURRENT | 0 |
| PERIOD_M1 | 1 |
| PERIOD_M2 | 2 |
| PERIOD_M3 | 3 |
| PERIOD_M4 | 4 |
| PERIOD_M5 | 5 |
| PERIOD_M6 | 6 |
| PERIOD_M10 | 10 |
| PERIOD_M12 | 12 |
| PERIOD_M15 | 15 |
| PERIOD_M20 | 20 |
| PERIOD_M30 | 30 |
| PERIOD_H1 | 60 |
| PERIOD_H2 | 120 |
| PERIOD_H3 | 180 |
| PERIOD_H4 | 240 |
| PERIOD_H6 | 360 |
| PERIOD_H8 | 480 |
| PERIOD_H12 | 720 |
| PERIOD_D1 | 1440 |
| PERIOD_W1 | 10080 |
| PERIOD_MN1 | 43200 |