Построение модели для ограничения диапазона сигналов по тренду (Часть 4): Настройка стиля отображения для каждой трендовой волны
Содержание
- Введение
- Краткое повторение
- Стили отображения MQL5
- Реализация стиля DRAW_LINE в системе.
- Состояние свечи D1
- Понимание функций и переменных My_D1_Candlestatus.mq5
- Альтернативы стилям рисования MQL5
- Заключение
Введение
Пользовательские стили рисования могут улучшить визуальную привлекательность графиков, сделав их более удобными для анализа. Хорошо продуманный график может улучшить снижает нагрузку на глаза во время длительных торговых сессий.Адаптируя стили рисования к конкретным потребностям, трейдеры могут добиться более эффективных торговых настроек. Например, использование гистограмм для представления данных об объеме или линий для скользящих средних может облегчить ускорить интерпретацию этих индикаторов. Для обозначения определенных событий или сигналов на графике, например точек покупки/продажи, можно использовать такие стили рисования, как стрелки или символы, что упрощает выявление торговых возможностей.
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 в меню индикатора.
Рис. 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
Наше обновленное решение теперь демонстрирует расширенные возможности, изменяя цвет линии каждый раз, когда устанавливается новое направление. Этот функционал оптимизирует график за счет добавления цвета, тем самым улучшая систему сигналов наряду с другими аудио- и видеоуведомлениями. На изображениях ниже наглядно показана работа новой функции.

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

Рис. 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() | Функция сохраняет сообщение о состоянии на вкладке "Эксперты". |
После компиляции кода скрипт можно запустить, следуя инструкциям, приведенным ниже. Скрипт отобразит комментарий, показывающий состояние свечи текущего дня.

Рис. 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
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Алгоритм атомарного орбитального поиска — Atomic Orbital Search (AOS)
Нейросети в трейдинге: Гиперболическая модель латентной диффузии (Окончание)
Быстрый тестер торговых стратегий на Python с использованием Numba
Пошаговая инструкция для торговли по стратегии Break of Structure (BoS)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования

Ознакомьтесь с новой статьей: Построение модели ограничений свечного тренда (часть 4): Настройка стиля отображения для каждой волны тренда.
Автор: Клеменс Бенджамин