Scalping Orderflow for MQL5
Introduction
An example of a sophisticated algorithmic trading system for MetaTrader 5 (MQL5) that uses the Scalping OrderFlow technique is this Expert Advisor (EA).
A short-term trading strategy known as "scalping order flow" focuses on identifying possible entry and exit points in the market by examining the real-time flow of orders. It makes quick trading decisions by combining the study of volume, price activity, and order book data. Typically, positions are held for a very short time—often within minutes or even seconds.
This EA finds trading opportunities based on order flow imbalances by using a variety of technical indicators and market analysis methodologies. Advanced risk management features including trailing stops, partial position closing, and dynamic position size are also included. In addition, the EA incorporates a method to prevent trading during significant news events and sets a limit on consecutive losses.
Predicting short-term price swings through the examination of real-time order book data and volume dynamics is the fundamental idea behind OrderFlow trading. By combining this idea with other established technical analysis indicators, this expert advisor develops a hybrid strategy that seeks to pinpoint high-probability trading opportunities.
The emphasis on risk management in this EA is one of its main characteristics. Effective risk control is essential in the turbulent world of forex trading, especially when using scalping tactics. In order to safeguard capital and optimize possible returns, this system includes trailing stops, partial position closure methods, and dynamic position sizing.
Because of its flexible design, traders can modify the EA's parameters to better fit their trading style and risk tolerance. Users can adjust several aspects of the system to match their trading objectives and market perspectives, such as volume thresholds and indicator periods.
It's crucial to understand that even though this EA trades automatically, it is not a "set and forget" solution. The basics of forex trading, the ideas behind OrderFlow, and the particular indicators included in this system should all be well understood by users. It is advisable to conduct routine monitoring and make necessary modifications to guarantee that the EA operates at its best under different market circumstances.
It's crucial to understand that even though this EA trades automatically, it is not a "set and forget" solution. The basics of forex trading, the ideas behind OrderFlow, and the particular indicators included in this system should all be well understood by users. It is advisable to conduct routine monitoring and make necessary modifications to guarantee that the EA operates at its best under different market circumstances.
The Code
This Expert Advisor (EA) is designed for MetaTrader 5 and implements an advanced Order Flow scalping strategy with sophisticated risk management features. The EA begins by initializing various technical indicators and validating input parameters during the OnInit() function. It sets up handles for indicators such as Moving Averages, ADX, ATR, RSI, and Bollinger Bands.
#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;
The main trading logic is executed in the OnTick() function, which is called on each price tick. The EA first checks if a new bar has formed and if trading is allowed. It then analyzes the order flow by comparing buy and sell volumes over a specified period. The EA uses multiple technical indicators to confirm trading signals, including trend strength (ADX), price position relative to moving averages, and RSI levels.
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; } } }
For risk management, the EA implements dynamic position sizing based on a percentage of account balance and the current market volatility (using ATR). It also includes a trailing stop mechanism and partial position closing to lock in profits. The EA limits risk by enforcing a maximum number of consecutive losses and a minimum number of bars between trades.
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; }
The CalculateLotSize() function determines the appropriate position size based on the account balance, risk percentage, and current market conditions. The ManageOpenPositions() function handles existing trades, implementing trailing stops and partial closures.
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; }
Error handling is comprehensively addressed through the HandleTradingErrors() function, which provides detailed feedback on various trading-related errors. The EA also includes functions for logging trading statistics and checking for high-impact news events (though the latter is left as a placeholder for users to implement).
//+------------------------------------------------------------------+ //| 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; } }
Overall, this EA represents a complex trading system that combines order flow analysis with traditional technical indicators and advanced risk management techniques. It's designed for experienced traders and should be thoroughly tested before live deployment.
Note: High-impact news events function is not done, this I will leave it for you to finish it.
Backtesting
This EA also works in 5, 15 and 30 minutes time periods.
You must analyze well all time periods and Optimize the EA before thinking of trading with it.
This are the results for 15 minutes time period
Using data from 15-minute charts, this backtesting research sheds light on how a trading strategy performed on the EURUSD currency pair from 2000 to 2025. With a 1:100 leverage ratio and a starting deposit of $3000 USD, the account size was comparatively modest, and the high leverage may magnify both profits and losses. During the backtesting period, the approach yielded a modest 4.19% return on the initial 3000 USD deposit, with a total net profit of 125.83 USD.
With 1.13 USD in earnings for every $1 in losses, the strategy appears to have been slightly profitable overall, as indicated by the profit factor of 1.13. 364 trades were performed in total, comprising 167 long trades and 197 short trades. Good trade selection was indicated by the high win rates, which were 73.60% for short trades and 86.23% for long transactions.
The method appeared to have tiny wins but higher losses when trades went against it, since the average profit per winning transaction (3.71) was considerably smaller than the average loss per losing trade (-12.62 USD). There was a maximum of 15 deals with wins and a maximum of 5 trades with losses. The biggest trade that resulted in a profit was 50.22 USD, while the biggest loss was -66.10 USD.
The strategy's greatest drawdown on the equity curve was 5.63%, which is an acceptable amount of loss and indicates prudent risk management. The strategy produced returns that adequately offset the degree of risk assumed, as evidenced by the 1.83 Sharpe ratio.
All things considered, it looks like this is a high-frequency scalping approach that seeks to make lots of little, successful trades while occasionally suffering bigger losses. As evidenced by its high win rate and smaller profit factor, which might make it vulnerable to significant losses in the event that market conditions shift. Please check your answers again.
5 minutes time frame
Using data from 5-minute charts, this backtesting research looks at how a trading strategy performed on the EURUSD currency pair between January 1, 2000, and February 1, 2025. The technique uses an initial deposit of $3000 USD with a 1:100 leverage, which indicates a relatively small account size with high leverage that has the potential to magnify gains as well as losses.
According to the backtesting results, the initial 3000 USD deposit resulted in a total net profit of 150.32 USD, or a modest 5.01% return over the course of 25 years. A total of 1732 transactions were completed using the strategy, comprising 1023 short trades and 709 long positions. Good trade selection was evident in both directions as seen by the high win rates of 81.82% and 81.95% for the short and long trades, respectively.
The method appeared to have many minor wins but huge losses when trades went against it, as the average profit per winning trade (2.27) was much smaller than the average loss per losing trade (-9.79 USD). With 1.05 USD in gains for every $1 in losses, the strategy was only slightly lucrative overall, as indicated by the profit factor of 1.05. The strategy's greatest drawdown on the equity curve was 9.95%, which is a reasonable amount but might raise questions for risk management.
The approach appears to have produced returns that only marginally offset the level of risk incurred, as indicated by the Sharpe ratio of 0.92. The equity curve generally indicates an upward tendency, however there are notable oscillations and downturns.
The method parameters recommend using a complicated multi-factor approach to trade decisions by using a variety of technical indicators, such as ADX, RSI moving averages, and Bollinger Bands. All things considered, it looks like this is a high-frequency scalping approach that seeks to make lots of little, successful trades while occasionally suffering bigger losses. It may find it difficult to provide substantial returns over time and may be susceptible to major drawdowns in unfavorable market situations given its high win rate but low profit component.
Conclusion
Using cutting edge risk management tools, this expert advisor for MetaTrader 5 applies a complex Order Flow scalping approach. It uses a combination of various technical indicators, order flow analysis, and dynamic position size to find high-probability forex trading opportunities. Backtesting the EA on different timeframes for the EURUSD pair, especially on 15-minute and 5-minute intervals, indicates potential.
Still, the outcomes point to both advantages and disadvantages. Despite the strategy's high win rates and modest profitability, it may not be able to produce large returns due to its low profit factor and relatively minor gains over extended testing durations. Due to its propensity for frequent small wins to be offset by bigger, sporadic losses, the method may be susceptible to significant drawdowns in the event of unfavorable market conditions.
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
Where is AnalyzeOrderFlow()?
line 285
line 285
Where is the other functions ()?
I will have it in mind for next Articles. You can still download the script, and look them.