
Скальпинг по потоку ордеров (Order Flow Scalping) с MQL5
Введение
В этой статье рассматривается советник, который представляет собой пример сложной алгоритмической торговой системы для MetaTrader 5 (MQL5), работающей по методу скальпинга потока ордеров Scalping OrderFlow.
Это краткосрочная торговая стратегия, которая пытается определить возможные точки входа и выхода, изучая потока ордеров в режиме реального времени. Советник быстро принимает торговые решения на основе анализа объемов, ценовой активности и данных о портфеле ордеров. Обычно позиции удерживаются очень короткое время — часто в течение минут или даже секунд.
Данный советник находит торговые возможности на основе дисбаланса потока ордеров, используя различные технические индикаторы и методологии анализа рынка. Также включены расширенные функции управления рисками, включая трейлинг-стопы, частичное закрытие позиций и динамический размер позиции. Кроме того, в советник включен запрет торговли во время важных новостных событий, а также ограничение последовательных убыточных серий.
Прогнозирование краткосрочных колебаний цен на основе анализа данных о портфеле заказов и динамики объема в режиме реального времени является фундаментальной идеей, лежащей в основе торговли OrderFlow. Объединив эту идею с другими популярными индикаторами технического анализа, данный советник разрабатывает гибридную стратегию, направленную на определение потенциальных возможностей для торговли.
Также важная часть в советнике — управление рисками. Как мы знаем, особенно большое значение контроль рисков имеет при скальпинге. Чтобы сохранить капитал и при этом оптимально использовать торговые возможности, мы будем использовать трейлинг-стопы, частичное закрытие позиций и динамическое определение размера позиции.
Благодаря гибкому дизайну трейдеры могут изменять параметры советника, чтобы он лучше соответствовал их стилю торговли и готовности к риску. Пользователи могут настроить несколько аспектов системы в соответствии со своими торговыми целями и перспективами рынка, такими как пороговые значения объема и периоды индикации.
Важно понимать, что, несмотря на то, что этот советник торгует автоматически, он не является решением из ряда "установил и забыл". Пользователи должны хорошо понимать основы торговли на рынке Форекс, идеи, лежащие в основе OrderFlow, а также конкретные индикаторы, включенные в данную систему. Рекомендуется проводить регулярный мониторинг и вносить необходимые изменения, чтобы гарантировать наилучшую работу советника в различных рыночных условиях.
Код
Данный советник (EA) разработан для MetaTrader 5 и реализует передовую стратегию скальпинга потока ордеров со сложными функциями управления рисками. Советник начинает работу с инициализации различных технических индикаторов и проверки входных параметров во время работы функции OnInit(). Он настраивает хэндлы для таких индикаторов, как скользящие средние, ADX, ATR, RSI и Полосы Боллинджера.
#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;
Основная торговая логика выполняется в функции OnTick(), которая вызывается на каждом ценовом тике. Сначала советник проверяет, сформировался ли новый бар и разрешена ли торговля. Затем он анализирует поток ордеров путем сравнения объемов покупок и продаж за определенный период. Советник использует множество технических индикаторов для подтверждения торговых сигналов, включая силу тренда (ADX), положение цены относительно скользящих средних, а также уровни 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; } } }
Для управления рисками советник реализует динамическое определение размера позиции на основе процента от баланса счета и текущей волатильности рынка (с использованием ATR). Он также включает в себя механизм трейлинг-стопа и частичного закрытия позиций для фиксации прибыли. Советник ограничивает риск, устанавливая максимальное количество последовательных потерь и минимальное количество баров между сделками.
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; }
Функция CalculateLotSize() определяет подходящий размер позиции на основе баланса счета, процента риска и текущих рыночных условий. Функция ManageOpenPositions() обрабатывает существующие сделки, реализуя трейлинг-стопы и частичное закрытие.
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; }
Обработка ошибок осуществляется с помощью функции HandleTradingErrors(), которая предоставляет подробную информацию о различных связанных с торговлей ошибках. Советник также включает в себя функции для ведения торговой статистики и проверки важных новостных событий (хотя последнее оставлено в качестве индикатора-пустышки для реализации пользователями).
//+------------------------------------------------------------------+ //| 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; } }
В целом, данный советник представляет собой сложную торговую систему, сочетающую в себе анализ потока ордеров с традиционными техническими индикаторами и передовыми методами управления рисками. Он предназначен для опытных трейдеров и перед внедрением на практике его необходимо тщательно протестировать.
Примечание: Функция «Важные новостные события» (High-impact news events) не реализована, мы предоставим вам возможность завершить ее.
Тестирование на истории
Данный советник также работает с периодами в 5, 15 и 30 минут.
Прежде чем задумываться о торговле с помощью советника, необходимо тщательно проанализировать все временные периоды и оптимизировать его.
Это результаты за 15-минутный период времени
Используя данные 15-минутных графиков, настоящее исследование, посвященное бэк-тестированию, проливает свет на то, как работала торговая стратегия на валютной паре EURUSD с 2000 по 2025 годы. При коэффициенте финансового левериджа 1:100 и стартовом депозите в размере 3000 долларов США размер счета был сравнительно небольшим, а высокий леверидж может увеличить как прибыль, так и убытки. В течение периода бэк-тестирования данный подход принес скромную прибыль в размере 4,19% от первоначального депозита в размере 3000 долларов США при общей чистой прибыли в размере 125,83 долларов США.
Учитывая прибыль в размере 1,13 доллара США на каждый убыток в размере 1 доллара США, стратегия, по-видимому, в целом была немного прибыльной, о чем свидетельствует коэффициент прибыли, равный 1,13. Всего было совершено 364 сделки, в том числе 167 долгосрочных и 197 краткосрочных сделок. На хороший выбор сделок указывали высокие показатели прибыли, составившие 73,60% для краткосрочных сделок и 86,23% для долгосрочных сделок.
Оказалось, что данный метод приносил небольшие прибыли, но и более высокие убытки, когда сделки шли вразрез с ним, поскольку средняя прибыль на выигрышную сделку (3,71) была значительно меньше, чем средний убыток на убыточную сделку (-12,62 доллара США). Заключено максимум 15 сделок с прибылью и максимум 5 сделок с убытком. Самая крупная сделка, приведшая к прибыли, составила 50,22 доллара США, в то время как самый большой убыток составил -66,10 доллара США.
Наибольшая просадка по кривой эквити в рамках данной стратегии составила 5,63%, что является приемлемой величиной убытка и свидетельствует о разумном управлении рисками. Стратегия принесла доход, который адекватно компенсировал степень принятого риска, о чем свидетельствует коэффициент Шарпа, равный 1,83.
Учитывая все соответствующие обстоятельства, похоже, что это - высокочастотный подход к скальпингу, направленный на совершение множества небольших успешных сделок; в то же время он периодически терпит большие убытки. Об этом свидетельствует его высокий коэффициент выигрыша и меньший коэффициент прибыли, что может сделать его уязвимым к значительным потерям в случае изменения рыночных условий. Проверьте свои ответы еще раз.
Таймфрейм с периодом в 5 минут
Используя данные 5-минутных графиков, в настоящем исследовании, посвященном бэк-тестированию, рассматривается эффективность торговой стратегии на валютной паре EURUSD в период с 1 января 2000 года по 1 февраля 2025 года. В этом методе используется первоначальный депозит в размере 3000 долларов США с кредитным плечом 1:100, что указывает на относительно небольшой размер счета с высоким кредитным плечом, которое потенциально может увеличить как прибыль, так и убытки.
Согласно результатам бэк-тестирования, первоначальный депозит в размере 3000 долларов США принес общую чистую прибыль в размере 150,32 долларов США, или скромную доходность в размере 5,01% в течение 25 лет. С использованием стратегии совершено в общей сложности 1732 сделки, в том числе 1023 краткосрочные сделки и 709 длинных позиций. Хороший выбор сделок был очевиден в обоих направлениях, о чем свидетельствуют высокие показатели выигрыша в 81,82% и 81,95% для краткосрочных и долгосрочных сделок соответственно.
Оказалось, что этот метод приносил много незначительных выигрышей, но огромные убытки, когда сделки шли вразрез с ним, поскольку средняя прибыль на выигрышную сделку (2,27) была намного меньше, чем средний убыток на убыточную сделку (-9,79 доллара США). При прибыли в 1,05 доллара США на каждый убыток в 1 доллар стратегия в целом была прибыльной лишь незначительно, о чем свидетельствует коэффициент прибыли, равный 1,05. Наибольшая просадка стратегии по кривой эквити составила 9,95%, что является обоснованной величиной, но может вызвать вопросы к управлению рисками.
Данный подход, по-видимому, позволил получить доходность, которая лишь незначительно компенсирует уровень понесенного риска, о чем свидетельствует коэффициент Шарпа, равный 0,92. Кривая капитала в целом демонстрирует тенденцию к росту, однако наблюдаются заметные колебания и спады.
Параметры метода рекомендуют использовать сложный многофакторный подход к принятию торговых решений с использованием различных технических индикаторов, таких как ADX, скользящие средние RSI и Полосы Боллинджера. Учитывая все соответствующие обстоятельства, похоже, что это высокочастотный подход к скальпингу, направленный на совершение множества небольших успешных сделок; в то же время он периодически терпит большие убытки. Ему может быть трудно обеспечить существенную прибыль с течением времени, также он может быть подвержен серьезным просадкам в неблагоприятных рыночных ситуациях, учитывая его высокий процент выигрышей, но низкую составляющую прибыли.
Заключение
Используя передовые инструменты управления рисками, данный советник для MetaTrader 5 применяет комплексный подход к скальпированию потока ордеров. В нем используется сочетание различных технических индикаторов, анализ потока ордеров и динамический размер позиции, чтобы найти возможности для успешной торговли на рынке Форекс с высокой вероятностью. Бэк-тестирование советника на разных таймфреймах для пары EURUSD, особенно на 15-минутных и 5-минутных интервалах, указывает на потенциал.
Тем не менее, результаты указывают как на преимущества, так и на недостатки. Несмотря на высокие показатели выигрыша и скромную прибыльность стратегии, возможно, что она не будет способна приносить большой прибыли из-за низкого коэффициента прибыли и относительно незначительной прибыли при длительном тестировании. Из-за своей склонности к тому, что частые небольшие выигрыши компенсируются более крупными, спорадическими потерями, данный метод может быть подвержен значительным просадкам в случае неблагоприятных рыночных условий.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/15895
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Где находится AnalyzeOrderFlow()?
строка 285
линия 285
Где находятся другие функции ()?
Я буду иметь это в виду для следующих статей. Вы все еще можете скачать скрипт и посмотреть на них.