MQL5 — Análise Multi-Timeframe (MTF)
Como ler e combinar dados de múltiplos timeframes em MQL5: CopyRates, CopyBuffer com timeframe externo, sincronização de barras e padrões MTF em Expert Advisors.
MQL5 — Análise Multi-Timeframe (MTF)
A análise multi-timeframe é um dos princípios mais poderosos do trading profissional: usar o timeframe maior para direção e o menor para timing de entrada. Em MQL5, isso é direto — todas as funções de cópia de dados aceitam um parâmetro de timeframe independente do gráfico atual.
Fundamentos: MQL5 — Fundamentos
Lendo OHLC de qualquer Timeframe
MqlRates ratesH4[];
ArraySetAsSeries(ratesH4, true);
// Copia 100 barras do H4, independente do gráfico atual
int copied = CopyRates(_Symbol, PERIOD_H4, 0, 100, ratesH4);
if(copied <= 0)
{
Print("Erro ao copiar H4: ", GetLastError());
return;
}
double h4Close_0 = ratesH4[0].close; // barra atual H4 (em formação)
double h4Close_1 = ratesH4[1].close; // última barra H4 fechada
double h4High_1 = ratesH4[1].high;
double h4Low_1 = ratesH4[1].low;CopyBuffer de indicador em outro timeframe
// Criar handle de MA no H4
int maH4Handle = iMA(_Symbol, PERIOD_H4, 200, 0, MODE_SMA, PRICE_CLOSE);
double maH4[];
ArraySetAsSeries(maH4, true);
CopyBuffer(maH4Handle, 0, 0, 3, maH4);
double maH4_value = maH4[1]; // valor da MA200 H4 na última barra fechadaPadrão: Direção no H4, Entrada no M15
Estrutura clássica de EA MTF:
#include <Trade/Trade.mqh>
input int MA_H4_Period = 200;
input int MA_M15_Period = 20;
input double RiskPercent = 1.0;
int g_maH4Handle;
int g_maM15Handle;
int g_atrHandle;
CTrade trade;
int OnInit()
{
g_maH4Handle = iMA(_Symbol, PERIOD_H4, MA_H4_Period, 0, MODE_SMA, PRICE_CLOSE);
g_maM15Handle = iMA(_Symbol, PERIOD_M15, MA_M15_Period, 0, MODE_EMA, PRICE_CLOSE);
g_atrHandle = iATR(_Symbol, PERIOD_M15, 14);
trade.SetExpertMagicNumber(20250101);
return(INIT_SUCCEEDED);
}
// Retorna +1 (bullish), -1 (bearish), 0 (neutro)
int GetH4Bias()
{
double maH4[], closeH4[];
ArraySetAsSeries(maH4, true);
ArraySetAsSeries(closeH4, true);
CopyBuffer(g_maH4Handle, 0, 0, 3, maH4);
MqlRates ratesH4[];
ArraySetAsSeries(ratesH4, true);
CopyRates(_Symbol, PERIOD_H4, 0, 3, ratesH4);
if(ratesH4[1].close > maH4[1]) return 1;
if(ratesH4[1].close < maH4[1]) return -1;
return 0;
}
// Verifica sinal no M15 (cruzamento de EMA)
bool IsM15BuySignal()
{
double maM15[];
ArraySetAsSeries(maM15, true);
CopyBuffer(g_maM15Handle, 0, 0, 3, maM15);
MqlRates rates[];
ArraySetAsSeries(rates, true);
CopyRates(_Symbol, PERIOD_M15, 0, 3, rates);
return (rates[1].close > maM15[1] && rates[2].close <= maM15[2]);
}
bool IsM15SellSignal()
{
double maM15[];
ArraySetAsSeries(maM15, true);
CopyBuffer(g_maM15Handle, 0, 0, 3, maM15);
MqlRates rates[];
ArraySetAsSeries(rates, true);
CopyRates(_Symbol, PERIOD_M15, 0, 3, rates);
return (rates[1].close < maM15[1] && rates[2].close >= maM15[2]);
}
void OnTick()
{
// Executar apenas na abertura de nova barra M15
static datetime lastBar = 0;
datetime currentBar = iTime(_Symbol, PERIOD_M15, 0);
if(currentBar == lastBar) return;
lastBar = currentBar;
if(PositionsTotal() > 0) return;
int bias = GetH4Bias();
double atr[];
ArraySetAsSeries(atr, true);
CopyBuffer(g_atrHandle, 0, 0, 3, atr);
double stopDist = atr[1] * 1.5;
if(bias == 1 && IsM15BuySignal())
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = ask - stopDist;
double tp = ask + stopDist * 2.0;
double lots = CalculateLotByRisk(RiskPercent, stopDist / _Point);
trade.Buy(lots, _Symbol, ask, sl, tp, "MTF Buy");
}
else if(bias == -1 && IsM15SellSignal())
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = bid + stopDist;
double tp = bid - stopDist * 2.0;
double lots = CalculateLotByRisk(RiskPercent, stopDist / _Point);
trade.Sell(lots, _Symbol, bid, sl, tp, "MTF Sell");
}
}Sincronização de Barras — Executar Apenas em Barra Nova
Um erro crítico: executar lógica em cada tick em vez de em cada nova barra. Em M15, isso pode significar centenas de avaliações desnecessárias por barra.
// Forma correta: comparar tempo da barra atual
bool IsNewBar(ENUM_TIMEFRAMES tf = PERIOD_CURRENT)
{
static datetime lastTime = 0;
datetime currentTime = iTime(_Symbol, tf, 0);
if(currentTime != lastTime)
{
lastTime = currentTime;
return true;
}
return false;
}
// Uso no OnTick
void OnTick()
{
if(!IsNewBar(PERIOD_M15)) return; // só processa na abertura de barra M15
// ... lógica ...
}Para múltiplos timeframes simultaneamente
struct BarTracker
{
ENUM_TIMEFRAMES tf;
datetime lastTime;
bool IsNew(const string symbol)
{
datetime t = iTime(symbol, tf, 0);
if(t != lastTime) { lastTime = t; return true; }
return false;
}
};
BarTracker g_barH4 = { PERIOD_H4, 0 };
BarTracker g_barM15 = { PERIOD_M15, 0 };
void OnTick()
{
bool newH4 = g_barH4.IsNew(_Symbol);
bool newM15 = g_barM15.IsNew(_Symbol);
if(newH4) UpdateH4Context(); // atualiza viés e zonas H4
if(newM15) CheckM15Entries(); // verifica setup de entrada
}Detectar Estrutura de Mercado em MTF
// Detectar se H4 está em tendência de alta (HH + HL)
bool IsH4Uptrend(int lookback = 5)
{
MqlRates rates[];
ArraySetAsSeries(rates, true);
int copied = CopyRates(_Symbol, PERIOD_H4, 1, lookback * 2, rates);
if(copied < lookback * 2) return false;
// Verificar sequência de topos e fundos ascendentes
double lastHigh = rates[0].high;
double lastLow = rates[0].low;
int higherHighs = 0;
int higherLows = 0;
for(int i = 1; i < copied; i++)
{
if(rates[i].high > lastHigh) { higherHighs++; lastHigh = rates[i].high; }
if(rates[i].low > lastLow) { higherLows++; lastLow = rates[i].low; }
}
return (higherHighs >= lookback / 2 && higherLows >= lookback / 2);
}Ler nível de suporte/resistência do H4 no M15
Identifica o suporte/resistência mais próximo do H4 e usa como referência no M15.
void GetH4SupportResistance(double &support, double &resistance, int lookback = 20)
{
MqlRates rates[];
ArraySetAsSeries(rates, true);
CopyRates(_Symbol, PERIOD_H4, 1, lookback, rates);
double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
support = DBL_MAX * -1;
resistance = DBL_MAX;
for(int i = 0; i < lookback; i++)
{
// Pivô de alta (barra com high maior que vizinhas)
if(i > 0 && i < lookback - 1)
{
if(rates[i].high > rates[i-1].high && rates[i].high > rates[i+1].high)
{
if(rates[i].high > price && rates[i].high < resistance)
resistance = rates[i].high;
}
if(rates[i].low < rates[i-1].low && rates[i].low < rates[i+1].low)
{
if(rates[i].low < price && rates[i].low > support)
support = rates[i].low;
}
}
}
}Boas práticas MTF
| Prática | Razão |
|---|---|
Criar handles no OnInit(), não no OnTick() | Handles são custosos — criar 1x e reusar |
Liberar handles no OnDeinit() | Evita memory leak |
| Usar barras fechadas (índice 1) para sinais | Barras em formação (índice 0) mudam a cada tick |
Não criar loops internos ao OnTick() sem controle | Pode travar o terminal em ativos com muitos ticks |
Validar CopyRates() > 0 antes de usar o array | Falhas de cópia retornam -1 ou 0 |
Usar PERIOD_CURRENT só quando intencional | Explicitar sempre o timeframe evita bugs sutis |
Combinações MTF recomendadas
| Estratégia | Timeframe macro | Timeframe de entrada |
|---|---|---|
| Swing trade forex | D1 / H4 | H1 / M30 |
| Day trade índices | H4 / H1 | M15 / M5 |
| Scalping | H1 / M30 | M5 / M1 |
| Position trade | W1 / D1 | H4 / H1 |
Referências
Referências externas
MQL5 — Ordens Avançadas e Gerenciamento de Posição
Trailing stop, fechamento parcial, ordens pendentes, OCO, gestão de múltiplas posições e padrões avançados de execução em MQL5.
MQL5 — Otimização e Robustez de Estratégias
Walk forward testing, análise de sensibilidade, evitar overfitting, métricas de qualidade e validação estatística de Expert Advisors no Strategy Tester do MetaTrader 5.