MQL5 — Fundamentos da Linguagem
Tipos de dados, OOP, structs, arrays, strings e padrões fundamentais de programação em MQL5 para criar EAs e indicadores robustos.
MQL5 — Fundamentos da Linguagem
MQL5 é uma linguagem derivada de C++ com tipagem estática, orientação a objetos completa e acesso nativo à API do MetaTrader 5. Dominar seus fundamentos é o pré-requisito para criar Expert Advisors, indicadores e scripts confiáveis.
Visão geral e estrutura de um EA: MetaTrader 5 — Introdução
Tipos de Dados Primitivos
// Inteiros
int i = 10; // 32 bits com sinal
long l = 100000; // 64 bits com sinal
uchar b = 255; // 8 bits sem sinal (útil para bytes)
// Ponto flutuante
double d = 1.12345; // 64 bits — use para preços
float f = 1.12f; // 32 bits — evite em cálculos financeiros
// Booleano
bool flag = true;
// Caracter e string
uchar c = 'A';
string s = "EURUSD";
// Tipos especiais de MQL5
datetime dt = TimeCurrent(); // timestamp Unix (segundos)
color cor = clrRed; // cor RGBConstantes do símbolo atual
_Symbol // string: nome do ativo (ex: "EURUSD")
_Period // ENUM_TIMEFRAMES: timeframe do gráfico atual
_Point // double: menor variação de preço (ex: 0.00001 em EURUSD 5 dígitos)
_Digits // int: casas decimais do preço (ex: 5 em EURUSD)Arrays em MQL5
// Array estático
double buffer[100];
// Array dinâmico
double series[];
ArrayResize(series, 200);
// Configurar como série temporal (índice 0 = barra mais recente)
ArraySetAsSeries(series, true);
// Copiar buffer de indicador
CopyBuffer(handle, 0, 0, 100, series); // handle, buffer_num, start, count, array
// Copiar dados de preço
MqlRates rates[];
CopyRates(_Symbol, PERIOD_H1, 0, 100, rates);
// rates[0] = barra mais recente
// rates[i].open, .high, .low, .close, .tick_volume, .time
// Funções úteis
int size = ArraySize(series);
ArraySort(series); // ordena ascendente
int idx = ArrayMaximum(series); // índice do maior valor
int idx2 = ArrayMinimum(series); // índice do menor valorStructs nativas importantes
MqlRates — dados OHLC
MqlRates rates[];
CopyRates(_Symbol, PERIOD_D1, 0, 10, rates);
for(int i = 0; i < ArraySize(rates); i++)
{
datetime t = rates[i].time;
double open = rates[i].open;
double high = rates[i].high;
double low = rates[i].low;
double close = rates[i].close;
long vol = rates[i].tick_volume;
int sp = rates[i].spread;
}MqlTick — tick a tick
MqlTick tick;
SymbolInfoTick(_Symbol, tick);
double bid = tick.bid;
double ask = tick.ask;
double last = tick.last;
long vol = tick.volume;
datetime t = tick.time;MqlTradeRequest / MqlTradeResult
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.1;
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.sl = request.price - 50 * _Point;
request.tp = request.price + 100 * _Point;
request.comment = "Entrada manual";
if(!OrderSend(request, result))
Print("Erro: ", result.retcode, " — ", result.comment);Orientação a Objetos em MQL5
Classe básica
class CRiskManager
{
private:
double m_riskPercent;
double m_accountBalance;
public:
// Construtor
CRiskManager(double riskPercent)
{
m_riskPercent = riskPercent;
m_accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
}
// Método público
double CalculateLotSize(double stopLossPips)
{
double riskAmount = m_accountBalance * m_riskPercent / 100.0;
double pipValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double lotSize = riskAmount / (stopLossPips * pipValue);
return NormalizeDouble(lotSize, 2);
}
// Getter
double GetRiskPercent() const { return m_riskPercent; }
};
// Uso no EA
CRiskManager *risk = new CRiskManager(1.0); // 1% de risco
double lots = risk.CalculateLotSize(50);
delete risk;Herança e polimorfismo
// Classe base abstrata para sinais
class CSignalBase
{
public:
virtual bool IsBuySignal() = 0; // método virtual puro
virtual bool IsSellSignal() = 0;
virtual string Name() = 0;
};
// Implementação: sinal de cruzamento de médias
class CMASignal : public CSignalBase
{
private:
int m_fastHandle;
int m_slowHandle;
public:
CMASignal(int fast, int slow)
{
m_fastHandle = iMA(_Symbol, PERIOD_CURRENT, fast, 0, MODE_EMA, PRICE_CLOSE);
m_slowHandle = iMA(_Symbol, PERIOD_CURRENT, slow, 0, MODE_EMA, PRICE_CLOSE);
}
~CMASignal()
{
IndicatorRelease(m_fastHandle);
IndicatorRelease(m_slowHandle);
}
bool IsBuySignal() override
{
double fast[], slow[];
ArraySetAsSeries(fast, true);
ArraySetAsSeries(slow, true);
CopyBuffer(m_fastHandle, 0, 0, 3, fast);
CopyBuffer(m_slowHandle, 0, 0, 3, slow);
return (fast[1] > slow[1] && fast[2] <= slow[2]);
}
bool IsSellSignal() override
{
double fast[], slow[];
ArraySetAsSeries(fast, true);
ArraySetAsSeries(slow, true);
CopyBuffer(m_fastHandle, 0, 0, 3, fast);
CopyBuffer(m_slowHandle, 0, 0, 3, slow);
return (fast[1] < slow[1] && fast[2] >= slow[2]);
}
string Name() override { return "MA Cross"; }
};Enumerações (ENUM)
MQL5 tem centenas de enumerações nativas. As mais usadas:
// Timeframes
PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30
PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1, PERIOD_MN1
// Tipos de ordem
ORDER_TYPE_BUY, ORDER_TYPE_SELL
ORDER_TYPE_BUY_LIMIT, ORDER_TYPE_SELL_LIMIT
ORDER_TYPE_BUY_STOP, ORDER_TYPE_SELL_STOP
// Ações de trade
TRADE_ACTION_DEAL // ordem a mercado
TRADE_ACTION_PENDING // ordem pendente
TRADE_ACTION_SLTP // modificar SL/TP
TRADE_ACTION_MODIFY // modificar ordem pendente
TRADE_ACTION_REMOVE // remover ordem pendente
TRADE_ACTION_CLOSE_BY // fechar posição por posição oposta
// Tipo de posição
POSITION_TYPE_BUY, POSITION_TYPE_SELL
// Informações de conta
ACCOUNT_BALANCE, ACCOUNT_EQUITY, ACCOUNT_MARGIN
ACCOUNT_MARGIN_FREE, ACCOUNT_MARGIN_LEVEL
// Informações de símbolo
SYMBOL_ASK, SYMBOL_BID
SYMBOL_POINT, SYMBOL_DIGITS
SYMBOL_TRADE_TICK_VALUE
SYMBOL_VOLUME_MIN, SYMBOL_VOLUME_MAX, SYMBOL_VOLUME_STEPFunções de Informação de Conta e Símbolo
// Conta
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double margin = AccountInfoDouble(ACCOUNT_MARGIN);
double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
string currency = AccountInfoString(ACCOUNT_CURRENCY);
int leverage = (int)AccountInfoInteger(ACCOUNT_LEVERAGE);
// Símbolo
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double tickVal = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);Normalização de Preços e Lotes
Um dos erros mais comuns em MQL5 é enviar ordens com preços ou volumes fora das especificações do símbolo.
// Normalizar preço
double price = NormalizeDouble(rawPrice, (int)_Digits);
// Normalizar lote (arredondar para múltiplo do step)
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double NormalizeLot(double rawLot)
{
double lot = MathFloor(rawLot / lotStep) * lotStep;
lot = MathMax(lot, minLot);
lot = MathMin(lot, maxLot);
return NormalizeDouble(lot, 2);
}Tratamento de Erros
void OnTick()
{
MqlTradeRequest req = {};
MqlTradeResult res = {};
// ... preenche request ...
if(!OrderSend(req, res))
{
uint retcode = res.retcode;
// Erros que permitem retry imediato
if(retcode == TRADE_RETCODE_REQUOTE ||
retcode == TRADE_RETCODE_PRICE_OFF ||
retcode == TRADE_RETCODE_PRICE_CHANGED)
{
Print("Requote/preço alterado, tentando novamente...");
req.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
OrderSend(req, res);
}
else
{
Print("Erro definitivo: ", retcode, " — ", res.comment);
}
}
}
// Mapeamento dos retcodes mais comuns
// 10004 — REQUOTE: preço mudou, novo Ask/Bid necessário
// 10006 — REJECT: ordem rejeitada pelo servidor
// 10010 — ONLY_REAL: operação disponível apenas em conta real
// 10013 — INVALID_REQUEST: parâmetros inválidos
// 10014 — INVALID_VOLUME: lote inválido
// 10015 — INVALID_PRICE: preço fora dos limites
// 10016 — INVALID_STOPS: SL/TP inválidos
// 10019 — NO_MONEY: margem insuficiente
// 10027 — TOO_MANY_REQUESTS: muitas requisiçõesDebug e Logging
// Print básico (aparece no journal)
Print("Valor: ", price, " | Volume: ", lots);
// Exibe no gráfico (temporário)
Comment("Balance: ", AccountInfoDouble(ACCOUNT_BALANCE),
"\nEquity: ", AccountInfoDouble(ACCOUNT_EQUITY));
// Print formatado
PrintFormat("Posição aberta: %s | Lote: %.2f | PnL: %.2f",
_Symbol, lots, profit);
// Alert (popup)
Alert("Stop loss atingido: ", _Symbol);
// Gravar em arquivo
int file = FileOpen("log_ea.csv", FILE_WRITE | FILE_CSV | FILE_ANSI);
FileWrite(file, TimeToString(TimeCurrent()), _Symbol, lots, price);
FileClose(file);Padrões Recomendados
| Prática | Por quê |
|---|---|
| Sempre normalizar preços e lotes | Evita erros de execução |
Checar IsTradeAllowed() antes de enviar ordem | Evita erro em conta bloqueada |
Usar ArraySetAsSeries(true) em buffers | Índice 0 = mais recente (intuitivo) |
Liberar handles com IndicatorRelease() no OnDeinit | Evita memory leak |
Não usar Sleep() em OnTick() | Bloqueia o thread do EA |
| Separar lógica de sinal, risco e execução em classes | Facilita backtesting e manutenção |
Próximos passos
Referências externas
MetaTrader 5 — MQL5, Expert Advisors e Automação
Hub completo de automação no MetaTrader 5: fundamentos MQL5, gestão de risco em código, ordens avançadas, análise multi-timeframe, otimização e integração com Python/ONNX.
MQL5 — Event Handlers: Estrutura de Execução
Guia completo dos 14 event handlers do MQL5: OnInit, OnDeinit, OnTick, OnCalculate, OnTimer, OnTrade, OnTradeTransaction, OnChartEvent, OnTester e outros — com assinaturas, códigos de retorno e exemplos práticos.