English 中文 Español Deutsch 日本語 Português
preview
Построение модели для ограничения диапазона сигналов по тренду (Часть 8): Разработка советника (II)

Построение модели для ограничения диапазона сигналов по тренду (Часть 8): Разработка советника (II)

MetaTrader 5Тестер | 20 марта 2025, 12:10
487 0
Clemence Benjamin
Clemence Benjamin

Содержание

  1. Введение
  2. Создание советника:
  3. Тестер
  4. Заключение


    Введение

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

    Статья является следующим шагом в нашей серии и знакомит вас с процессом разработки независимого советника, который не только включает в себя возможности анализа трендов Trend Constraint V1.09, но и интегрирует функции риска и вознаграждения непосредственно в советник. Наша цель — предоставить трейдерам комплексное решение с использованием MQL5 на платформе MetaTrader 5, обеспечивающее улучшенную автоматизацию и бесперебойную работу, чтобы идти в ногу с требованиями рынка.

    Для этого мы вернемся к основам, заложенным в частях 12 и 3, заимствуя логику, необходимую для выполнения советником его торговых задач. Теперь мы объединим все эти части и их логику, чтобы написать советника.

    Ниже приведено краткое описание условий, при которых генерируются сигналы в индикаторе, реализованном на языке MQL5:

    Условие покупки:

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

    Условие продажи:

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


    Создание советника

    Используем MetaEditor для создания нашего MQL5-советника. Самое главное — помнить об основах. Ниже представлена обобщенная структура нашего советника.

    Краткое описание архитектуры большинства советников:

    • Инициализация (OnInit): Настройка необходимых индикаторов и переменных.
    • Основной цикл (OnTick): Обработка входящих тиков для оценки рыночных условий и принятия торговых решений.
    • Управление торговлей (OnTrade): Обработка событий, связанных с торговлей.
    • Тестирование (OnTester и связанные функции): Предоставление структуры для оптимизации и оценки производительности советника в тестере стратегий.
    • Взаимодействие с пользователем (OnChartEvent): Необязательный этап, позволяющий взаимодействовать с советником через события графика.

    Я считаю, что черновой вариант на блок-схеме ниже поможет прояснить желаемый результат и облегчит его понимание.

    Советник Trend Constraint

    Примерная структурная схема частей советника и их взаимосвязь

    Такая структура гарантирует, что наш советник хорошо организован и способен эффективно решать различные задачи, необходимые для реализации нашей торговой стратегии. Я разделю процесс разработки на подразделы, но продвинутые разработчики могут пропустить этапы (i) и (ii) и перейти сразу к подразделам (iii).

    (i) Запуск советника (шаблона) по умолчанию в MetaEditor.

    (ii) Настройка шаблона.

    (iii)  Создание логики советника Trend Constraint в подготовленном шаблоне.


    (i) Запуск шаблона советника

    В MetaEditor нажмите Ctrl + N, чтобы запустить новый файл, и выберите "Советник (шаблон)":

    Запуск советника (шаблон)

    Запуск нового советника (шаблон)

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


    (ii) Настройка шаблона

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

    Минимальный шаблон представляет собой основу, на которой мы позже будем строить логику нашего советника.

    Вот сгенерированный шаблон из MetaEditor:

    //+------------------------------------------------------------------+
    //|                                      Trend Constraint Expert.mq5 |
    //|                                Copyright 2024, Clemence Benjamin |
    //|             https://www.mql5.com/en/users/billionaire2024/seller |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2024, Clemence Benjamin"
    #property link      "https://www.mql5.com/en/users/billionaire2024/seller"
    #property version   "1.00"
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //---
       
    //---
       return(INIT_SUCCEEDED);
      }
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //---
       
      }
    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick()
      {
    //---
       
      }
    //+------------------------------------------------------------------+
    //| Trade function                                                   |
    //+------------------------------------------------------------------+
    void OnTrade()
      {
    //---
       
      }
    //+------------------------------------------------------------------+
    //| Tester function                                                  |
    //+------------------------------------------------------------------+
    double OnTester()
      {
    //---
       double ret=0.0;
    //---
    
    //---
       return(ret);
      }
    //+------------------------------------------------------------------+
    //| TesterInit function                                              |
    //+------------------------------------------------------------------+
    void OnTesterInit()
      {
    //---
       
      }
    //+------------------------------------------------------------------+
    //| TesterPass function                                              |
    //+------------------------------------------------------------------+
    void OnTesterPass()
      {
    //---
       
      }
    //+------------------------------------------------------------------+
    //| TesterDeinit function                                            |
    //+------------------------------------------------------------------+
    void OnTesterDeinit()
      {
    //---
       
      }
    //+------------------------------------------------------------------+
    //| ChartEvent function                                              |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id,
                      const long &lparam,
                      const double &dparam,
                      const string &sparam)
      {
    //---
       
      }
    //+------------------------------------------------------------------+
    

     Давайте рассмотрим основные функции, необходимые нашим советникам, основываясь на шаблоне:

    • OnInit(): Функция запускается один раз при инициализации советника, настраивая индикаторы, переменные или ресурсы, необходимые для работы. Правильная инициализация гарантирует готовность всех необходимых ресурсов до того, как советник начнет обработку рыночных данных. В случае с советником Trend Constraint здесь обычно инициализируются индикатор RSI и другие важные переменные.

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

    • OnTick(): Эта основная функция запускается каждый раз, когда поступает новый тик (обновление цены) для символа, к которому прикреплен советник. В советнике Trend Constraint она будет содержать логику проверки рыночных условий, таких как тренд D1 и уровни RSI, а также принятия торговых решений, таких как открытие или закрытие позиций.

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

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

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

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

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

    Дополнительные функции, не входящие в шаблон советника, но необходимые для нашего проекта:

    • Функции индикаторов (например, iRSI): используются для расчета индикаторов, таких как RSI, которые являются неотъемлемой частью вашей торговой стратегии.
    • Торговые функции (класс CTrade class): используются для управления ордерами и позициями, например, для размещения ордеров на покупку/продажу, установки стоп-лоссов и изменения позиций.
    Таким образом, мы обрисовали логику, которую должен использовать наш советник в рамках конкретных подходящих функций. Это базовая схема функций, которые я намерен включить в наш советник. Я объяснил, почему каждая из них важна в этой разработке, с помощью комментариев в коде.
    //+------------------------------------------------------------------+
    //|                               Trend Constraint Expert Advisor.mq5|
    //|                                 Copyright 2024, Clemence Benjamin|
    //|              https://www.mql5.com/en/users/billionaire2024/seller|
    //+------------------------------------------------------------------+
    
    
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
       // Initialization code here
       rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);
       if (rsi_handle == INVALID_HANDLE)
         {
          Print("Failed to create RSI indicator handle");
          return(INIT_FAILED);
         }
    
       // Any other initialization tasks
       
       return(INIT_SUCCEEDED);
      }
    
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
       // Cleanup code here
       IndicatorRelease(rsi_handle);  // Release RSI indicator handle
       // Any other deinitialization tasks
      }
    
    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick()
      {
       // Main trading logic goes here
       
       // Determine market conditions (e.g., daily trend, RSI levels)
       
       // Check for trade conditions and execute orders if necessary
    
       // Implement trailing stop logic if necessary
      }
    
    //+------------------------------------------------------------------+
    //| Trade event function                                             |
    //+------------------------------------------------------------------+
    void OnTrade()
      {
       // Handle trade events (e.g., order placement, modification, closure)
      }
    
    //+------------------------------------------------------------------+
    //| Tester function                                                  |
    //+------------------------------------------------------------------+
    double OnTester()
      {
       double ret = 0.0;
       // Custom optimization criteria (if any) go here
       return(ret);
      }
    
    //+------------------------------------------------------------------+
    //| TesterInit function                                              |
    //+------------------------------------------------------------------+
    void OnTesterInit()
      {
       // Initialization for testing (if needed)
      }
    
    //+------------------------------------------------------------------+
    //| TesterPass function                                              |
    //+------------------------------------------------------------------+
    void OnTesterPass()
      {
       // Actions after each optimization pass (if needed)
      }
    
    //+------------------------------------------------------------------+
    //| TesterDeinit function                                            |
    //+------------------------------------------------------------------+
    void OnTesterDeinit()
      {
       // Cleanup after testing (if needed)
      }
    
    //+------------------------------------------------------------------+
    //| Chart event function                                             |
    //+------------------------------------------------------------------+
    void OnChartEvent(const int id,
                      const long &lparam,
                      const double &dparam,
                      const string &sparam)
      {
       // Handle chart events (e.g., mouse clicks, key presses) here
      }
    
    //+------------------------------------------------------------------+
    


    (iii)  Создание логики советника Trend Constraint. 

    Теперь мы можем перейти к написанию логики для каждой функции, составляющей нашего советника. Давайте построим нашу программу шаг за шагом:

    Включение торговой библиотеки:

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

    #include <Trade\Trade.mqh>  // Include the trade library
    

    Определение входных параметров:

    Далее мы определяем входные параметры, которые пользователи могут настраивать в соответствии со своими торговыми предпочтениями. К этим параметрам относятся период RSI, уровни перекупленности и перепроданности, размер лота, стоп-лосс, тейк-профит и трейлинг-стоп. Записывая эти входные строки, мы гарантируем, что советник можно будет настроить под различные рыночные условия. Программа будет использовать эти значения для принятия решений о том, когда входить в сделки и выходить из них.

    // Input parameters
    input int    RSI_Period = 14;            // RSI period
    input double RSI_Overbought = 70.0;      // RSI overbought level
    input double RSI_Oversold = 30.0;        // RSI oversold level
    input double Lots = 0.1;                 // Lot size
    input double StopLoss = 100;             // Stop Loss in points
    input double TakeProfit = 200;           // Take Profit in points
    input double TrailingStop = 50;          // Trailing Stop in points
    

    Объявление глобальных переменных:

    Затем мы объявляем глобальные переменные, такие как RSI_value и RS1_handle, которые будут хранить значение и хэндл RSI соответственно, а также экземпляр класса CTrade. Объявляя эти переменные, мы гарантируем, что советник сможет сохранять состояние в различных функциях, позволяя программе получать доступ к этим значениям и изменять их по мере необходимости во время ее работы.

    // Global variables
    double rsi_value;
    int rsi_handle;
    CTrade trade;  // Declare an instance of the CTrade class
    

    Инициализация советника:

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

    int OnInit()
      {
       // Create an RSI indicator handle
       rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);
       if (rsi_handle == INVALID_HANDLE)
         {
          Print("Failed to create RSI indicator handle");
          return(INIT_FAILED);
         }
    
       return(INIT_SUCCEEDED);
      }
    

    Деинициализация советника:

    Для эффективного управления ресурсами мы реализуем функцию OnDeinit, которая освобождает хэндл индикатора RSI при удалении советника с графика. Код очистки предотвращает утечки памяти и обеспечивает правильное освобождение ресурсов. Программа автоматически выполнит очистку при деинициализации, поддерживая оптимальную производительность.

    void OnDeinit(const int reason)
      {
       // Release the RSI indicator handle
       IndicatorRelease(rsi_handle);
      }
    

    Реализация базовой торговой логики:

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

    void OnTick()
      {
       // Determine current daily trend (bullish or bearish)
       double daily_open = iOpen(_Symbol, PERIOD_D1, 0);
       double daily_close = iClose(_Symbol, PERIOD_D1, 0);
    
       bool is_bullish = daily_close > daily_open;
       bool is_bearish = daily_close < daily_open;
    

    Получение значений RSI:

    Затем мы извлекаем значение RSI с помощью CopyBuffer и хэндла RSI, созданного ранее. Таким образом мы гарантируем, что программа сможет оценить, находится ли рынок в состоянии перекупленности или перепроданности. Программа будет использовать это значение RSI в процессе принятия решений, определяя, соответствует ли оно условиям для входа в сделку.

       // Get the RSI value for the current bar
       double rsi_values[];
       if (CopyBuffer(rsi_handle, 0, 0, 1, rsi_values) <= 0)
         {
          Print("Failed to get RSI value");
          return;
         }
       rsi_value = rsi_values[0];
    

    Закрытие позиций при изменении тренда:

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

       // Close open positions if the trend changes
       for (int i = PositionsTotal() - 1; i >= 0; i--)
         {
          if (PositionSelect(PositionGetSymbol(i)))  // Corrected usage
            {
             int position_type = PositionGetInteger(POSITION_TYPE);
             ulong ticket = PositionGetInteger(POSITION_TICKET);  // Get the position ticket
    
             if ((position_type == POSITION_TYPE_BUY && is_bearish) ||
                 (position_type == POSITION_TYPE_SELL && is_bullish))
               {
                trade.PositionClose(ticket);  // Use the ulong variable directly
               }
            }
         }
    

    Проверка условий покупки и продажи:

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

       // Check for buy condition (bullish trend + RSI oversold)
       if (is_bullish && rsi_value < RSI_Oversold)
         {
          // No open positions? Place a buy order
          if (PositionsTotal() == 0)
            {
             double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
             double sl = price - StopLoss * _Point;
             double tp = price + TakeProfit * _Point;
    
             // Open a buy order
             trade.Buy(Lots, _Symbol, price, sl, tp, "TrendConstraintExpert Buy");
            }
         }
    
       // Check for sell condition (bearish trend + RSI overbought)
       if (is_bearish && rsi_value > RSI_Overbought)
         {
          // No open positions? Place a sell order
          if (PositionsTotal() == 0)
            {
             double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
             double sl = price + StopLoss * _Point;
             double tp = price - TakeProfit * _Point;
    
             // Open a sell order
             trade.Sell(Lots, _Symbol, price, sl, tp, "TrendConstraintExpert Sell");
            }
         }
    

    Реализация механизма трейлинг-стопа:

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

       // Apply trailing stop
       for (int i = PositionsTotal() - 1; i >= 0; i--)
         {
          if (PositionSelect(PositionGetSymbol(i)))  // Corrected usage
            {
             double price = PositionGetDouble(POSITION_PRICE_OPEN);
             double stopLoss = PositionGetDouble(POSITION_SL);
             double current_price;
    
             if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
               {
                current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
                if (current_price - price > TrailingStop * _Point)
                  {
                   if (stopLoss < current_price - TrailingStop * _Point)
                     {
                      trade.PositionModify(PositionGetInteger(POSITION_TICKET), current_price - TrailingStop * _Point, PositionGetDouble(POSITION_TP));
                     }
                  }
               }
             else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
               {
                current_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
                if (price - current_price > TrailingStop * _Point)
                  {
                   if (stopLoss > current_price + TrailingStop * _Point || stopLoss == 0)
                     {
                      trade.PositionModify(PositionGetInteger(POSITION_TICKET), current_price + TrailingStop * _Point, PositionGetDouble(POSITION_TP));
                     }
                  }
               }
            }
         }
      }

    Наша окончательная программа с заголовком и другими свойствами:

    //+------------------------------------------------------------------+
    //|                                      Trend Constraint Expert.mq5 |
    //|                                Copyright 2024, Clemence Benjamin |
    //|             https://www.mql5.com/en/users/billionaire2024/seller |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2024, Clemence Benjamin"
    #property link      "https://www.mql5.com/en/users/billionaire2024/seller"
    #property version   "1.00"
    #property description "A System that seeks to Long D1 Bullish sentiment and short D1 Bearish sentiment"
    #property strict
    
    
    #include <Trade\Trade.mqh>  // Include the trade library
    
    // Input parameters
    input int    RSI_Period = 14;            // RSI period
    input double RSI_Overbought = 70.0;      // RSI overbought level
    input double RSI_Oversold = 30.0;        // RSI oversold level
    input double Lots = 0.1;                 // Lot size
    input double StopLoss = 100;             // Stop Loss in points
    input double TakeProfit = 200;           // Take Profit in points
    input double TrailingStop = 50;          // Trailing Stop in points
    
    // Global variables
    double rsi_value;
    int rsi_handle;
    CTrade trade;  // Declare an instance of the CTrade class
    
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
       // Create an RSI indicator handle
       rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);
       if (rsi_handle == INVALID_HANDLE)
         {
          Print("Failed to create RSI indicator handle");
          return(INIT_FAILED);
         }
    
       return(INIT_SUCCEEDED);
      }
    
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
       // Release the RSI indicator handle
       IndicatorRelease(rsi_handle);
      }
    
    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick()
      {
       // Determine current daily trend (bullish or bearish)
       double daily_open = iOpen(_Symbol, PERIOD_D1, 0);
       double daily_close = iClose(_Symbol, PERIOD_D1, 0);
    
       bool is_bullish = daily_close > daily_open;
       bool is_bearish = daily_close < daily_open;
    
       // Get the RSI value for the current bar
       double rsi_values[];
       if (CopyBuffer(rsi_handle, 0, 0, 1, rsi_values) <= 0)
         {
          Print("Failed to get RSI value");
          return;
         }
       rsi_value = rsi_values[0];
    
       // Close open positions if the trend changes
       for (int i = PositionsTotal() - 1; i >= 0; i--)
         {
          if (PositionSelect(PositionGetSymbol(i)))  // Corrected usage
            {
             int position_type = PositionGetInteger(POSITION_TYPE);
             ulong ticket = PositionGetInteger(POSITION_TICKET);  // Get the position ticket
    
             if ((position_type == POSITION_TYPE_BUY && is_bearish) ||
                 (position_type == POSITION_TYPE_SELL && is_bullish))
               {
                trade.PositionClose(ticket);  // Use the ulong variable directly
               }
            }
         }
    
       // Check for buy condition (bullish trend + RSI oversold)
       if (is_bullish && rsi_value < RSI_Oversold)
         {
          // No open positions? Place a buy order
          if (PositionsTotal() == 0)
            {
             double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
             double sl = price - StopLoss * _Point;
             double tp = price + TakeProfit * _Point;
    
             // Open a buy order
             trade.Buy(Lots, _Symbol, price, sl, tp, "TrendConstraintExpert Buy");
            }
         }
    
       // Check for sell condition (bearish trend + RSI overbought)
       if (is_bearish && rsi_value > RSI_Overbought)
         {
          // No open positions? Place a sell order
          if (PositionsTotal() == 0)
            {
             double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
             double sl = price + StopLoss * _Point;
             double tp = price - TakeProfit * _Point;
    
             // Open a sell order
             trade.Sell(Lots, _Symbol, price, sl, tp, "TrendConstraintExpert Sell");
            }
         }
    
       // Apply trailing stop
       for (int i = PositionsTotal() - 1; i >= 0; i--)
         {
          if (PositionSelect(PositionGetSymbol(i)))  // Corrected usage
            {
             double price = PositionGetDouble(POSITION_PRICE_OPEN);
             double stopLoss = PositionGetDouble(POSITION_SL);
             double current_price;
    
             if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
               {
                current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
                if (current_price - price > TrailingStop * _Point)
                  {
                   if (stopLoss < current_price - TrailingStop * _Point)
                     {
                      trade.PositionModify(PositionGetInteger(POSITION_TICKET), current_price - TrailingStop * _Point, PositionGetDouble(POSITION_TP));
                     }
                  }
               }
             else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
               {
                current_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
                if (price - current_price > TrailingStop * _Point)
                  {
                   if (stopLoss > current_price + TrailingStop * _Point || stopLoss == 0)
                     {
                      trade.PositionModify(PositionGetInteger(POSITION_TICKET), current_price + TrailingStop * _Point, PositionGetDouble(POSITION_TP));
                     }
                  }
               }
            }
         }
      }
    //+------------------------------------------------------------------+
    //HAPPY DEVELOPING!

    Достигнув этого этапа, мы можем приступить к тестированию нашей программы.


    Тестер

    Для проверки советника Trend Constraint в тестере стратегий MetaTrader 5 мы начнем с настройки тестирования на истории для оценки производительности советника. Это позволит нам моделировать торговую стратегию в различных рыночных условиях, помогая анализировать прибыльность, управление рисками и общую эффективность. Нам необходимо выбрать желаемый таймфрейм (в данном случае M1), входные параметры и торговую среду, а также посмотреть, насколько хорошо советник придерживается логики следования за трендом и условий RSI. Этот тест имеет решающее значение для точной настройки советника перед рассмотрением возможности торговли в реальном времени. Я являюсь поклонником индекса Boom 500 и мне понравилось тестировать на нем советники.

    Тестер стратегий

    Настройки тестера стратегий: Советник Trend Constraint

    Производительность в тестере

    Производительность советника в тестере

    Результат в тестере

    Результат в тестере 01/2023-12/2023



    Заключение

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

    Мы успешно разработали полноценный советник на основе нашей первоначальной идеи и можем наблюдать за исполнением ордеров в тестере. Однако еще многое предстоит сделать. Советник Trend Constraint нуждается в дальнейшей доработке, особенно в части условий входа, чтобы повысить прибыльность в соответствии с преобладающими дневными трендами. На этот раз мы не включили магическое число, и при тестировании на реальном демо-счете я понял, что советник влияет на другие уже размещенные ордера.

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

    Далее мы введем магическое число и улучшим методы входа. Удачной торговли!

    Файл Описание
    Trend Constraint Expert.mq5 Исходный код.

    В начало


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

    Прикрепленные файлы |
    Разработка системы репликации (Часть 71): Настройка времени (IV) Разработка системы репликации (Часть 71): Настройка времени (IV)
    В этой статье мы рассмотрим, как реализовать то, что было показано в предыдущей статье, в сервисе репликации/моделирования. Но, как и во многих других случаях, в жизни обязательно возникают проблемы. И данный случай не стал исключением. Дальше вы узнаете тему следующей статьи из этой серии. Представленные здесь материалы предназначены только для обучения. Ни в коем случае нельзя рассматривать это приложение как окончательное, цели которого будут иные, кроме изучения представленных концепций.
    Оптимизация нейробоидами — Neuroboids Optimization Algorithm (NOA) Оптимизация нейробоидами — Neuroboids Optimization Algorithm (NOA)
    Новая авторская биоинспирированная метаэвристика оптимизации — NOA (Neuroboids Optimization Algorithm), объединяющая принципы коллективного интеллекта и нейронных сетей. В отличие от классических методов, алгоритм использует популяцию самообучающихся "нейробоидов", каждый с собственной нейросетью, адаптирующей стратегию поиска в реальном времени. Статья раскрывает архитектуру алгоритма, механизмы самообучения агентов и перспективы применения этого гибридного подхода в сложных задачах оптимизации.
    Визуализация стратегий в MQL5: раскладываем результаты оптимизации по графикам критериев Визуализация стратегий в MQL5: раскладываем результаты оптимизации по графикам критериев
    В этой статье мы напишем пример визуализации процесса оптимизации и сделаем отображение трёх лучших проходов для четырёх критериев оптимизации. А также обеспечим возможность выбора одного из трёх лучших проходов для вывода его данных в таблицы и на график.
    Разработка системы репликации (Часть 70): Настройка времени (III) Разработка системы репликации (Часть 70): Настройка времени (III)
    В данной статье мы рассмотрим, как правильно и эффективно использовать функцию CustomBookAdd. Несмотря на кажущуюся простоту, она имеет множество нюансов. Например, позволяет сообщить указателю мыши, находится ли пользовательский символ на аукционе, торгуется ли он или рынок закрыт. Представленные здесь материалы предназначены только для обучения. Ни в коем случае нельзя рассматривать это приложение как окончательное, цели которого будут иные, кроме изучения представленных концепций.