Построение модели ограничения тренда свечей (Часть 1): Для советников и технических индикаторов
Содержание
- Введение
- Анатомия свечей старшего таймфрейма
- Разработка стратегии (пересечение скользящих средних) плюс код
- Обоснование ограничения и его применение плюс код
- Преимущества использования кода
- Заключение
Введение
Бычий или медвежий характер свечей более высокого таймфрейма может дать ценную информацию о направлении рынка. Такой анализ может служить альтернативой использованию скользящих средних для определения рыночных трендов. Например, в рамках свечи D1 или H4 наблюдается значительная базовая активность, происходящая на таймфреймах M1 и даже тиках. Трейдеры могут получить преимущество, используя возможности покупки, предоставляемые бычьими свечами D1, и продажи во время медвежьих фаз. Сочетание с техническими индикаторами на более коротких таймфреймах помогает точно определять точки входа, предоставляя трейдерам стратегическое преимущество. При работе с бычьей дневной свечой, трейдерам следует терпеливо ждать, пока не сложатся благоприятные рыночные условия, прежде чем уверенно следовать тренду.
Целью данной статьи является эффективная классификация текущей свечи как бычьей или медвежьей с использованием кода MQL5, устанавливающего условие продажи только в случае медвежьей свечи и покупки только в случае бычьей свечи.
Цель этой модели — ограничить генератор сигналов выдачей сигналов, соответствующих текущему тренду свечи. Это можно сравнить с забором, который не позволяет определенным животным проникать на ваш двор в зависимости от их размера, но при этом позволяет проходить другим. Мы применяем аналогичную концепцию для фильтрации избранных сигналов и сохранения только наиболее оптимальных. Модель анализирует свечи и рыночные тренды более высокого таймфрейма, фактически создавая виртуальный барьер, который пропускает только сигналы, соответствующие преобладающей тенденции. Такая выборочная фильтрация повышает точность и надежность генерируемых сигналов, гарантируя, что пользователю будут предоставлены только самые выгодные торговые возможности.
К концу этой статьи вы сможете:
- Изучать ценовое движение на всей свече D1 с помощью доступных коротких таймфреймов.
- Создать буфер индикатора пересечения скользящих средних, который включает условие ограничения тренда на более высоком таймфрейме.
- Понимать концепцию отсеивания лучших сигналов из заданной стратегии.
Анатомия свечей старшего таймфрейма
Рис. 1.1. Анатомия свечм D1 на M5 для синтетического индекса Boom 500
На изображении выше показана красная полоса свечи D1 слева и ценовое действие M5 справа между разделителями дневных периодов. Очевиден отчетливый нисходящий тренд, поддерживаемый медвежьим характером дневной свечи, что указывает на более высокую вероятность продажи. В данной настройке особое внимание уделяется исполнению сделок в соответствии с дневной свечой, что отражает возникновение идеи ограничения в результате развития тренда более высокого таймфрейма.
Разработка стратегии (пересечение скользящих средних)
Разработка торговой стратегии требует сочетания анализа, тестирования и постоянного совершенствования. Успешная торговая стратегия должна основываться на глубоком понимании рынка, а также на четком наборе правил и рекомендаций, которым необходимо следовать. Важно постоянно отслеживать и корректировать стратегию по мере изменения рыночных условий, чтобы адаптироваться к новым трендам и возможностям. Постоянно анализируя данные, тестируя различные подходы и внося коррективы по мере необходимости, трейдеры могут повысить свои шансы на успех на рынке.
Прежде чем мы перейдем к нашей стратегии пересечения скользящих средних, обобщим основные советы по разработке стратегии:
- Определите свои цели и терпимость к риску
- Понимайте рынок
- Выберите свой стиль торговли
- Разработайте правила входа и выхода
- Внедрите стратегии управления рисками
- Протестируйте стратегию на истории
- Оптимизируйте ее
- Торгуйте "на бумаге", перед тем как перейти на реальный счет
- Отслеживайте и оценивайте
- Установите условия стратегии (в данном случае пересечение EMA7 выше или ниже EMA21)
- Установите стиль отображения индикатора, который может быть стрелкой или любой геометрической фигурой, доступной в MetaTrader 5.
- (Необязательно) Если индикатор будет настраиваться пользователем, задайте входные данные
Я решил включить сюда окончательный код без особых пояснений, чтобы сосредоточиться на алгоритме ограничений — нашей главной теме в этой статье. Следующая программа готова к компиляции и генерации сигналов покупки и продажи. Далее мы проанализируем результаты на графике и определим проблему, которую будет решать алгоритм ограничений.
//Indicator Name: Trend Constraint #property copyright "Clemence Benjamin" #property link "https://mql5.com" #property version "1.00" #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 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_width1 5 #property indicator_color1 0xFFAA00 #property indicator_label1 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Sell" #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; double myPoint; //initialized in OnInit int MA_handle; double MA[]; int MA_handle2; double MA2[]; double Low[]; double High[]; void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | Trend constraint @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } } // 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); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_EMA, 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, 21, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle2 < 0) { Print("The creation of iMA has failed: MA_handle2=", 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); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); } else limit++; 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(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); //--- 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 //Indicator Buffer 1 if(MA[i] > MA2[i] && MA[i+1] < MA2[i+1] //Moving Average crosses above Moving Average ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(MA[i] < MA2[i] && MA[i+1] > MA2[i+1] //Moving Average crosses below Moving Average ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); } //copy the code to meta editor to compile it
На графике результатов теста EURUSD от 12.04.24 отмечено начало периода, наблюдаемого на таймфрейме М1. Пересечения обозначены стрелками: красные — для сигналов продажи, синие — для сигналов покупки. Несмотря на это, более широкая перспектива выявляет отчетливый нисходящий тренд, указывающий на медвежью свечу D1. Индикатор пересечения подает оба сигнала (на покупку и на продажу), игнорируя преобладающий тренд. Противоречивые сигналы создают сложную ситуацию для трейдеров, пытающихся ориентироваться на рынке. Хотя таймфреймы M1 указывают на потенциальные возможности для краткосрочной торговли, общий нисходящий тренд на свече D1 ставит под вопрос устойчивость любых восходящих движений. Мы решим эту проблему, ограничив наши сигналы трендом D1.
Рис. 1.2. Индикатор пересечения скользящих средних до введения ограничений
Результат свечи D1 является медвежьим. Стрелки на покупку и продажу генерируются условием пересечения скользящих средних. Многие сигналы считаются ложными или несоответствующими тренду, что можно исправить, включив ограничение тренда более высокого таймфрейма. Приведенная ниже таблица была создана с использованием информации графика с начала дня до его закрытия.
Тип сигнала | Количество |
---|---|
Сигналы на продажу | 29 |
Сигналы на покупку | 28 |
Итого | 57 |
Ложные и нетрендовые сигналы | 41 |
Успешные сигналы | 25 |
Обоснование ограничения и его применение
Представьте себе смесь зерен кукурузы и сорго - первое грубее последнего. Для их разделения мы используем сито. Оно отсеивает зерна кукурузы, пропуская только сорго. Эта аналогия согласуется с рассматриваемой концепцией ограничения более высокого временного интервала. Он действует как фильтр, отсеивая определенные сигналы и оставляя только те, которые соответствуют преобладающему тренду. Ограничение по большему таймфрейму, подобно ситу, усиливает наше внимание, позволяя нам различать основные элементы рыночного тренда. Просеивая шум, мы можем лучше понять основную динамику происходящего, способствуя принятию более обоснованных решений. Этот стратегический подход повышает нашу способность ориентироваться в сложностях финансового ландшафта, гарантируя, что мы остаемся на одной линии с общим направлением, подобно тому, как сорго отделяется от кукурузы, раскрывая истинную суть движения рынка.
Определим природу свечи D1 как условия для ограничения тренда.- Я определяю свои текущие рыночные настроения как бычьи или медвежьи, сравнивая цену закрытия предыдущего дня, которая аналогична цене открытия текущего дня, и цены закрытия свечей младшего таймфрейма M1.
- Давайте рассмотрим код. Он хорошо структурирован и прост для понимания.
Для БЫЧЬЕЙ свечи:
закрытие предыдущей свечи M1 >= закрытие предыдущей свечи D1
Для МЕДВЕЖЬЕЙ свечи:
закрытие предыдущей свечи M1 <= закрытие предыдущей свечи D1
Математика показывает, что при наличии бычьей свечи D1 в качестве драйвера тренда мы будем получать только сигналы на покупку, а для медвежьей свечи D1 - только сигналы на продажу.
Мы выбрали закрытие более короткого таймфрейма в качестве точки сравнения с нашим открытием D1 вместо других показателей, таких как цена Bid и Ask или закрытие текущего дня, поскольку последнее не отображает стрелки на графике, как того требуют стратегия и стиль индикатора. Сосредоточившись на закрытии более короткого таймфрейма по отношению к открытию D1, мы можем эффективно выровнять нашу стратегию с желаемыми визуальными подсказками и индикаторами на графике. Такой подход повышает ясность и точность наших торговых решений, обеспечивая более оптимизированный и эффективный процесс анализа.
if(Close[1+barshift_M1[i]] >= Open[1+barshift_D1[i]] //Candlestick Close >= Candlestick Open ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; }
Приведенный выше код представляет собой состояние бычьей свечи D1. Зеркальная версия кода работает и для медвежьего тренда.
- Ниже представлен окончательный код, в котором ограничение бесшовно интегрировано с индикатором пересечения скользящей средней.
/Indicator Name: Trend Constraint #property copyright "Clemence Benjamin" #property link "https://mql5.com" #property version "1.00" #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 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_width1 5/ #property indicator_color1 0xFFAA00 #property indicator_label1 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Sell" #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; double myPoint; //initialized in OnInit int MA_handle; double MA[]; int MA_handle2; double MA2[]; double Close[]; double Close2[]; double Low[]; double High[]; void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | Trend constraint @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } } // 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); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_EMA, 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, 21, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle2 < 0) { Print("The creation of iMA has failed: MA_handle2=", 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); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); } else limit++; 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(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(CopyClose(Symbol(), PERIOD_M1, 0, rates_total, Close) <= 0) return(rates_total); ArraySetAsSeries(Close, true); if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close2) <= 0) return(rates_total); ArraySetAsSeries(Close2, 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); //--- 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(MA[i] > MA2[i] && MA[i+1] < MA2[i+1] //Moving Average crosses above Moving Average && Close[1+barshift_M1[i]] >= Close2[1+barshift_D1[i]] //Candlestick Close >= Candlestick Close ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(MA[i] < MA2[i] && MA[i+1] > MA2[i+1] //Moving Average crosses below Moving Average && Close[1+barshift_M1[i]] <= Close2[1+barshift_D1[i]] //Candlestick Close <= Candlestick Close ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); }
Результат использования кода выше превосходен.
Рис. 1.4. Применено ограничение тренда. Результат потрясающий
Тип сигнала | Units |
---|---|
Сигнал на продажу | 27 |
Сигнал на покупку | 1 |
Итого | 28 |
Ложные и нетрендовые сигналы | 3 |
Успешные сигналы | 25 |
Из приведенной выше таблицы мы видим положительное влияние ограничения тренда на более высоком таймфрейме как фильтра, приводящего к большему количеству выигрышей, чем проигрышей, что делает его идеальным для советников. Сравнивая предыдущие и текущие таблицы результатов, мы замечаем, что успешные сигналы сохранили свою ценность, в то время как количество ложных сигналов сократилось. Это улучшение точности сигнала указывает на эффективность нашей методологии анализа данных. Усовершенствовав наши алгоритмы и критерии, мы свели к минимуму возникновение ложных сигналов, повысив общую надежность наших результатов. В дальнейшем этот прогресс, несомненно, будет способствовать принятию более обоснованных решений и улучшению результатов наших стратегий.
Преимущества использования кода
Преимущества наложения ограничений на тренды более высокого таймфрейма повышают ясность направления рынка, уменьшая тенденции к чрезмерной торговле и способствуя более дисциплинированному подходу к торговым решениям. Этот метод также может обеспечить более широкую перспективу, помогая трейдерам не попасть в ловушку краткосрочных колебаний и позволяя им согласовывать свои стратегии с преобладающим долгосрочным трендом. Сосредоточившись на общей картине, трейдеры лучше подготовлены к тому, чтобы отфильтровывать шум и принимать более обоснованные решения. Такой подход поощряет терпение и более глубокое понимание динамики рынка, что в конечном итоге приводит к более последовательным и прибыльным торговым результатам. Кроме того, ограничения на тренды более высокого таймфрейма могут служить ценными инструментами для управления рисками, позволяя трейдерам устанавливать четкие уровни входа и выхода на основе стратегической оценки рыночных условий.
Если кратко:
- Повышенная точность индикаторов генерации сигналов
- Лучшее управление рисками
- Повышение прибыльности
- Меньше работы
- Меньше сигналов
Заключение
Свечи более высокого таймфрейма оказывают существенное влияние на тренды более низкого таймфрейма, по сути, направляя рынки. На основании различных исследований рекомендуется рассматривать возможность покупки во время бычьих дневных свечей на меньших таймфреймах и продажи во время медвежьих свечей. Интеграция концепции ограничений тренда на более высоких временных интервалах может иметь решающее значение в разработке советников и индикаторов для получения устойчивых положительных результатов. Возникает вопрос: следует ли нам отказаться от скользящих средних как инструментов определения тренда? Возможно, следующая статья прольет свет на этот вопрос. В ней мы глубже погрузимся в уточнение и развитие этой концепции. К статье приложены файлы исходного кода, которые вы можете просмотреть в редакторе MetaEditor, и файлы .ex5 для работы в MetaTrader 5.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/14347
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования