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

Построение модели для ограничения диапазона сигналов по тренду (Часть 4): Настройка стиля отображения для каждой трендовой волны

MetaTrader 5Торговые системы |
784 1
Clemence Benjamin
Clemence Benjamin

Содержание


Введение

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

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

Вместо того чтобы просто нарисовать стрелку для оповещения, мы хотим добиться более продвинутой визуализации на графике. Как мы помним, наша цель в этой серии — усовершенствовать модель ограничения тренда таким образом, чтобы она соответствовала настроению свечи D1, а также отображать комплексные визуальные сигналы на графике. Стили рисования MQL5 можно настраивать по цвету, толщине и стилю (например, пунктирные или сплошные линии), что помогает трейдерам персонализировать свои графики в соответствии со своими предпочтениями и улучшить читаемость. Различные стили рисования позволяют трейдерам представлять данные более четко и точно. Например, использование линий, гистограмм или свечей может облегчить интерпретацию движения цен и рыночных трендов.

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


    Краткое повторение

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

    Для разработки стратегии мы добавили к торговому инструменту скользящие средние (MA) 200 и 100 на графике MQL5. Анализируя поведение этих встроенных индикаторов, мы выявили значимое периодическое событие пересечения. Впоследствии был создан персонализированный индикатор пересечения с системой оповещения, который оповещает нас о таких событиях, указывая на возможный разворот тренда. Корректировка значений MA в соответствии с более крупным тайфмреймом может помочь отфильтровать сигналы во время колебаний рынка. В третьей части я еще больше усовершенствовал подход, введя настраиваемый ввод таймфрейма для изучения различных значений таймфрейма и определения оптимальных настроек для разворотов тренда.

    input int Slow_MA_period = 200;
    input int Fast_MA_period = 100;

    Приложение позволяет мгновенно настраивать входные параметры в визуальном представлении. Чтобы изменить настройки, нажмите Ctrl + I при просмотре графика MetaTrader 5 или просто щелкните правой кнопкой мыши и найдите Trend Constraint V1.03 в меню индикатора.

    Оптимизация MA для разворотов тренда

     Рис. 1. Оптимизация периода MA для наилучших настроек разворота тренда

    Исходник приложен к статье. Ниже представлен самый последний код для Trend Constraint V1.03:

    /// Program after adding Moving Average optimization feature for reversals
    ///Indicator Name: Trend Constraint
    #property copyright "Clemence Benjamin"
    #property link      "https://mql5.com"
    #property version   "1.03"
    #property description "A model that seek to produce sell signal when D1 candle is Bearish only and  buy signal when it is Bullish"
    
    
    //--- indicator settings
    #property indicator_chart_window
    #property indicator_buffers 4
    #property indicator_plots 4
    
    #property indicator_type1 DRAW_ARROW
    #property indicator_width1 5
    #property indicator_color1 0xFF3C00
    #property indicator_label1 "Buy"
    
    #property indicator_type2 DRAW_ARROW
    #property indicator_width2 5
    #property indicator_color2 0x0000FF
    #property indicator_label2 "Sell"
    
    #property indicator_type3 DRAW_ARROW
    #property indicator_width3 1
    #property indicator_color3 0x04CC04
    #property indicator_label3 "Buy Reversal"
    
    #property indicator_type4 DRAW_ARROW
    #property indicator_width4 1
    #property indicator_color4 0xE81AC6
    #property indicator_label4 "Sell Reversal"
    
    #define PLOT_MAXIMUM_BARS_BACK 5000
    #define OMIT_OLDEST_BARS 50
    
    //--- indicator buffers
    double Buffer1[];
    double Buffer2[];
    double Buffer3[];
    double Buffer4[];
    
    input double Oversold = 30;
    input double Overbought = 70;
    input int Slow_MA_period = 200;
    input int Fast_MA_period = 100;
    datetime time_alert; //used when sending alert
    input bool Audible_Alerts = true;
    input bool Push_Notifications = true;
    double myPoint; //initialized in OnInit
    int RSI_handle;
    double RSI[];
    double Open[];
    double Close[];
    int MA_handle;
    double MA[];
    int MA_handle2;
    double MA2[];
    int MA_handle3;
    double MA3[];
    int MA_handle4;
    double MA4[];
    double Low[];
    double High[];
    
    void myAlert(string type, string message)
      {
       if(type == "print")
          Print(message);
       else if(type == "error")
         {
          Print(type+" | Trend Constraint V1.03 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
         }
       else if(type == "order")
         {
         }
       else if(type == "modify")
         {
         }
       else if(type == "indicator")
         {
          if(Audible_Alerts) Alert(type+" | Trend Constraint V1.03 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
          if(Push_Notifications) SendNotification(type+" | Trend Constraint V1.03 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
         }
      }
    
    //+------------------------------------------------------------------+
    //| Custom indicator initialization function                         |
    //+------------------------------------------------------------------+
    int OnInit()
      {   
       SetIndexBuffer(0, Buffer1);
       PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
       PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
       PlotIndexSetInteger(0, PLOT_ARROW, 241);
       SetIndexBuffer(1, Buffer2);
       PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
       PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
       PlotIndexSetInteger(1, PLOT_ARROW, 242);
       SetIndexBuffer(2, Buffer3);
       PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
       PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
       PlotIndexSetInteger(2, PLOT_ARROW, 236);
       SetIndexBuffer(3, Buffer4);
       PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE);
       PlotIndexSetInteger(3, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
       PlotIndexSetInteger(3, PLOT_ARROW, 238);
       //initialize myPoint
       myPoint = Point();
       if(Digits() == 5 || Digits() == 3)
         {
          myPoint *= 10;
         }
       RSI_handle = iRSI(NULL, PERIOD_CURRENT, 14, PRICE_CLOSE);
       if(RSI_handle < 0)
         {
          Print("The creation of iRSI has failed: RSI_handle=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_SMMA, PRICE_CLOSE);
       if(MA_handle < 0)
         {
          Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       MA_handle2 = iMA(NULL, PERIOD_CURRENT, 400, 0, MODE_SMA, PRICE_CLOSE);
       if(MA_handle2 < 0)
         {
          Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       MA_handle3 = iMA(NULL, PERIOD_CURRENT, Fast_MA_period, 0, MODE_EMA, PRICE_CLOSE);
       if(MA_handle3 < 0)
         {
          Print("The creation of iMA has failed: MA_handle3=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       MA_handle4 = iMA(NULL, PERIOD_CURRENT, Slow_MA_period, 0, MODE_SMA, PRICE_CLOSE);
       if(MA_handle4 < 0)
         {
          Print("The creation of iMA has failed: MA_handle4=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       return(INIT_SUCCEEDED);
      }
    
    //+------------------------------------------------------------------+
    //| Custom indicator iteration function                              |
    //+------------------------------------------------------------------+
    int OnCalculate(const int rates_total,
                    const int prev_calculated,
                    const datetime& time[],
                    const double& open[],
                    const double& high[],
                    const double& low[],
                    const double& close[],
                    const long& tick_volume[],
                    const long& volume[],
                    const int& spread[])
      {
       int limit = rates_total - prev_calculated;
       //--- counting from 0 to rates_total
       ArraySetAsSeries(Buffer1, true);
       ArraySetAsSeries(Buffer2, true);
       ArraySetAsSeries(Buffer3, true);
       ArraySetAsSeries(Buffer4, true);
       //--- initial zero
       if(prev_calculated < 1)
         {
          ArrayInitialize(Buffer1, EMPTY_VALUE);
          ArrayInitialize(Buffer2, EMPTY_VALUE);
          ArrayInitialize(Buffer3, EMPTY_VALUE);
          ArrayInitialize(Buffer4, EMPTY_VALUE);
         }
       else
          limit++;
       datetime Time[];
       
       datetime TimeShift[];
       if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total);
       ArraySetAsSeries(TimeShift, true);
       int barshift_M1[];
       ArrayResize(barshift_M1, rates_total);
       int barshift_D1[];
       ArrayResize(barshift_D1, rates_total);
       for(int i = 0; i < rates_total; i++)
         {
          barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]);
          barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]);
       }
       if(BarsCalculated(RSI_handle) <= 0) 
          return(0);
       if(CopyBuffer(RSI_handle, 0, 0, rates_total, RSI) <= 0) return(rates_total);
       ArraySetAsSeries(RSI, true);
       if(CopyOpen(Symbol(), PERIOD_M1, 0, rates_total, Open) <= 0) return(rates_total);
       ArraySetAsSeries(Open, true);
       if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close) <= 0) return(rates_total);
       ArraySetAsSeries(Close, true);
       if(BarsCalculated(MA_handle) <= 0) 
          return(0);
       if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total);
       ArraySetAsSeries(MA, true);
       if(BarsCalculated(MA_handle2) <= 0) 
          return(0);
       if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total);
       ArraySetAsSeries(MA2, true);
       if(BarsCalculated(MA_handle3) <= 0) 
          return(0);
       if(CopyBuffer(MA_handle3, 0, 0, rates_total, MA3) <= 0) return(rates_total);
       ArraySetAsSeries(MA3, true);
       if(BarsCalculated(MA_handle4) <= 0) 
          return(0);
       if(CopyBuffer(MA_handle4, 0, 0, rates_total, MA4) <= 0) return(rates_total);
       ArraySetAsSeries(MA4, true);
       if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total);
       ArraySetAsSeries(Low, true);
       if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total);
       ArraySetAsSeries(High, true);
       if(CopyTime(Symbol(), Period(), 0, rates_total, Time) <= 0) return(rates_total);
       ArraySetAsSeries(Time, true);
       //--- main loop
       for(int i = limit-1; i >= 0; i--)
         {
          if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation   
          
          if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue;
          if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue;
          
          //Indicator Buffer 1
          if(RSI[i] < Oversold
          && RSI[i+1] > Oversold //Relative Strength Index crosses below fixed value
          && Open[barshift_M1[i]] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close
          && MA[i] > MA2[i] //Moving Average > Moving Average
          && MA3[i] > MA4[i] //Moving Average > Moving Average
          )
            {
             Buffer1[i] = Low[1+i]; //Set indicator value at Candlestick Low
             if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy"); //Alert on next bar open
             time_alert = Time[1];
            }
          else
            {
             Buffer1[i] = EMPTY_VALUE;
            }
          //Indicator Buffer 2
          if(RSI[i] > Overbought
          && RSI[i+1] < Overbought //Relative Strength Index crosses above fixed value
          && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close
          && MA[i] < MA2[i] //Moving Average < Moving Average
          && MA3[i] < MA4[i] //Moving Average < Moving Average
          )
            {
             Buffer2[i] = High[1+i]; //Set indicator value at Candlestick High
             if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell"); //Alert on next bar open
             time_alert = Time[1];
            }
          else
            {
             Buffer2[i] = EMPTY_VALUE;
            }
          //Indicator Buffer 3
          if(MA3[i] > MA4[i]
          && MA3[i+1] < MA4[i+1] //Moving Average crosses above Moving Average
          )
            {
             Buffer3[i] = Low[i]; //Set indicator value at Candlestick Low
             if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy Reversal"); //Alert on next bar open
             time_alert = Time[1];
            }
          else
            {
             Buffer3[i] = EMPTY_VALUE;
            }
          //Indicator Buffer 4
          if(MA3[i] < MA4[i]
          && MA3[i+1] > MA4[i+1] //Moving Average crosses below Moving Average
          )
            {
             Buffer4[i] = High[i]; //Set indicator value at Candlestick High
             if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell Reversal"); //Alert on next bar open
             time_alert = Time[1];
            }
          else
            {
             Buffer4[i] = EMPTY_VALUE;
            }
         }
       return(rates_total);
      }
    //Thank you, friend. You have reached this stage and you can do more+


    Стили отображения MQL5

    MQL5 предоставляет широкий спектр стилей рисования индикаторов. При разработке индикаторов основной целью обычно является проектирование систем, которые могут оповещать пользователей как звуковыми, так и визуальными сигналами. Это помогает оптимизировать торговые операции, поскольку трейдерам больше не нужно постоянно следить за графиками. Давайте кратко рассмотрим некоторые стили рисования, которые можно использовать в MQL5, такие как DRAW_ARROW, DRAW_LINE, DRAW_HISTOGRAM, DRAW_FILLING и DRAW_NONE. Подробные описания стилей рисования можно найти в Справочнике MQL5.

    Стиль рисования Описание
    DRAW_ARROW Рисует стрелки в указанных точках. Часто используется для обозначения сигналов покупки/продажи или других важных событий.
    DRAW_LINE Используется для рисования линии, соединяющей точки данных. Идеально подходит для скользящих средних, линий тренда и других линейных индикаторов.
    DRAW_HISTOGRAM Отображает данные в виде столбцов или гистограмм. Полезно для объема, гистограмм MACD и других столбчатых индикаторов.
    DRAW_FILLING Используется для заполнения области между двумя линиями на графике, обеспечивая визуальный интуитивно понятный способ представления диапазонов данных, спреда или различий между двумя индикаторами.
    DRAW_NONE Используется для индикатора, который визуально не отображается на графике.


    Реализация стиля DRAW_LINE style в системе

    Давайте воспользуемся функцией DRAW_LINE, чтобы наглядно отобразить наши тренды на графике MetaTrader 5. Нам уже удавалось эффективно настроить наш индикатор для распознавания разворотов тренда посредством пересечений со скользящими средними с более крупных периодов. Теперь наша цель — улучшить визуальное представление информации, не перегружая график слишком большим количеством элементов. Это новое дополнение позволит нам нарисовать одну линию, которая будет демонстрировать тренды и автоматически менять свой цвет с каждым новым направлением. У нас уже есть четыре буфера. Расширим наши возможности, добавив буферы 5 и 6 для версии 1.04.

    • Буфер 5: Для отображения синей линии, когда MA 100 находится выше MA 200
    ///properties
    #property indicator_type5 DRAW_LINE
    #property indicator_style5 STYLE_SOLID
    #property indicator_width5 2
    #property indicator_color5 0xFFAA00
    #property indicator_label5 "Buy Trend"

    • Буфер 6: Для отображения красной линии, когда MA 100 ниже MA 200

    #property indicator_type6 DRAW_LINE
    #property indicator_style6 STYLE_SOLID
    #property indicator_width6 2
    #property indicator_color6 0x0000FF
    #property indicator_label6 "Sell Trend"
    Примечание: Раздел выше служит в качестве заглушки для дополнительной информации. Более подробную информацию можно найти в основном коде ниже. Структура буфера не жесткая и допускает вариации значений при условии сохранения исходного замысла.

    Основной код Trend Constraint v1.04

    ///Indicator Name: Trend Constraint
    #property copyright "Clemence Benjamin"
    #property link      "https://mql5.com"
    #property version   "1.04"
    #property description "A model that seek to produce sell signal when D1 candle is Bearish only and  buy signal when it is Bullish"
    //--- indicator settings
    #property indicator_chart_window
    #property indicator_buffers 6
    #property indicator_plots 6
    
    #property indicator_type1 DRAW_ARROW
    #property indicator_width1 5
    #property indicator_color1 0xFF3C00
    #property indicator_label1 "Buy"
    
    #property indicator_type2 DRAW_ARROW
    #property indicator_width2 5
    #property indicator_color2 0x0000FF
    #property indicator_label2 "Sell"
    
    #property indicator_type3 DRAW_ARROW
    #property indicator_width3 2
    #property indicator_color3 0xE8351A
    #property indicator_label3 "Buy Reversal"
    
    #property indicator_type4 DRAW_ARROW
    #property indicator_width4 2
    #property indicator_color4 0x1A1AE8
    #property indicator_label4 "Sell Reversal"
    
    #property indicator_type5 DRAW_LINE
    #property indicator_style5 STYLE_SOLID
    #property indicator_width5 2
    #property indicator_color5 0xFFAA00
    #property indicator_label5 "Buy Trend"
    
    #property indicator_type6 DRAW_LINE
    #property indicator_style6 STYLE_SOLID
    #property indicator_width6 2
    #property indicator_color6 0x0000FF
    #property indicator_label6 "Sell Trend"
    
    #define PLOT_MAXIMUM_BARS_BACK 5000
    #define OMIT_OLDEST_BARS 50
    
    //--- indicator buffers
    double Buffer1[];
    double Buffer2[];
    double Buffer3[];
    double Buffer4[];
    double Buffer5[];
    double Buffer6[];
    
    input double Oversold = 30;
    input double Overbought = 70;
    input int Slow_MA_period = 200;
    input int Fast_MA_period = 100;
    datetime time_alert; //used when sending alert
    input bool Audible_Alerts = true;
    input bool Push_Notifications = true;
    double myPoint; //initialized in OnInit
    int RSI_handle;
    double RSI[];
    double Open[];
    double Close[];
    int MA_handle;
    double MA[];
    int MA_handle2;
    double MA2[];
    int MA_handle3;
    double MA3[];
    int MA_handle4;
    double MA4[];
    double Low[];
    double High[];
    int MA_handle5;
    double MA5[];
    int MA_handle6;
    double MA6[];
    
    void myAlert(string type, string message)
      {
       if(type == "print")
          Print(message);
       else if(type == "error")
         {
          Print(type+" | Trend Constraint V1.04 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
         }
       else if(type == "order")
         {
         }
       else if(type == "modify")
         {
         }
       else if(type == "indicator")
         {
          if(Audible_Alerts) Alert(type+" | Trend Constraint V1.04 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
          if(Push_Notifications) SendNotification(type+" | Trend Constraint V1.04 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
         }
      }
    
    //+------------------------------------------------------------------+
    //| Custom indicator initialization function                         |
    //+------------------------------------------------------------------+
    int OnInit()
      {   
       SetIndexBuffer(0, Buffer1);
       PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
       PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
       PlotIndexSetInteger(0, PLOT_ARROW, 241);
       SetIndexBuffer(1, Buffer2);
       PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
       PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
       PlotIndexSetInteger(1, PLOT_ARROW, 242);
       SetIndexBuffer(2, Buffer3);
       PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
       PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
       PlotIndexSetInteger(2, PLOT_ARROW, 236);
       SetIndexBuffer(3, Buffer4);
       PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE);
       PlotIndexSetInteger(3, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
       PlotIndexSetInteger(3, PLOT_ARROW, 238);
       SetIndexBuffer(4, Buffer5);
       PlotIndexSetDouble(4, PLOT_EMPTY_VALUE, EMPTY_VALUE);
       PlotIndexSetInteger(4, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
       SetIndexBuffer(5, Buffer6);
       PlotIndexSetDouble(5, PLOT_EMPTY_VALUE, EMPTY_VALUE);
       PlotIndexSetInteger(5, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
       //initialize myPoint
       myPoint = Point();
       if(Digits() == 5 || Digits() == 3)
         {
          myPoint *= 10;
         }
       RSI_handle = iRSI(NULL, PERIOD_CURRENT, 14, PRICE_CLOSE);
       if(RSI_handle < 0)
         {
          Print("The creation of iRSI has failed: RSI_handle=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_SMMA, PRICE_CLOSE);
       if(MA_handle < 0)
         {
          Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       MA_handle2 = iMA(NULL, PERIOD_CURRENT, 400, 0, MODE_SMA, PRICE_CLOSE);
       if(MA_handle2 < 0)
         {
          Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       MA_handle3 = iMA(NULL, PERIOD_CURRENT, 100, 0, MODE_EMA, PRICE_CLOSE);
       if(MA_handle3 < 0)
         {
          Print("The creation of iMA has failed: MA_handle3=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       MA_handle4 = iMA(NULL, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE);
       if(MA_handle4 < 0)
         {
          Print("The creation of iMA has failed: MA_handle4=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       MA_handle5 = iMA(NULL, PERIOD_CURRENT, Fast_MA_period, 0, MODE_SMA, PRICE_CLOSE);
       if(MA_handle5 < 0)
         {
          Print("The creation of iMA has failed: MA_handle5=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       MA_handle6 = iMA(NULL, PERIOD_CURRENT, Slow_MA_period, 0, MODE_SMA, PRICE_CLOSE);
       if(MA_handle6 < 0)
         {
          Print("The creation of iMA has failed: MA_handle6=", INVALID_HANDLE);
          Print("Runtime error = ", GetLastError());
          return(INIT_FAILED);
         }
       
       return(INIT_SUCCEEDED);
      }
    
    //+------------------------------------------------------------------+
    //| Custom indicator iteration function                              |
    //+------------------------------------------------------------------+
    int OnCalculate(const int rates_total,
                    const int prev_calculated,
                    const datetime& time[],
                    const double& open[],
                    const double& high[],
                    const double& low[],
                    const double& close[],
                    const long& tick_volume[],
                    const long& volume[],
                    const int& spread[])
      {
       int limit = rates_total - prev_calculated;
       //--- counting from 0 to rates_total
       ArraySetAsSeries(Buffer1, true);
       ArraySetAsSeries(Buffer2, true);
       ArraySetAsSeries(Buffer3, true);
       ArraySetAsSeries(Buffer4, true);
       ArraySetAsSeries(Buffer5, true);
       ArraySetAsSeries(Buffer6, true);
       //--- initial zero
       if(prev_calculated < 1)
         {
          ArrayInitialize(Buffer1, EMPTY_VALUE);
          ArrayInitialize(Buffer2, EMPTY_VALUE);
          ArrayInitialize(Buffer3, EMPTY_VALUE);
          ArrayInitialize(Buffer4, EMPTY_VALUE);
          ArrayInitialize(Buffer5, EMPTY_VALUE);
          ArrayInitialize(Buffer6, EMPTY_VALUE);
         }
       else
          limit++;
       datetime Time[];
       
       datetime TimeShift[];
       if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total);
       ArraySetAsSeries(TimeShift, true);
       int barshift_M1[];
       ArrayResize(barshift_M1, rates_total);
       int barshift_D1[];
       ArrayResize(barshift_D1, rates_total);
       for(int i = 0; i < rates_total; i++)
         {
          barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]);
          barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]);
       }
       if(BarsCalculated(RSI_handle) <= 0) 
          return(0);
       if(CopyBuffer(RSI_handle, 0, 0, rates_total, RSI) <= 0) return(rates_total);
       ArraySetAsSeries(RSI, true);
       if(CopyOpen(Symbol(), PERIOD_M1, 0, rates_total, Open) <= 0) return(rates_total);
       ArraySetAsSeries(Open, true);
       if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close) <= 0) return(rates_total);
       ArraySetAsSeries(Close, true);
       if(BarsCalculated(MA_handle) <= 0) 
          return(0);
       if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total);
       ArraySetAsSeries(MA, true);
       if(BarsCalculated(MA_handle2) <= 0) 
          return(0);
       if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total);
       ArraySetAsSeries(MA2, true);
       if(BarsCalculated(MA_handle3) <= 0) 
          return(0);
       if(CopyBuffer(MA_handle3, 0, 0, rates_total, MA3) <= 0) return(rates_total);
       ArraySetAsSeries(MA3, true);
       if(BarsCalculated(MA_handle4) <= 0) 
          return(0);
       if(CopyBuffer(MA_handle4, 0, 0, rates_total, MA4) <= 0) return(rates_total);
       ArraySetAsSeries(MA4, true);
       if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total);
       ArraySetAsSeries(Low, true);
       if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total);
       ArraySetAsSeries(High, true);
       if(BarsCalculated(MA_handle5) <= 0) 
          return(0);
       if(CopyBuffer(MA_handle5, 0, 0, rates_total, MA5) <= 0) return(rates_total);
       ArraySetAsSeries(MA5, true);
       if(BarsCalculated(MA_handle6) <= 0) 
          return(0);
       if(CopyBuffer(MA_handle6, 0, 0, rates_total, MA6) <= 0) return(rates_total);
       ArraySetAsSeries(MA6, true);
       if(CopyTime(Symbol(), Period(), 0, rates_total, Time) <= 0) return(rates_total);
       ArraySetAsSeries(Time, true);
       //--- main loop
       for(int i = limit-1; i >= 0; i--)
         {
          if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation   
          
          if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue;
          if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue;
          
          //Indicator Buffer 1
          if(RSI[i] < Oversold
          && RSI[i+1] > Oversold //Relative Strength Index crosses below fixed value
          && Open[barshift_M1[i]] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close
          && MA[i] > MA2[i] //Moving Average > Moving Average
          && MA3[i] > MA4[i] //Moving Average > Moving Average
          )
            {
             Buffer1[i] = Low[1+i]; //Set indicator value at Candlestick Low
             if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy"); //Alert on next bar open
             time_alert = Time[1];
            }
          else
            {
             Buffer1[i] = EMPTY_VALUE;
            }
          //Indicator Buffer 2
          if(RSI[i] > Overbought
          && RSI[i+1] < Overbought //Relative Strength Index crosses above fixed value
          && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close
          && MA[i] < MA2[i] //Moving Average < Moving Average
          && MA3[i] < MA4[i] //Moving Average < Moving Average
          )
            {
             Buffer2[i] = High[1+i]; //Set indicator value at Candlestick High
             if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell"); //Alert on next bar open
             time_alert = Time[1];
            }
          else
            {
             Buffer2[i] = EMPTY_VALUE;
            }
          //Indicator Buffer 3
          if(MA5[i] > MA6[i]
          && MA5[i+1] < MA6[i+1] //Moving Average crosses above Moving Average
          )
            {
             Buffer3[i] = Low[i]; //Set indicator value at Candlestick Low
             if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy Reversal"); //Alert on next bar open
             time_alert = Time[1];
            }
          else
            {
             Buffer3[i] = EMPTY_VALUE;
            }
          //Indicator Buffer 4
          if(MA5[i] < MA6[i]
          && MA5[i+1] > MA6[i+1] //Moving Average crosses below Moving Average
          )
            {
             Buffer4[i] = High[i]; //Set indicator value at Candlestick High
             if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell Reversal"); //Alert on next bar open
             time_alert = Time[1];
            }
          else
            {
             Buffer4[i] = EMPTY_VALUE;
            }
          //Indicator Buffer 5
          if(MA5[i] > MA6[i] //Moving Average > Moving Average
          )
            {
             Buffer5[i] = MA6[i]; //Set indicator value at Moving Average
             if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Buy Trend"); //Alert on next bar open
             time_alert = Time[1];
            }
          else
            {
             Buffer5[i] = EMPTY_VALUE;
            }
          //Indicator Buffer 6
          if(MA5[i] < MA6[i] //Moving Average < Moving Average
          )
            {
             Buffer6[i] = MA6[i]; //Set indicator value at Moving Average
             if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Sell Trend"); //Alert on next bar open
             time_alert = Time[1];
            }
          else
            {
             Buffer6[i] = EMPTY_VALUE;
            }
         }
       return(rates_total);
      }
    //You are the best coder


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

    Trend Constraint V1.04 на USDJPY

    Рис. 2. Trend Constraint V1.04 на USDJPY

    Trend Constraint V1.04 на индексе Boom 500

    Рис. 3. Trend Constraint V1.04 на индексе Boom 500

    Состояние свечи D1

    Мы хотим быстро проверять статус свечи D1 в момент начала использования нашей модели. Я решил добавить скрипт, который показывает статус свечи D1 на графике, даже если его таймфрейм отличается от D1. Это улучшение помогает быстро определять состояние свечи, особенно при работе на таймфрейме M1, где разделители периода D1 могут быть не видны при определенных уровнях масштабирования. Теперь давайте рассмотрим код скрипта MQL5:

    //My_D1_candlestatus.mql5
    //Author: Clemence Benjamin
    //Link: 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 script_show_inputs
    #property strict
    
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
      {
       //--- Get the opening and closing prices of the current D1 candle
       double openPrice = iOpen(NULL, PERIOD_D1, 0);
       double closePrice = iClose(NULL, PERIOD_D1, 0);
       
       //--- Determine if the candle is bullish or bearish
       string candleStatus;
       if(closePrice > openPrice)
         {
          candleStatus = " D1 candle is bullish.";
         }
       else if(closePrice < openPrice)
         {
          candleStatus = " D1 candle is bearish.";
         }
       else
         {
          candleStatus = " D1 candle is neutral.";// when open price is equal to close price
         
         }
       
       //--- Print the status on the chart
       Comment(candleStatus);
       
       //--- Also print the status in the Experts tab for logging
       Print(candleStatus);
      }
    //+------------------------------------------------------------------+
    
    


    Понимание функций и переменных скрипта My_D1_Candlestatus.mq5

    Функции и переменные Описание
    OnStart() Основная функция скрипта, которая выполняется при его запуске. Она извлекает цены открытия и закрытия текущей свечи D1, определяет, является ли свеча бычьей, медвежьей или нейтральной, а затем отображает эту информацию на графике с помощью Comment().
    iOpen() и iClose() Функции извлекают цены открытия и закрытия текущей свечи D1.

    candleStatus Строковая переменная для хранения сообщения о состоянии текущей свечи D1.
    Comment() Функция отображает сообщение о состоянии на графике.
    Print() Функция сохраняет сообщение о состоянии на вкладке "Эксперты".

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

    Запуск скрипта состояния свечи My D1 Candle

    Рис. 4. Запуск скрипта My_D1_candlestatus.mq5


    Альтернативы стилям рисования MQL5

    MetaTrader 5 поставляется с широким набором вспомогательных средств для оценки рынка, таких как линии, каналы и фигуры. Глубокое понимание объектно-ориентированного языка программирования MQL5 и его связей с Python и C++ позволяет трейдерам разрабатывать персонализированные вспомогательные инструменты и расширения. Трейдеры могут использовать эти инструменты для расширения своих возможностей технического анализа и принятия более обоснованных торговых решений. Благодаря гибкости и возможностям настройки, доступным в MetaTrader 5, трейдеры могут адаптировать свою торговлю в соответствии со своими предпочтениями и стратегиями. 


    Заключение

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

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


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

    Прикрепленные файлы |
    My_D1_Candle.mq5 (1.35 KB)
    MY_D1_Candle.ex5 (5.7 KB)
    Последние комментарии | Перейти к обсуждению на форуме трейдеров (1)
    4641208
    4641208 | 13 июн. 2024 в 16:23
    В статьях:MQL5 разработан таким образом, что он силен в алгоритме анализа данных, а также силен в рисовании различных стилей индикаторов на Meta Trader 5.
    Алгоритм атомарного орбитального поиска — Atomic Orbital Search (AOS) Алгоритм атомарного орбитального поиска — Atomic Orbital Search (AOS)
    В статье рассматривается алгоритм AOS (Atomic Orbital Search), который использует концепции атомной орбитальной модели для моделирования поиска решений. Алгоритм основывается на вероятностных распределениях и динамике взаимодействий в атоме. В статье подробно обсуждаются математические аспекты AOS, включая обновление положений кандидатов решений и механизмы поглощения и выброса энергии. AOS открывает новые горизонты для применения квантовых принципов в вычислительных задачах, предлагая инновационный подход к оптимизации.
    Нейросети в трейдинге: Гиперболическая модель латентной диффузии (Окончание) Нейросети в трейдинге: Гиперболическая модель латентной диффузии (Окончание)
    Применение анизотропных диффузионных процессов для кодирования исходных данных в гиперболическом латентном пространстве, как это предложено в фреймворке HypDIff, способствует сохранению топологических особенностей текущей рыночной ситуации, и повышает качество её анализа. В предыдущей статье мы начали реализацию предложенных подходов средствами MQL5. И сегодня продолжим начатую работу, доведя ее до логического завершения.
    Быстрый тестер торговых стратегий на Python с использованием Numba Быстрый тестер торговых стратегий на Python с использованием Numba
    В статье реализован быстрый тестер стратегий для моделей машинного обучения с применением Numba. По скорости он превосходит тестер стратегий на чистом Python в 50 раз. Автор рекомендует использовать эту библиотеку для ускорения математических расчетов и особенно там, где используются циклы.
    Пошаговая инструкция для торговли по стратегии Break of Structure (BoS) Пошаговая инструкция для торговли по стратегии Break of Structure (BoS)
    Подробное руководство по разработке автоматизированного торгового алгоритма на основе стратегии Break of Structure (BoS, прорыв структуры). Дана подробная информация по всем аспектам создания советника на MQL5 и его тестирования в MetaTrader 5 — от анализа ценовых уровней поддержки и сопротивления до управления рисками