Kaique Mitsuo Silva Yamamoto
Mercado financeiroAutomação de EstratégiasMetaTrader 5 / MQL5

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 RGB

Constantes 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 valor

Structs 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_STEP

Funçõ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ções

Debug 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áticaPor quê
Sempre normalizar preços e lotesEvita erros de execução
Checar IsTradeAllowed() antes de enviar ordemEvita erro em conta bloqueada
Usar ArraySetAsSeries(true) em buffersÍndice 0 = mais recente (intuitivo)
Liberar handles com IndicatorRelease() no OnDeinitEvita memory leak
Não usar Sleep() em OnTick()Bloqueia o thread do EA
Separar lógica de sinal, risco e execução em classesFacilita backtesting e manutenção

Próximos passos

Referências externas

On this page