
Scalping Orderflow para MQL5
Introdução
Este Expert Advisor (EA) é um exemplo de sistema de trading algorítmico sofisticado para MetaTrader 5 (MQL5) que utiliza a técnica de Scalping OrderFlow.
Scalping OrderFlow é uma estratégia de negociação de curto prazo que foca em identificar possíveis pontos de entrada e saída no mercado analisando o fluxo de ordens em tempo real. Toma decisões rápidas de negociação combinando o estudo de volume, atividade de preço e dados do book de ofertas. Normalmente, as posições são mantidas por um período muito curto — muitas vezes em minutos ou até segundos
Este EA encontra oportunidades de trading com base em desequilíbrios do fluxo de ordens usando uma variedade de indicadores técnicos e metodologias de análise de mercado. Inclui recursos avançados de gerenciamento de risco, como trailing stops (stop móvel), fechamento parcial de posições e dimensionamento dinâmico de posições. Além disso, o EA incorpora um método para evitar operações durante eventos de notícias importantes e estabelece um limite para perdas consecutivas.
Prever movimentos de preço de curto prazo através da análise em tempo real do book de ofertas e da dinâmica de volume é a ideia fundamental do trading por OrderFlow. Ao combinar esse conceito com outros indicadores técnicos consagrados, este EA desenvolve uma estratégia híbrida que busca identificar oportunidades de alta probabilidade.
A ênfase no gerenciamento de risco é uma das principais características deste EA. O controle de risco eficiente é essencial no volátil mercado de forex, especialmente ao usar táticas de scalping. Para proteger o capital e otimizar os possíveis retornos, o sistema inclui trailing stops, métodos de fechamento parcial de posição e dimensionamento dinâmico de posições.
Graças ao seu design flexível, os traders podem modificar os parâmetros do EA para se adequarem melhor ao seu estilo de negociação e tolerância ao risco. Usuários podem ajustar diversos aspectos do sistema para combinar com seus objetivos e visão de mercado, como limites de volume e períodos dos indicadores.
É fundamental entender que, embora este EA opere automaticamente, ele não é uma solução “plug-and-play”. Os fundamentos do trading em forex, os conceitos de OrderFlow e os indicadores específicos deste sistema devem ser bem compreendidos pelos usuários. É recomendável realizar monitoramento rotineiro e fazer ajustes necessários para garantir o melhor desempenho do EA em diferentes condições de mercado.
O Código
Este Expert Advisor (EA) foi projetado para MetaTrader 5 e implementa uma estratégia avançada de scalping por Order Flow com recursos sofisticados de gerenciamento de risco. O EA começa inicializando vários indicadores técnicos e validando parâmetros de entrada durante a função OnInit(). Configura os handles para indicadores como Médias Móveis, ADX, ATR, RSI e Bandas de Bollinger.
#include <Trade\Trade.mqh> #include <Trade\PositionInfo.mqh> // Input parameters input int VolumeThreshold = 35000; // Volume threshold to consider imbalance input int OrderFlowPeriod = 30; // Number of candles to analyze order flow input double RiskPercent = 1.0; // Risk percentage per trade input int ADXPeriod = 14; // ADX Period input int ADXThreshold = 25; // ADX threshold for strong trend input int MAPeriod = 200; // Moving Average Period input ENUM_TIMEFRAMES Timeframe = PERIOD_M15; // Timeframe for analysis input double MaxLotSize = 0.1; // Maximum allowed lot size input int ATRPeriod = 14; // ATR Period input double ATRMultiplier = 2.0; // ATR Multiplier input int RSIPeriod = 14; // RSI Period input int RSIOverbought = 70; // RSI Overbought level input int RSIOversold = 30; // RSI Oversold level input int MAFastPeriod = 10; // Fast Moving Average Period input int MASlowPeriod = 30; // Slow Moving Average Period input int BollingerPeriod = 20; // Bollinger Bands Period input double BollingerDeviation = 2.5; // Bollinger Bands Standard Deviation input int MaxConsecutiveLosses = 1; // Maximum number of consecutive losses before pausing input int MinBarsBetweenTrades = 1; // Minimum number of bars between trades // Global variables CTrade trade; CPositionInfo positionInfo; int maHandle, adxHandle, atrHandle, rsiHandle, maFastHandle, maSlowHandle, bollingerHandle; int consecutiveLosses = 0; datetime lastTradeTime = 0; int barsSinceLastTrade = 0; // New global variables for statistics int totalTrades = 0; int winningTrades = 0; double totalProfit = 0;
int OnInit() { // Logging initialization Print("Starting Order Flow EA v13..."); // Verify trading permissions if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) { Print("Error: Automated trading is not allowed in the terminal."); return INIT_FAILED; } if(!MQLInfoInteger(MQL_TRADE_ALLOWED)) { Print("Error: Automated trading is not allowed for this EA."); return INIT_FAILED; } // Initialize trading object trade.SetExpertMagicNumber(123456); trade.SetMarginMode(); trade.SetTypeFillingBySymbol(_Symbol); trade.SetDeviationInPoints(10); // 1 pip deviation allowed Print("Trading object initialized."); // Initialize indicators maHandle = iMA(_Symbol, Timeframe, MAPeriod, 0, MODE_SMA, PRICE_CLOSE); adxHandle = iADX(_Symbol, Timeframe, ADXPeriod); atrHandle = iATR(_Symbol, Timeframe, ATRPeriod); rsiHandle = iRSI(_Symbol, Timeframe, RSIPeriod, PRICE_CLOSE); maFastHandle = iMA(_Symbol, Timeframe, MAFastPeriod, 0, MODE_EMA, PRICE_CLOSE); maSlowHandle = iMA(_Symbol, Timeframe, MASlowPeriod, 0, MODE_EMA, PRICE_CLOSE); bollingerHandle = iBands(_Symbol, Timeframe, BollingerPeriod, 0, BollingerDeviation, PRICE_CLOSE); // Verify indicator initialization if(maHandle == INVALID_HANDLE || adxHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE || rsiHandle == INVALID_HANDLE || maFastHandle == INVALID_HANDLE || maSlowHandle == INVALID_HANDLE || bollingerHandle == INVALID_HANDLE) { Print("Error initializing indicators:"); if(maHandle == INVALID_HANDLE) Print("- Invalid MA"); if(adxHandle == INVALID_HANDLE) Print("- Invalid ADX"); if(atrHandle == INVALID_HANDLE) Print("- Invalid ATR"); if(rsiHandle == INVALID_HANDLE) Print("- Invalid RSI"); if(maFastHandle == INVALID_HANDLE) Print("- Invalid Fast MA"); if(maSlowHandle == INVALID_HANDLE) Print("- Invalid Slow MA"); if(bollingerHandle == INVALID_HANDLE) Print("- Invalid Bollinger Bands"); return INIT_FAILED; } Print("All indicators initialized successfully."); // Verify input parameters if(VolumeThreshold <= 0 || OrderFlowPeriod <= 0 || RiskPercent <= 0 || RiskPercent > 100 || ADXPeriod <= 0 || ADXThreshold <= 0 || MAPeriod <= 0 || MaxLotSize <= 0 || ATRPeriod <= 0 || ATRMultiplier <= 0 || RSIPeriod <= 0 || RSIOverbought <= RSIOversold || MAFastPeriod <= 0 || MASlowPeriod <= 0 || BollingerPeriod <= 0 || BollingerDeviation <= 0 || MaxConsecutiveLosses < 0 || MinBarsBetweenTrades < 0) { Print("Error: Invalid input parameters."); return INIT_FAILED; } Print("Input parameters validated."); // Initialize global variables consecutiveLosses = 0; lastTradeTime = 0; barsSinceLastTrade = MinBarsBetweenTrades;
A lógica principal de negociação é executada na função OnTick(), chamada a cada tick de preço. O EA primeiro verifica se uma nova barra foi formada e se a negociação está permitida. Depois, analisa o fluxo de ordens comparando volumes de compra e venda em um determinado período. O EA utiliza múltiplos indicadores técnicos para confirmar sinais de negociação, incluindo força de tendência (ADX), posição do preço em relação às médias móveis e níveis de RSI.
void OnTick() { if(!IsNewBar()) return; Print("Current state - Consecutive losses: ", consecutiveLosses, ", Bars since last trade: ", barsSinceLastTrade); if(!IsTradeAllowed()) { Print("Trading not allowed. Check EA configuration and account permissions."); return; } // Check if there's an open position and manage it if(PositionExists()) { ManageOpenPositions(); return; // Exit if there's an open position } barsSinceLastTrade++; // Increment only if there's no open position if(!IsRiskAcceptable()) { Print("Risk not acceptable."); return; } double buyVolume = 0, sellVolume = 0; AnalyzeOrderFlow(buyVolume, sellVolume); double adxValue[], maValue[], atrValue[], rsiValue[], maFastValue[], maSlowValue[], bollingerUpper[], bollingerLower[]; if(!GetIndicatorData(adxValue, maValue, atrValue, rsiValue, maFastValue, maSlowValue, bollingerUpper, bollingerLower)) return; bool strongTrend = (adxValue[0] > ADXThreshold); bool aboveMA = (SymbolInfoDouble(_Symbol, SYMBOL_LAST) > maValue[0]); bool fastAboveSlow = (maFastValue[0] > maSlowValue[0]); int dynamicSL = (int)(atrValue[0] * ATRMultiplier / SymbolInfoDouble(_Symbol, SYMBOL_POINT)); int dynamicTP = dynamicSL * 3; // Risk/Reward ratio of 1:3 double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); // Conditions for a buy trade if(strongTrend && aboveMA && fastAboveSlow && buyVolume > sellVolume + VolumeThreshold && rsiValue[0] < RSIOverbought && currentPrice < bollingerUpper[0] && barsSinceLastTrade >= MinBarsBetweenTrades) { Print("Buy conditions met. Attempting to open position..."); if(ExecuteTrade(ORDER_TYPE_BUY, dynamicSL, dynamicTP)) { Print("Buy position opened successfully."); barsSinceLastTrade = 0; } } // Conditions for a sell trade else if(strongTrend && !aboveMA && !fastAboveSlow && sellVolume > buyVolume + VolumeThreshold && rsiValue[0] > RSIOversold && currentPrice > bollingerLower[0] && barsSinceLastTrade >= MinBarsBetweenTrades) { Print("Sell conditions met. Attempting to open position..."); if(ExecuteTrade(ORDER_TYPE_SELL, dynamicSL, dynamicTP)) { Print("Sell position opened successfully."); barsSinceLastTrade = 0; } } }
Para o gerenciamento de risco, o EA implementa dimensionamento dinâmico de posição com base em uma porcentagem do saldo da conta e da volatilidade atual do mercado (usando ATR). Também inclui trailing stop e fechamento parcial de posição para travar lucros. O EA limita o risco impondo um número máximo de perdas consecutivas e um número mínimo de barras entre operações.
bool IsRiskAcceptable() { if(IsHighImpactNews()) { Print("Risk not acceptable: High impact news detected."); return false; } if(consecutiveLosses >= MaxConsecutiveLosses) { Print("Risk not acceptable: Maximum consecutive losses reached (", consecutiveLosses, "/", MaxConsecutiveLosses, ")."); return false; } if(barsSinceLastTrade < MinBarsBetweenTrades) { Print("Risk not acceptable: Not enough bars since last trade (", barsSinceLastTrade, "/", MinBarsBetweenTrades, ")."); return false; } double equity = AccountInfoDouble(ACCOUNT_EQUITY); double balance = AccountInfoDouble(ACCOUNT_BALANCE); double drawdown = (balance - equity) / balance * 100; if(drawdown > 20) // Increased from 10% to 20% { Print("Risk not acceptable: Excessive drawdown (", DoubleToString(drawdown, 2), "%)."); return false; } Print("Risk acceptable. Consecutive losses: ", consecutiveLosses, ", Bars since last trade: ", barsSinceLastTrade, ", Current drawdown: ", DoubleToString(drawdown, 2), "%"); return true; }
A função CalculateLotSize() determina o tamanho apropriado da posição com base no saldo da conta, percentual de risco e condições atuais do mercado. A função ManageOpenPositions() gerencia as operações abertas, aplicando trailing stops e fechamentos parciais.
double CalculateLotSize(double stopLossDistance) { double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE); double maxRiskAmount = accountBalance * (RiskPercent / 100); double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); if(tickValue == 0 || stopLossDistance == 0) { Print("Error: Tick value or Stop Loss distance is 0"); return 0; } double lotSize = NormalizeDouble(maxRiskAmount / (stopLossDistance * tickValue), 2); lotSize = MathFloor(lotSize / lotStep) * lotStep; double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); lotSize = MathMax(MathMin(lotSize, maxLot), minLot); lotSize = MathMin(lotSize, MaxLotSize); double margin = AccountInfoDouble(ACCOUNT_MARGIN_FREE); double requiredMargin = SymbolInfoDouble(_Symbol, SYMBOL_MARGIN_INITIAL) * lotSize; if(requiredMargin > margin) { Print("Not enough free margin to open this position. Required: ", requiredMargin, " Available: ", margin); return 0; } Print("Calculated lot size: ", lotSize, " Risk: $", NormalizeDouble(lotSize * stopLossDistance * tickValue, 2)); return lotSize; }
O tratamento de erros é abordado de forma abrangente através da função HandleTradingErrors(), que fornece feedback detalhado sobre vários erros relacionados à negociação. O EA também inclui funções para registrar estatísticas de operações e verificar eventos de notícias de alto impacto (sendo esta última deixada como espaço para implementação pelo usuário).
//+------------------------------------------------------------------+ //| Function for error handling | //+------------------------------------------------------------------+ void HandleTradingErrors(int errorCode) { switch(errorCode) { case TRADE_RETCODE_REQUOTE: Print("Error: Requote"); break; case TRADE_RETCODE_REJECT: Print("Error: Request rejected"); break; case TRADE_RETCODE_CANCEL: Print("Error: Request cancelled by trader"); break; case TRADE_RETCODE_PLACED: Print("Order placed successfully"); break; case TRADE_RETCODE_DONE: Print("Request completed"); break; case TRADE_RETCODE_DONE_PARTIAL: Print("Request partially completed"); break; case TRADE_RETCODE_ERROR: Print("Request processing error"); break; case TRADE_RETCODE_TIMEOUT: Print("Error: Request cancelled by timeout"); break; case TRADE_RETCODE_INVALID: Print("Error: Invalid request"); break; case TRADE_RETCODE_INVALID_VOLUME: Print("Error: Invalid volume in request"); break; case TRADE_RETCODE_INVALID_PRICE: Print("Error: Invalid price in request"); break; case TRADE_RETCODE_INVALID_STOPS: Print("Error: Invalid stops in request"); break; case TRADE_RETCODE_TRADE_DISABLED: Print("Error: Trading is disabled"); break; case TRADE_RETCODE_MARKET_CLOSED: Print("Error: Market is closed"); break; case TRADE_RETCODE_NO_MONEY: Print("Error: Not enough money to complete request"); break; case TRADE_RETCODE_PRICE_CHANGED: Print("Error: Prices changed"); break; case TRADE_RETCODE_PRICE_OFF: Print("Error: No quotes to process request"); break; case TRADE_RETCODE_INVALID_EXPIRATION: Print("Error: Invalid order expiration date"); break; case TRADE_RETCODE_ORDER_CHANGED: Print("Error: Order state changed"); break; case TRADE_RETCODE_TOO_MANY_REQUESTS: Print("Error: Too many requests"); break; case TRADE_RETCODE_NO_CHANGES: Print("Error: No changes in request"); break; case TRADE_RETCODE_SERVER_DISABLES_AT: Print("Error: Autotrading disabled by server"); break; case TRADE_RETCODE_CLIENT_DISABLES_AT: Print("Error: Autotrading disabled by client terminal"); break; case TRADE_RETCODE_LOCKED: Print("Error: Request locked for processing"); break; case TRADE_RETCODE_FROZEN: Print("Error: Order or position frozen"); break; case TRADE_RETCODE_INVALID_FILL: Print("Error: Invalid order filling type"); break; case TRADE_RETCODE_CONNECTION: Print("Error: No connection to trading server"); break; case TRADE_RETCODE_ONLY_REAL: Print("Error: Operation allowed only for live accounts"); break; case TRADE_RETCODE_LIMIT_ORDERS: Print("Error: Pending orders limit reached"); break; case TRADE_RETCODE_LIMIT_VOLUME: Print("Error: Volume limit for orders and positions reached"); break; default: Print("Unknown error: ", errorCode); break; } }
No geral, este EA representa um sistema de trading complexo que combina análise de fluxo de ordens com indicadores técnicos tradicionais e técnicas avançadas de gerenciamento de risco. Foi projetado para traders experientes e deve ser rigorosamente testado antes de ser utilizado em conta real.
Nota: A função para eventos de notícias de alto impacto não está implementada, deixo para você finalizar.
Backtesting
Este EA também funciona nos períodos gráficos de 5, 15 e 30 minutos.
Você deve analisar bem todos os períodos e otimizar o EA antes de pensar em operá-lo.
Estes são os resultados para o período de 15 minutos
Usando dados de gráficos de 15 minutos, esta pesquisa de backtesting mostra como a estratégia se comportou no par EURUSD de 2000 a 2025. Com alavancagem de 1:100 e um depósito inicial de US$ 3000, o tamanho da conta era modesto e a alta alavancagem pode potencializar tanto ganhos quanto perdas. Durante o período do backtesting, a abordagem gerou um retorno modesto de 4,19% sobre o depósito inicial, com lucro líquido total de US$ 125,83.
Com US$ 1,13 de ganhos para cada US$ 1 de perdas, a estratégia mostrou-se ligeiramente lucrativa, conforme indicado pelo fator de lucro de 1,13. Foram realizadas 364 operações no total, sendo 167 operações de compra e 197 de venda. A boa seleção de trades foi indicada pelas altas taxas de acerto: 73,60% para operações de venda e 86,23% para operações de compra.
O método apresentou ganhos médios pequenos, mas perdas maiores quando as operações davam errado, pois o lucro médio por trade vencedor (3,71) era significativamente menor que a perda média por trade perdedor (-12,62 USD). Houve um máximo de 15 operações vencedoras e 5 perdedoras consecutivas. O maior trade vencedor foi de US$ 50,22, enquanto a maior perda foi de -US$ 66,10.
O maior drawdown (redução máxima) da curva de capital foi de 5,63%, o que representa um valor aceitável e indica gestão de risco cuidadosa. A estratégia produziu retornos proporcionais ao risco assumido, conforme mostra o índice de Sharpe de 1,83.
No geral, parece ser uma abordagem de scalping de alta frequência que busca muitos pequenos ganhos, sofrendo ocasionalmente perdas maiores. Como evidenciado pela alta taxa de acerto e baixo fator de lucro, pode ser vulnerável a perdas significativas caso as condições de mercado mudem. Por favor, confira novamente seus resultados.
Período de 5 minutos
Usando dados de gráficos de 5 minutos, este backtesting avalia como a estratégia se saiu no par EURUSD entre 1º de janeiro de 2000 e 1º de fevereiro de 2025. A técnica utiliza um depósito inicial de US$ 3000 com alavancagem de 1:100, o que indica um tamanho de conta relativamente pequeno com alto potencial de amplificação de ganhos e perdas.
De acordo com os resultados, o depósito inicial de US$ 3000 resultou em lucro líquido total de US$ 150,32, ou um retorno modesto de 5,01% ao longo de 25 anos. Foram realizadas 1732 operações usando a estratégia, sendo 1023 vendas e 709 compras. A boa seleção dos trades ficou evidente nas altas taxas de acerto, com 81,82% para vendas e 81,95% para compras.
O método apresentou muitos ganhos pequenos e perdas grandes quando as operações davam errado, já que o lucro médio por trade vencedor (2,27) foi muito menor do que a perda média por trade perdedor (-9,79 USD). Com US$ 1,05 de lucro para cada US$ 1 de perda, a estratégia foi apenas ligeiramente lucrativa, conforme mostra o fator de lucro de 1,05. O maior drawdown da curva de capital foi de 9,95%, valor razoável, mas que pode levantar preocupações em relação ao risco.
A abordagem produziu retornos que só compensaram marginalmente o risco, conforme mostra o índice de Sharpe de 0,92. A curva de capital mostra tendência ascendente, mas com oscilações e quedas notáveis.
Os parâmetros do método recomendam o uso de abordagem multifatorial, empregando vários indicadores técnicos como ADX, RSI, médias móveis e Bandas de Bollinger para as decisões de negociação. No geral, trata-se de uma estratégia de scalping de alta frequência que busca muitos pequenos lucros, mas sofre perdas maiores ocasionalmente. Pode ser difícil gerar retornos substanciais ao longo do tempo e pode ser suscetível a grandes drawdowns em condições de mercado desfavoráveis, dada sua alta taxa de acerto, mas baixo fator de lucro.
Conclusão
Utilizando ferramentas modernas de gerenciamento de risco, este EA para MetaTrader 5 aplica uma abordagem complexa de scalping por Order Flow. Ele combina diferentes indicadores técnicos, análise de fluxo de ordens e dimensionamento dinâmico de posição para identificar oportunidades de negociação forex de alta probabilidade. O backtesting do EA em diferentes timeframes para o par EURUSD, especialmente nos intervalos de 15 e 5 minutos, mostra potencial.
Ainda assim, os resultados apontam vantagens e desvantagens. Apesar das altas taxas de acerto e lucratividade modesta, a estratégia pode não conseguir entregar grandes retornos devido ao baixo fator de lucro e ganhos relativamente pequenos ao longo de períodos longos de teste. Devido à tendência de muitos ganhos pequenos serem anulados por perdas grandes e esporádicas, o método pode estar sujeito a grandes drawdowns em condições desfavoráveis.
*Lembre-se de salvar o arquivo mq5 na pasta MQL5/Experters Advisors/ (ou em algum lugar dentro dela)
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15895





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso
Onde está AnalyzeOrderFlow()?
linha 285
linha 285
Onde estão as outras funções ()?
Terei isso em mente para os próximos artigos. Você ainda pode fazer o download do script e dar uma olhada nele.