English 中文 Español Deutsch 日本語 Português
preview
Стратегия торговли каскадами ордеров на основе пересечений EMA для MetaTrader 5

Стратегия торговли каскадами ордеров на основе пересечений EMA для MetaTrader 5

MetaTrader 5Трейдинг | 12 февраля 2025, 09:29
641 2
Kikkih25
Kikkih25

Введение 

В этой статье мы демонстрируем стратегию торговли каскадами ордеров советника (EA) для рынка Форекс, разработанного на языке MetaQuotes Language 5 (MQL5) для MetaTrader 5. Статья посвящена советнику на MQL5, использующему пересечения скользящих средних в качестве основы торговой стратегии, и описывает автоматизацию принятия торговых решений на платформе MetaTrader 5. Кроме того, в статье рассматриваются основные функции инициализации, настройки и мониторинга позиций. Для эффективного управления ордерами в ней также используется библиотека Trade.mqh.

В первую очередь, изначально в рамках данной методики используются два экспоненциальных скользящих средних (EMA) с предварительно заданными периодами. При пересечении этих скользящих средних формируется сигнал на покупку или продажу в зависимости от направления такого пересечения. Ордера устанавливаются с указанными уровнями тейк-профит и стоп-лосс, которые корректируются динамически по мере движения рынка.

Кроме того, скрипт содержит процедуру определения новых баров, что имеет большое значение для обеспечения принятия торговых решений на основе полностью сформированных свечей. Более того, предлагается функция корректировки текущего актива при достижении целевых показателей прибыли.

Рекомендуемый советник в целом демонстрирует, как можно использовать MQL5 для практической реализации системной торговой стратегии с помощью автоматического исполнения и технических индикаторов, чтобы совершать сделки по заранее определенным правилам.

В статье мы обсуждаем следующие темы:

  1. Объяснение стратегии торговли каскадами ордеров
  2. Реализация советника на MQL5
  3. Заключение


Объяснение стратегии торговли каскадами ордеров 

Стратегия торговли каскадами ордеров описывает метод, при котором для определения момента размещения более позднего ордера используются результаты или условия ранее размещенных ордеров. Эта стратегия часто применяется в трейдинге для управления и оптимизации входов в рынок, выходов из него и размеров позиций на основе движений рынка и заранее заданных правил. Вот подробное описание возможной работы торговой стратегии, применяющей каскады ордеров.

Основные компоненты стратегии торговли каскадами ордеров:

  1. Последовательное размещение ордеров: Стратегия торговли каскадами ордеров подразумевает последовательную инициацию сделок в ответ на заранее определенные события или условия. Первоначальный ордер может разместить трейдер, например, в ответ на конкретный сигнал технического индикатора.
  2. Условный ордер: Будущие ордера размещаются в зависимости от результатов предыдущих сделок или состояния рынка. Если рынок движется в вашу пользу, это может повлечь за собой размещение большего количества ордеров для масштабирования позиции.
  3. Масштабирование: Для контроля риска и оптимизации потенциальной прибыльности каскадная стратегия часто подразумевает постепенное вхождение в позицию. С другой стороны, масштабирование в сторону увеличения влечет за собой уменьшение размера позиции при достижении целевых показателей прибыли или отрицательном движении рынка.
  4. Управление рисками: Для сведения потерь к минимуму в каскадных методах важную роль играет эффективное управление рисками. Это подразумевает установление пороговых уровней стоп-лосс для каждого ордера либо динамичное изменение таких уровней по мере изменения позиции.

Фиксация прибыли: При выполнении определенных требований принимаются меры по закреплению прибылей. Целевые уровни тейк-профита устанавливаются для каждого ордера на всех этапах сделки. Это гарантирует трейдерам прибыль, допуская при этом дополнительное увеличение прибыли, если того потребуют условия рынка.

Вот график, обобщающий описание стратегии торговли каскадами ордеров:

Стратегия торговли каскадами ордеров


Реализация советника на MQL5

Во-первых, Trade.mqh в MQL5 — это мощная и практичная библиотека, которая упрощает торговую деятельность. Она предлагает высокоуровневый интерфейс для открытия, изменения и удаления позиций и ордеров. Включение в систему библиотеки Trade.mqh дает нам доступ к классу CTrade, что упрощает и инкапсулирует многие сложные детали торговой деятельности, повышая качество читаемости и удобство использования нашего кода.

#include <Trade/Trade.mqh>
CTrade obj_Trade;

После подключения библиотеки Trade.mqh можно получить доступ к классу CTrade, экземпляр которого мгновенно создается в виде объекта obj_Trade. Мы заметили, что многие имеющиеся у нас функциональные возможности для торговли инкапсулированы в класс CTrade. Ниже приведены некоторые основные методы, предлагаемые классом CTrade:

  1.  Выставление ордера
  2.  Модификация ордера
  3.  Завершение ордера

Затем переходим к глобальным переменным, которые имеют решающее значение для работы торговой стратегии и выполняют в советнике (EA) множество различных функций. Поговорим о каждой глобальной переменной и ее значении:

  •  Переменная в целых числах

int handleMAFast;
int handleMASlow;

В этих переменных хранятся хендлы, или идентификаторы, для индикаторов медленного и быстрого скользящих средних, вычисленных функцией OnInit. Чтобы извлечь текущие значения этих индикаторов, для доступа к их буферам требуются хендлеры.

  • Двойные массивы для скользящих средних

double maSlow[],maFast[];

В этих массивах хранятся значения быстрых и медленных скользящих средних, полученные из буферов индикаторов. В целях анализа и принятия торговых решений их используют для хранения текущих и исторических значений индикаторов.

  • Двойные переменные Take Profit и Stop Loss

double takeProfit = 0;
double stopLoss = 0;

В этой переменной в настоящее время хранятся уровни тейк-профита (TP) и стоп-лосса (SL) для торговых операций. Они используются для размещения или изменения торговых ордеров и обновляются в соответствии с условиями рынка.

  •  Зарезервированные переменные состояния системы

bool isBuySystemInitiated = false;
bool isSellSystemInitiated = false;

Эти зарезервированные флаги отслеживают начальное состояние покупки и продажи торговых систем. Они помогают предотвратить появление ненужных или дублирующих ордеров и обеспечивают размещение ордеров только при соблюдении определенных критериев (например, пересечений скользящих средних).

  • Параметры для ввода

input int slPts = 300;
input int tpPts = 300;
input double lot = 0.01;
input int slPts_Min = 100;
input int fastPeriods = 10;
input int slowPeriods = 20;

Эти переменные — входные параметры, которые, не меняя сам код, позволяют осуществлять внешнюю настройку характеристик советника. Трейдеры могут модифицировать эти параметры через настройки советника интерфейса MetaTrader. Они управляют переменными, включая тейк-профит, стоп-лосс, размер лота и быстро меняющиеся периоды.

После объяснения значения переменных нам стало понятно, что данные, доступ к которым необходим через тики и функции, хранятся в глобальных переменных на MQL5. Это связано с тем, что они служат для хранения важных данных, включая параметры ордеров, статус сделки, значения индикаторов и пользовательские настройки. Они используются для реализации торговой стратегии, поддержания позиций и реагирования на рыночные условия; различные функции советника получают доступ к этим переменным и изменяют их.

Конечно! Разберем часть кода, отвечающую за инициализацию. Функция OnInit отвечает за настройку начального состояния советника. Сначала с помощью функции iMa происходит создание хендлов для быстрых и медленных скользящих средних. Проверим, действительны ли эти хендлы. Если какой-либо хендл недействителен, инициализация завершится неудачно. Затем установим массивы maFast и maSlow как массивы временных рядов с помощью ArraySetAsSeries. Наконец, возвращаем успешное выполнение.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){
   
   handleMAFast = iMA(_Symbol,_Period,fastPeriods,0,MODE_EMA,PRICE_CLOSE);
   if (handleMAFast == INVALID_HANDLE){
      Print("UNABLE TO LOAD FAST MA, REVERTING NOW");
      return (INIT_FAILED);
   }
   
   handleMASlow = iMA(_Symbol,_Period,slowPeriods,0,MODE_EMA,PRICE_CLOSE);
   if (handleMASlow == INVALID_HANDLE){
      Print("UNABLE TO LOAD SLOW MA, REVERTING NOW");
      return (INIT_FAILED);
   }
   
   ArraySetAsSeries(maFast,true);
   ArraySetAsSeries(maSlow,true);
   
   return(INIT_SUCCEEDED);
}

После этого рассмотрим функцию деинициализации. В системе советников MQL5 функция вызывается при закрытии советника или удалении его с графика. Именно здесь и происходит очистка задач.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }

В этом экземпляре функция пуста, что указывает на отсутствие выполнения каких-либо конкретных действий после деинициализации советника. 

Функция принимает целочисленный параметр reason, указывающий на причину деинициализации. Такое могло произойти в связи с закрытием терминала, удалением советника с графика или по иным причинам.

Теперь перейдем к функции OnTick, которая срабатывает каждый раз при получении нового тика (изменения цены). В этой функции применяется торговая логика. Функция OnTick в представленном коде реализует торговую стратегию, основанную на пересечении скользящих средних.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
   
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   
   if (CopyBuffer(handleMAFast,0,1,3,maFast) < 3){
      Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   if (CopyBuffer(handleMASlow,0,1,3,maSlow) < 3){
      Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   
   //if (IsNewBar()){Print("FAST MA DATA:");ArrayPrint(maFast,6);}
   
   if (PositionsTotal()==0){
      isBuySystemInitiated=false;isSellSystemInitiated=false;
   }
   
   if (PositionsTotal()==0 && IsNewBar()){
      if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]){
         Print("BUY SIGNAL");
         takeProfit = Ask+tpPts*_Point;
         stopLoss = Ask-slPts*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,stopLoss,0);
         isBuySystemInitiated = true;
      }
      else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]){
         Print("SELL SIGNAL");
         takeProfit = Bid-tpPts*_Point;
         stopLoss = Bid+slPts*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,stopLoss,0);
         isSellSystemInitiated = true;
      }
   }
   
   else {
      if (isBuySystemInitiated && Ask >= takeProfit){
         takeProfit = takeProfit+tpPts*_Point;
         stopLoss = Ask-slPts_Min*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,0);
         ModifyTrades(POSITION_TYPE_BUY,stopLoss);
      }
      else if (isSellSystemInitiated && Bid <= takeProfit){
         takeProfit = takeProfit-tpPts*_Point;
         stopLoss = Bid+slPts_Min*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,0);
         ModifyTrades(POSITION_TYPE_SELL,stopLoss);
      }
   }
}

Ниже приводится подробный разбор функции OnTick для облегчения понимания:

Получаем цены Ask и Bid. Функция получает цены Ask и Bid на текущий момент и округляет их до соответствующего количества знаков после запятой. Извлечение и нормализация текущих цен имеют большое значение для стратегии торговли каскадами ордеров с целью принятия обоснованных решений о размещении ордеров в различных ценовых точках. При практической реализации стратегии торговли каскадами ордеров необходимо внимательно следить за текущими рыночными ценами. Это подразумевает получение цен Ask и Bid для символа, которым вы торгуете на платформе MetaTrader. Текущая цена Ask для указанного символа (_Symbol) получается посредством вызова функции. Цена, по которой можно приобрести этот актив, называется ценой предложения (ask). Текущая цена bid для символа извлекается вызовом этой функции. Цена, по которой вы можете приобрести этот актив, называется ценой спроса (bid).

double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

Нормализация обеспечивает соответствие извлеченных цен требованиям торговых символов к точности. От этого также зависит возможность избежать проблем с плавающей запятой. Вызовом этой функции значение округляется до указанного количества знаков после запятой (_Digits). Для символа обычно предварительно задается параметр _Digits, означающий количество цифр после запятой, поддерживаемое этим инструментом.

Дублирование буферов скользящих средних. Эта функция получает самые последние значения и медленных, и быстрых скользящих средних. Если данных недостаточно, функция завершает работу, и печатается сообщение об ошибке. Скользящие средние используются в стратегии торговли каскадами ордеров для отслеживания сделок и определения базовых моментов времени для размещения ордеров. Для обеспечения надежности стратегии очень важно, чтобы перед началом исследования было достаточно данных от скользящих средних.

if (CopyBuffer(handleMAFast,0,1,3,maFast) < 3){
      Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   if (CopyBuffer(handleMASlow,0,1,3,maSlow) < 3){
      Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
      return;
   }

Эта функция передает информацию из буфера индикатора быстрой скользящей средней в массив maFast. Индикаторы быстрых скользящих средних обрабатывают номер буфера, который для основной линии индикатора обычно равен 0, начальную точку, из которой должны копироваться данные, количество дублируемых элементов и массив, в котором будет храниться копия данных. Функция возвращает количество успешно скопированных элементов. При проверке жизнеспособности данных она определяет, было ли в maFast скопировано меньше трех элементов. Если передано менее трех компонентов, это говорит о недостаточности данных от быстрого скользящего среднего для обоснования надежного анализа. Функция завершает исполнение, печатая сообщение и возвращая результат раньше. Медленное скользящее среднее с хендлом MASlow и maSlow следует тем же рассуждениям.

Ниже представлен график скользящих средних, построенный на основе ценовых данных. График включает в себя ценовую серию, быструю скользящую среднюю (10-дневное EMA) и медленную скользящую среднюю (20-дневное EMA).

ПЕРЕСЕЧЕНИЕ СКОЛЬЗЯЩИХ СРЕДНИХ

Перед принятием каких-либо торговых решений стратегия проверяет наличие минимального объема исторических данных от скользящих средних. Это способствует принятию более заслуживающих внимания и обоснованных решений. Стратегия путем проверки достаточности данных предотвращает получение недостоверной информации, что могло бы привести к ложным сигналам и возможным убыточным сделкам. Этот фрагмент служит этапом проверки перед началом торговли. Если условие не будет выполнено, стратегия вернется к предыдущему состоянию и для данного тика не выполнит никаких сделок или анализа.

Скользящие средние используются для определения направления и силы тренда в стратегии торговли каскадами ордеров. Если быстрое скользящее среднее пересечет медленное скользящее среднее, находящееся выше или ниже его, например, можно размещать ордера на разных уровнях.

Проверка открытых позиций. Флаги инициирования системы покупок и продаж сбрасываются, если нет открытых позиций. Чтобы предотвратить перекрывание сделок и эффективно управлять состоянием торговой системы, при использовании стратегии торговли каскадами ордеров очень важно проверять наличие открытых позиций. Один из механизмов, которые мы реализовали в этой функции, — сброс определенных флагов в случае отсутствия свободных мест.

//if (IsNewBar()){Print("FAST MA DATA:");ArrayPrint(maFast,6);}
   
   if (PositionsTotal()==0){
      isBuySystemInitiated=false;isSellSystemInitiated=false;
   }

Эта функция возвращает общее количество открытых позиций для текущего торгового счета. Полезно выяснить, есть ли какие-то активные сделки. Если предположить, что PositionasTotal() == 0, то это условие определяет, есть ли всего 0 открытых позиций, что означает отсутствие открытых сделок в данный момент. Если открытых позиций нет, флаги isBuySytemInitiated и isSellSystemInitiated устанавливаются в значение false. Сбрасывает флаг, указывающий на факт наличия или отсутствия инициации системы покупки (_isBuySystemInitiated = false;). Сбрасывает флаг, указывающий на факт наличия или отсутствия инициации системы продажи (_isSellSystemInitiated = false;).

Такой подход посредством периодической проверки наличия открытых позиций и сброса флагов инициирования гарантирует, что новые сделки начинаются только при отсутствии открытых позиций. Благодаря этому удается избежать перекрывания сделок, которые могут привести к чрезмерной подверженности риску, или противоречивых торговых действий. Мы управляем торговой системой с помощью инициализации флагов isBuySystemInitiated и isSellSystemInitiated. Эти флаги делают так, чтобы до закрытия текущих позиций система не запускала идентичные ордера на покупку или продажув пределах определенного тренда более одного раза. Кроме того, мы в ходе этой проверки получаем помощь в сохранении логической последовательности стратегии. Такой подход позволяет точно реагировать на рыночные условия и тенденции, гарантируя размещение новых ордеров в подходящие моменты, то есть в отсутствие открытых позиций. Мы достигнем более эффективного управления рисками, предотвращая открытие большого количества позиций. Таким образом стратегия может ограничивать доступ к рынку и предотвращать возможное чрезмерное использование заемных средств.

 Обнаружение новых баров. На основе пересечений скользящих средних ищет сигналы на покупку или продажу, если сформировался новый бар (свеча) и отсутствуют открытые позиции. Для предотвращения многократного исполнения торговой стратегии важно обнаружить появление нового бара. Использование данных готового бара в качестве основы для принятия торговых решений в противоположность возможным нестабильным изменениям цен внутри бара повышает точность торговли.

if (PositionsTotal()==0 && IsNewBar()){
      if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]){
         Print("BUY SIGNAL");
         takeProfit = Ask+tpPts*_Point;
         stopLoss = Ask-slPts*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,stopLoss,0);
         isBuySystemInitiated = true;
      }
      else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]){
         Print("SELL SIGNAL");
         takeProfit = Bid-tpPts*_Point;
         stopLoss = Bid+slPts*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,stopLoss,0);
         isSellSystemInitiated = true;
      }
   }

Когда PositionsTotal == 0, это условие гарантирует, что функция блока if будет запускаться только в отсутствие открытых позиций. Благодаря этому предотвращается перекрывание сделок, а новые сделки будут открываться только после закрытия старых. Функция IsNewBar() определяет, сформировался ли с момента последнего запуска новый бар. По сути, если время открытия позиции было записано ранее, этот метод должен возвращать true.

В сигнале на покупку мы определяем, произошло на последнем баре бычье пересечение или пересечение быстрого скользящего среднего (MA) с медленным скользящим средним. Если это так, производится расчет уровней тейк-профита и стоп-лосса и публикуется сообщение BUY SIGNAL. После этого флаг isBuySystemInitiated устанавливается в значение true и с помощью obj_Trade.Buy() отправляется ордер на покупку. Ниже представлен сигнал на покупку при пересечении EMA по стратегии торговли каскадами ордеров:

Сигнал на покупку


В сигнале на продажу мы определяем, представляет ли собой недавний бар медвежье пересечение, означая, что быстрое скользящее среднее (MA) пересекло медленное скользящее среднее сверху вниз. Если это так, производится расчет уровней тейк-профита и стоп-лосса, и выводится сообщение SELL SIGNAL. После этого для отправки ордера на продажу используется obj_Trade. Функция Sell() устанавливает флаг isSellSystemInitiated в значение true. Ниже представлен сигнал на продажу при пересечении EMA по стратегии торговли каскадами ордеров:

Сигнал Продажи

Стратегия гарантирует, что торговая логика выполняется для каждого бара только один раз, определяя момент обнаружения нового бара. Благодаря этому удается избегать проблемы размещения в одном баре нескольких ордеров, что может привести к выходу торговли за пределы запаса средств и более высоким комиссиям за сделки. Использование данных готовых баров для принятия обоснованных торговых решений гарантирует, что выбор основан на достоверной информации. Изменения цен внутри баров могут создавать шум и предоставлять ошибочные данные. Состояние торговой системы эффективно регулируется посредством объединения проверок на отсутствие открытых позиций с обнаружением нового бара. Это гарантирует, что новые сделку будут совершаться только при необходимости, сохраняя логическую последовательность стратегии. 

Исполнение ордеров на покупку или продажу. Ордер на покупку размещается, если быстрое скользящее среднее пересекает медленное скользящее среднее. Он инициирует ордер на продажу, если быстрое MA пересечет медленное MA сверху вниз. Кроме того, он модифицирует флаги инициации и выполняет настройки уровней тейк-профита (TP) и стоп-лосса (SL). Такое «каскадирование» ордеров помогает постепенно сформировать позицию по мере того, как цена движется в пользу первой сделки.

else {
      if (isBuySystemInitiated && Ask >= takeProfit){
         takeProfit = takeProfit+tpPts*_Point;
         stopLoss = Ask-slPts_Min*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,0);
         ModifyTrades(POSITION_TYPE_BUY,stopLoss);
      }

В каскадах ордеров на покупку стратегия определяет, достигнут ли уровень тейк-профита и является ли цена предложения больше или равной ему. Данное обстоятельство означает, что сработал дополнительный ордер на покупку, поскольку цена изменилась в пользу текущей позиции на покупку. Уровень тейк-профита повышается на заранее определенное количество пунктов, устанавливая новый глобальный уровень для последующего приращения в каскаде. Модификация стоп-лосса гарантирует, что риск для нового ордера на покупку контролируется, а уровень стоп-лосса изменяется на новый уровень ниже цены предложения. Дополнительный ордер на покупку размещает второй ордер на покупку с заданным размером лота, вступающий в силу по текущей цене Ask. Модификация текущих сделок управляет риском для всей позиции, при этом стоп-лосс для текущих позиций на покупку изменяется на новый уровень стоп-лосса.

Последовательный ордер на продажу. Стратегия определяет, является ли текущая цена Bid меньшей или равной уровню тейк-профита и начала ли работать система продажи. Такая ситуация означает, что был активирован дополнительный ордер на продажу, поскольку цена изменилась в пользу текущей позиции на продажу. Уровень тейк-профита понижается на заданное количество пунктов, устанавливая для последующего прироста в каскаде новую цель. Обновление стоп-лосса гарантирует, что риск для нового ордера на продажу находится под контролем, уровень стоп-лосса изменяется на новый уровень выше существующей цены Bid. Дополнительный ордер на продажу с указанным размером лота исполняется по текущей цене Bid. Изменение текущих сделок контролирует риск во всех направлениях, стоп-лосс для текущих позиций на продажу переходит на новый уровень.

Корректировка текущих позиций. Если имеются открытые позиции и цена достигает порога тейк-профита, размещается больше ордеров, а суммы стоп-лоссов соответствующим образом обновляются. Это способствует максимальному увеличению прибыли и помогает управлять рисками.

else if (isSellSystemInitiated && Bid <= takeProfit){
         takeProfit = takeProfit-tpPts*_Point;
         stopLoss = Bid+slPts_Min*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,0);
         ModifyTrades(POSITION_TYPE_SELL,stopLoss);
      }
   }
}

Логический флаг с именем isBuySystemInitiated указывает, запущена ли система покупки. Логический флаг с именем isSellSystemInitiated указывает, запущена ли система продажи. Текущая ставка для цены ask, текущая цена bid, размер тейк-профита, необходимое для изменения порога тейк-профита количество пунктов, уровень стоп-лосса, минимальная точка корректировки стоп-лосса, размер лота сделки, возможность размещения ордера на покупку, возможность размещения ордера на продажу и функция, позволяющая изменять уровень стоп-лосса существующей позиции.

Теперь проверим, была ли запущена система UT и достигла на данный момент цена предложения порога тейк-профита или превысила его. Повышение уровня тейк-профита на заданное количество пунктов. Это позволяет стратегии извлекать дополнительную возможную прибыль, устанавливая новую цель по тейк-профиту выше существующей. Установка стоп-лосса на новый ценовой уровень, ниже цены предложения. Фиксация части предыдущих прибылей помогает управлять рисками. Исполнение дополнительных ордеров на покупку по цене предложения привело к исполнению второго ордера на покупку с указанным размером лота по цене предложения. По мере изменения цены в пользу первоначальных сделок позиция постепенно увеличивается. Обновляет уровни стоп-лосса всех текущих позиций на покупку для отражения нового уровня стоп-лосса. Это помогает осуществлять контроль за общим риском, связанным с позицией на покупку.

Далее проверим, запущен ли механизм продажи и выросла цена спроса до порогового уровня тейк-профита или опустилась ниже него. Уменьшение уровня тейк-профита на фиксированное количество пунктов. В результате новая цель по тейк-профиту оказывается ниже существующего уровня. После обновления стоп-лосса его уровень переместится на новый уровень, выше цены спроса. Фиксация части предыдущих прибылей помогает управлять рисками. Исполните дополнительный ордер на продажу с указанным размером лота по текущей цене спроса. По мере изменения цены в пользу первоначальной сделки позиция постепенно увеличивается. Обновляет уровни стоп-лосса всех позиций на продажу для отражения нового уровня стоп-лосса. Это помогает осуществлять контроль за общим риском, связанным с позицией на продажу.

По мере изменения рынка в пользу первой сделки стратегия постепенно увеличивает торговую позицию. В результате трейдер может увеличить свою позицию, не принимая на себя избыточный риск на начальном этапе, и получить прибыль от значимых трендов. Стратегия эффективно управляет рисками, меняя уровни стоп-лосса и для новых ордеров, и для открытых позиций. Если рынок пойдет на спад, это поможет сохранить прибыль и сократить убытки. Каждый раз, когда рынок движется в направлении, предпочтительном для каскадной стратегии, для извлечения максимальной прибыли постепенно устанавливаются новые уровни тейк-профита. Это обеспечивает рост в будущем, гарантируя при этом постепенную фиксацию прибыли.

Теперь рассмотрим две служебные функции в коде нашего советника (EA) на MQL5. IsNewBar и ModifyTrades. Эти процедуры обеспечивают исполнение необходимых вспомогательных операций для поддержки основной торговой логики, представленной в функции OnTick.

Начнем с функции IsNewBar. Эта функция проверяет, сформировался ли новый бар или свеча на графике. Это необходимо для обеспечения гарантии выполнения определенных действий, таких как открытие новых сделок, только один раз на каждом баре.

//+------------------------------------------------------------------+

bool IsNewBar(){
   static int prevBars = 0;
   int currBars = iBars(_Symbol,_Period);
   if (prevBars==currBars) return (false);
   prevBars = currBars;
   return (true);
}

Количество баров из предыдущего тика сохраняется в статической переменной prevBars. Между вызовами функции значение переменной сохраняется благодаря ключевому слову static. Представлено из количества баров**: currBars извлекает текущее количество баров на графике. Сравнение**: функция возвращает false, если не был сгенерирован новый бар, а prevBars и currBars равны. В случае их неравенства появился бы новый. Функция возвращает true после обновления prevBars до currBars. 

Теперь перейдем к функции ModifiyTrades. В зависимости от указанного типа позиции функция ModifyTrades корректирует уровни стоп-лосса (SL) активных позиций.

void ModifyTrades(ENUM_POSITION_TYPE posType, double sl){
   for (int i=0; i<=PositionsTotal(); i++){
      ulong ticket = PositionGetTicket(i);
      if (ticket > 0){
         if (PositionSelectByTicket(ticket)){
            ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            if (type==posType){
               obj_Trade.PositionModify(ticket,sl,0);
            }
         }
      }
   }
}

В этой функции:

  1. Цикл по позициям: использует positionsTotal() для обхода всех открытых позиций.
  2. Получить тикет: возвращает место номера тикета index{i}.
  3. Проверить тикет: проверьте, что номер тикета является действительным числом (больше 0).
  4. Выбрать позицию: использует PositionSelectByTicket} для выбора позиции.
  5.  **Проверить тип позиции**: проверяет, соответствует ли указанное значение posType типу позиции.
  6. ** Изменить позицию**: использует PositionModify для изменения соответствий типов позиции.

Ниже приведен полный код стратегии торговли каскадами ордеров:

//|                                                     CASCADE ORDERING.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade/Trade.mqh>
CTrade obj_Trade;

int handleMAFast;
int handleMASlow;
double maSlow[], maFast[];

double takeProfit = 0;
double stopLoss = 0;
bool isBuySystemInitiated = false;
bool isSellSystemInitiated = false;

input int slPts = 300;
input int tpPts = 300;
input double lot = 0.01;
input int slPts_Min = 100;
input int fastPeriods = 10;
input int slowPeriods = 20;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
    handleMAFast = iMA(_Symbol, _Period, fastPeriods, 0, MODE_EMA, PRICE_CLOSE);
    if (handleMAFast == INVALID_HANDLE) {
        Print("UNABLE TO LOAD FAST MA, REVERTING NOW");
        return (INIT_FAILED);
    }

    handleMASlow = iMA(_Symbol, _Period, slowPeriods, 0, MODE_EMA, PRICE_CLOSE);
    if (handleMASlow == INVALID_HANDLE) {
        Print("UNABLE TO LOAD SLOW MA, REVERTING NOW");
        return (INIT_FAILED);
    }

    ArraySetAsSeries(maFast, true);
    ArraySetAsSeries(maSlow, true);

    return (INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
    // Cleanup code if necessary
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
    double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
    double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);

    if (CopyBuffer(handleMAFast, 0, 1, 3, maFast) < 3) {
        Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
        return;
    }
    if (CopyBuffer(handleMASlow, 0, 1, 3, maSlow) < 3) {
        Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
        return;
    }

    if (PositionsTotal() == 0) {
        isBuySystemInitiated = false;
        isSellSystemInitiated = false;
    }

    if (PositionsTotal() == 0 && IsNewBar()) {
        if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]) {
            Print("BUY SIGNAL");
            takeProfit = Ask + tpPts * _Point;
            stopLoss = Ask - slPts * _Point;
            obj_Trade.Buy(lot, _Symbol, Ask, stopLoss, 0);
            isBuySystemInitiated = true;
        } else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]) {
            Print("SELL SIGNAL");
            takeProfit = Bid - tpPts * _Point;
            stopLoss = Bid + slPts * _Point;
            obj_Trade.Sell(lot, _Symbol, Bid, stopLoss, 0);
            isSellSystemInitiated = true;
        }
    } else {
        if (isBuySystemInitiated && Ask >= takeProfit) {
            takeProfit = takeProfit + tpPts * _Point;
            stopLoss = Ask - slPts_Min * _Point;
            obj_Trade.Buy(lot, _Symbol, Ask, 0);
            ModifyTrades(POSITION_TYPE_BUY, stopLoss);
        } else if (isSellSystemInitiated && Bid <= takeProfit) {
            takeProfit = takeProfit - tpPts * _Point;
            stopLoss = Bid + slPts_Min * _Point;
            obj_Trade.Sell(lot, _Symbol, Bid, 0);
            ModifyTrades(POSITION_TYPE_SELL, stopLoss);
        }
    }
}

    static int prevBars = 0;
    int currBars = iBars(_Symbol, _Period);
    if (prevBars == currBars) return (false);
    prevBars = currBars;
    return (true);
}

//+------------------------------------------------------------------+
//| ModifyTrades Function                                            |
//+------------------------------------------------------------------+

void ModifyTrades(ENUM_POSITION_TYPE posType, double sl) {
    for (int i = 0; i <= PositionsTotal(); i++) {
        ulong ticket = PositionGetTicket(i);
        if (ticket > 0) {
            if (PositionSelectByTicket(ticket)) {
                ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
                if (type == posType) {
                    obj_Trade.PositionModify(ticket, sl, 0);
                }
            }
        }
    }
}


Заключение

В заключение отметим, что этот советник на MQL5 является прекрасным примером удачной реализации торговой стратегии, основанной на пересечениях скользящих средних. В статье представлена эффективная автоматизация торговых решений с использованием библиотеки Trade.mqh для оптимизации управления ордерами и включения динамических уровней фиксации прибылей и ограничения убытков.

Среди основных характеристик этого советника можно выделить следующие:

  • Инициализация и управление. Систематически контролируются сигналы на покупку и продажу на основе пересечений, а скользящие средние эффективно инициализируются.
  • Управление рисками. Использование процедур фиксации прибыли и сокращения убытков для снижения рисков и обеспечения вознаграждений в пределах, настраиваемых пользователем.
  • Модульность и гибкость. Использование входных параметров и глобальных переменных для обеспечения пользовательских настроек и адаптации к различным ситуациям на рынке и торговым предпочтениям. 

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/15250

Последние комментарии | Перейти к обсуждению на форуме трейдеров (2)
ceejay1962
ceejay1962 | 22 авг. 2024 в 02:44

Спасибо за публикацию этой статьи, она оказалась очень полезной. Я интегрировал часть каскадного ордера в свой собственный советник, и это сильно повлияло на прибыльность!

Juan Luis De Frutos Blanco
Juan Luis De Frutos Blanco | 10 окт. 2024 в 07:43

Muchas gracias por la buena explicación y la simplicidad: Un gran trabajo formativo.

А теперь, чтобы окончательно решить проблему, нужно обеспечить среднюю арендную плату. ¿Алгуна идея?

Возможности Мастера MQL5, которые вам нужно знать (Часть 31): Выбор функции потерь Возможности Мастера MQL5, которые вам нужно знать (Часть 31): Выбор функции потерь
Функция потерь (Loss Function) — это ключевая метрика алгоритмов машинного обучения, которая обеспечивает обратную связь для процесса обучения, количественно определяя, насколько хорошо данный набор параметров работает по сравнению с предполагаемым целевым значением. Мы рассмотрим различные форматы этой функции в пользовательском классе Мастера MQL5.
Разработка системы репликации (Часть 66): Нажатие кнопки воспроизведения в сервисе (VII) Разработка системы репликации (Часть 66): Нажатие кнопки воспроизведения в сервисе (VII)
В этой статье мы реализуем первое решение, которое позволит нам определить когда на графике может появиться новый бар. Данное решение применимо в самых разных ситуациях. Понимание его развития поможет вам разобраться в нескольких аспектах. Представленные здесь материалы предназначены только для обучения. Ни в коем случае нельзя рассматривать это приложение как окончательное, цели которого будут иные, кроме изучения представленных концепций.
От начального до среднего уровня: Приоритеты операторов От начального до среднего уровня: Приоритеты операторов
Это, несомненно, самый сложный вопрос, который можно объяснить исключительно теоретически. Поэтому я советую вам попрактиковаться с материалами, которые будут показаны здесь. Хотя на первый взгляд всё может показаться простым, данный вопрос с операторами можно понять только на практике в сочетании с постоянным изучением.
MQL5-советник, интегрированный в Telegram (Часть 2): Отправка сигналов из MQL5 в Telegram MQL5-советник, интегрированный в Telegram (Часть 2): Отправка сигналов из MQL5 в Telegram
В этой статье мы создадим MQL5-советник, интегрированный с Telegram, который отправляет в мессенджер сигналы пересечения скользящих средних. Мы подробно опишем процесс генерации торговых сигналов на основе пересечений скользящих средних, реализуем необходимый код на языке MQL5 и обеспечим бесперебойную работу интеграции. В результате мы получим систему, которая отправляет торговые оповещения в реальном времени непосредственно в групповой чат Telegram.