Разработка инструментария для анализа движения цен (Часть 17): Советник TrendLoom
Содержание
Введение
Методы анализа рынка и подтверждения входа в сделку различаются у разных аналитиков трендов. Многие трейдеры анализируют несколько таймфреймов, таких как M1, M5 и M15 или H1, H4 и W1, чтобы подтвердить свои точки входа и повысить надежность сигналов. Вместо того чтобы переключать таймфреймы для оценки общего тренда, вы просто нажимаете кнопку и получаете своевременное обновление либо оно приходит автоматически. Вы когда-нибудь видели, как на более коротком таймфрейме начиналась продажа, вы открывали сделку, а затем, открыв график на более крупном таймфрейме, обнаруживали тренд на покупку?
Советник TrendLoom позволяет избежать такой ошибки. Он оснащен панелью с семью кнопками, представляющими различные торговые стили. Каждая кнопка отображает три таймфрейма, которые анализируются вместе с использованием скользящих средних для генерации сигналов, таких как BUY (покупка), SELL (продажа) или NEUTRAL (нейтральное состояние). Этот мощный инструмент обеспечивает быстрое обновление подтверждений и непрерывно обновляется по мере обнаружения соответствующих сигналов.
Обзор стратегии
Советник TrendLoom EA имеет графический интерфейс (панель). Панель содержит семь кнопок, каждая из которых соответствует определенной торговой стратегии.- Short-Term Focus (M1, M5, M15) - краткосрочная торговля
- Scalping/Intraday (M5, M15, H1) - скальпинг/внутридневная торговля
- Swing Trading (M15, H1, H4) - свинговая торговля
- Trend Trading (H1, H4, D1) - торговля по тренду
- MTF Trend Confirmation (H1, H4, W1) - подтверждение тренда на нескольких таймфреймах
- Short Scalper/Mid-Trend (M5, H1, D1) - короткий скальпинг
- Long-Term Trend (H1, D1, W1) - долгосрочный тренд
Давайте разберемся, как советник генерирует сигналы на покупку, продажу или нейтральную позицию при нажатии кнопки.
- Сбор данных - для каждого из трех временных интервалов (например, M1, M5 и M15) советник получает цену закрытия последней полностью сформированной свечи.
- Расчет SMA - для каждого таймфрейма советник рассчитывает простую скользящую среднюю (SMA) за 50 периодов. Она служит ориентиром для текущей цены.
- Если цена находится выше скользящей средней, это считается бычьим сигналом и ей присваивается значение +1.
- Если цена находится ниже скользящей средней, это расценивается как медвежий сигнал, и ей присваивается значение -1.
- Когда цена равна скользящей средней, сигнал нейтральный (0).
Объединение сигналов
- Три отдельных сигнала (по одному из каждого таймфрейма) суммируются.
- Определение окончательного сигнала:
- Если сумма равна 2 или больше, это указывает на сильный бычий импульс. Советник возвращает сигнал на покупку.
- Если сумма равна -2 или меньше, это указывает на сильный медвежий импульс. Советник возвращает сигнал на продажу.
- В противном случае сигналы являются смешанными или нейтральными.
Давайте рассмотрим следующую схему, чтобы лучше понять этот процесс.

Рис 1. Блок-схема
Реализация в MQL5
В самом верху вы увидите комментарии в заголовке и определения свойств советника. Эти строки служат метаданными для советника, указывая на авторские права, версию и ссылку на источник. Директива #property strict используется для обеспечения более строгих правил компиляции, что помогает предотвратить распространенные ошибки в коде.
//+------------------------------------------------------------------+ //| TrendLoom EA.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.00" #property strict
Далее, код включает в себя несколько заголовочных файлов, которые предоставляют элементы управления для диалоговых окон, кнопок, меток и панелей. Также добавлены элементы управления объектами графика для отображения текста на графике. Такая модульная структура позволяет советнику использовать предварительно созданные классы для пользовательского интерфейса.
Сюда входят директивы и библиотеки ссылок в папке Include в MetaEditor's. Файлы в подпапке Controls содержат встроенные классы для диалоговых окон и кнопок. Кроме того, они содержат классы для меток и панелей. Такая конструкция упрощает создание интерактивного интерфейса без переписывания кода. Файл в подпапке ChartObjects (ChartObjectsTxtControls.mqh) позволяет отображать динамический текст на графике.
#include <Controls/Dialog.mqh> #include <Controls/Button.mqh> #include <Controls/Label.mqh> #include <Controls/Panel.mqh> #include <ChartObjects/ChartObjectsTxtControls.mqh> // Adjusted include path (singular folder)
Затем определяются константы для выравнивания текста и значения цвета. Этот подход повышает ясность кода и упрощает его сопровождение.
#ifndef ALIGN_LEFT #define ALIGN_LEFT 0 #endif #ifndef ALIGN_CENTER #define ALIGN_CENTER 1 #endif #ifndef ALIGN_RIGHT #define ALIGN_RIGHT 2 #endif #define clrSilver 0xC0C0C0
Советник задает входные параметры, которые регулируют внешний вид и положение панели и ее кнопок. Параметры PanelX, PanelY и PanelWidth задают геометрию панели, а параметры цвета определяют визуальную тему. Размеры кнопок регулируются параметрами btnWidth, btnHeight и btnSpacing, а советник позволяет настраивать как расположение кнопок, так и их цвета. Данная конфигурация обеспечивает гибкость в настройке пользовательского интерфейса под ваши потребности.
//---- Input parameters ----------------------------------------------- input int PanelX = 10; input int PanelY = 10; input int PanelWidth = 250; input int btnWidth = 220; input int btnHeight = 30; input int btnSpacing = 5; input color PanelBackgroundColor = clrDimGray; input color PanelHeaderColor = clrBlueViolet; input color ButtonBgColor = clrBlack; input color ButtonTextColor = clrBlueViolet; input color AnalysisTextColor = clrLime;
Массивы хранят названия и тексты кнопок, что делает обновление или добавление новых кнопок быстрым и простым. В этой конструкции вся информация, касающаяся кнопок, сосредоточена в одном месте, поэтому для внесения изменений требуются лишь незначительные корректировки. Это также повышает согласованность пользовательского интерфейса и снижает вероятность ошибок. Этот метод обеспечивает гибкость для будущих улучшений и поддерживает чистоту и организованность кода.
//---- Button Names and Texts (7 analysis options) -------------------- string buttonNames[7] = { "btnShortTerm", "btnScalping", "btnSwing", "btnTrend", "btnMTFTrend", "btnShortScalper", "btnLongTerm" }; string buttonTexts[7] = { "Short Term Focus\n(M1, M5, M15)", "Scalping/Intraday\n(M5, M15, H1)", "Swing Trading\n(M15, H1, H4)", "Trend Trading\n(H1, H4, D1)", "MTF Trend Confirm\n(H1, H4, W1)", "Short Scalper/Mid Trend\n(M5, H1, D1)", "Long Term Trend\n(H1, D1, W1)" };
Глобальные макросы определяют имена для заголовка панели и метки анализа. Эти макросы обеспечивают согласованность всего кода и служат единым источником для этих идентификаторов. Централизация этих имен упрощает обновление компонентов панели и снижает риск опечаток. Такой подход упрощает сопровождение и обеспечивает согласованный и понятный код.
// Global object names for panel header and analysis label #define PANEL_BG "PanelBG" #define PANEL_HEADER "PanelHeader" #define ANALYSIS_LABEL "AnalysisResult"
Затем в коде объявляются две вспомогательные функции: GetSMA вычисляет простую скользящую среднюю, а AnalyzeTimeframes анализирует рынок на разных таймфреймах. Эти функции составляют основу логики анализа рынка.
//--- Helper function declarations double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift); string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3);
Пользовательский класс CTrendLoomPanel наследуется от CAppDialog. Он объединяет все элементы пользовательского интерфейса, такие как заголовок, главная панель, кнопки и метка результата. Такая конструкция создает модульный интерфейс, который проще в управлении и расширении.
Создание панели
Метод CreateTrendPanel сначала создает диалоговое окно. Затем создается заголовок с пользовательским текстом, цветом, размером и стилем шрифта. Выравнивание устанавливается с помощью функции ObjectSetInteger.
bool CreateTrendPanel(const long chart, const string name, const int x1, const int y1, const int x2, const int y2) { if(!CAppDialog::Create(chart, name, 0, x1, y1, x2, y2)) { Print("Failed to create TrendLoom dialog."); return false; } if(!m_lblHeader.Create(0, "TrendLoomHeader", 0, 10, 10, x2 - x1 - 20, 30)) { Print("Failed to create header label."); return false; } m_lblHeader.Text("TrendLoom EA"); m_lblHeader.Color(PanelHeaderColor); m_lblHeader.FontSize(14); m_lblHeader.Font("Segoe UI"); Add(m_lblHeader); if(!ObjectSetInteger(0L, m_lblHeader.Name(), OBJPROP_ALIGN, (long)ALIGN_CENTER)) Print("Failed to set header alignment");
Далее метод создает основную панель и динамически рассчитывает ее размеры. Затем он создает каждую кнопку и размещает их одну за другой. Наконец, под кнопками добавляется метка с результатами, отображающая итоговый анализ.
Обработка событий
Метод OnEvent обрабатывает взаимодействие с пользователем. При нажатии кнопки происходит вызов функции AnalyzeTimeframes с соответствующими параметрами таймфреймов. Результаты анализа обновляются на панели, и отображается предупреждение.
bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(sparam == "btnShortTerm") { string res = AnalyzeTimeframes(PERIOD_M1, PERIOD_M5, PERIOD_M15); string out = "Short Term Focus: " + res; UpdateResults(out); Alert(out); return true; } else if(sparam == "btnScalping") { string res = AnalyzeTimeframes(PERIOD_M5, PERIOD_M15, PERIOD_H1); string out = "Scalping/Intraday: " + res; UpdateResults(out); Alert(out); return true; } // Additional conditions for other buttons return false; }
Обновление пользовательского интерфейса
Метод UpdateResults обновляет метку результатов, добавляя новые данные анализа. Затем вызывается функция ChartRedraw, благодаря чему обновленная информация отображается немедленно.
void UpdateResults(const string &result) { m_lblResults.Text("Analysis Result: " + result); ChartRedraw(); }
Основные аналитические функции
Расчет простой скользящей средней (SMA)
Функция GetSMA вычисляет скользящую среднюю, создавая хэндл индикатора с помощью функции. Она копирует значения SMA из буфера индикатора, а затем освобождает хэндл для освобождения ресурсов.
double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift) { int handle = iMA(symbol, timeframe, period, 0, MODE_SMA, PRICE_CLOSE); if(handle == INVALID_HANDLE) { Print("Failed to create iMA handle for timeframe ", timeframe); return 0.0; } double sma[]; if(CopyBuffer(handle, 0, shift, 1, sma) <= 0) { Print("Failed to copy buffer for timeframe ", timeframe); IndicatorRelease(handle); return 0.0; } double result = sma[0]; IndicatorRelease(handle); return result; }
Анализ нескольких таймфреймов
Функция AnalyzeTimeframes получает цену закрытия и скользящую среднюю для трех таймфреймов и подает бычий сигнал, когда цена превышает скользящую среднюю, или медвежий сигнал, когда она опускается ниже нее. Она суммирует отдельные сигналы, чтобы выдать окончательную рекомендацию: покупать, когда сумма равна 2 или больше, продавать, когда она равна -2 или меньше, и нейтральное состояние в противном случае. Каждый таймфрейм оценивается независимо, чтобы получить сбалансированное представление о рыночных трендах, а параметр сдвига гарантирует, что для анализа используется только последняя завершенная свеча. Объединение сигналов с нескольких таймфреймов снижает влияние временных рыночных колебаний, а корректировка периода скользящей средней дополнительно повышает чувствительность торговых сигналов.
string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3) { int period = 50; int shift = 1; // last completed candle double price1 = iClose(_Symbol, tf1, shift); double sma1 = GetSMA(_Symbol, tf1, period, shift); int signal1 = (price1 > sma1) ? 1 : (price1 < sma1 ? -1 : 0); double price2 = iClose(_Symbol, tf2, shift); double sma2 = GetSMA(_Symbol, tf2, period, shift); int signal2 = (price2 > sma2) ? 1 : (price2 < sma2 ? -1 : 0); double price3 = iClose(_Symbol, tf3, shift); double sma3 = GetSMA(_Symbol, tf3, period, shift); int signal3 = (price3 > sma3) ? 1 : (price3 < sma3 ? -1 : 0); int sum = signal1 + signal2 + signal3; if(sum >= 2) return "BUY"; else if(sum <= -2) return "SELL"; else return "NEUTRAL"; }Функции жизненного цикла советника отвечают за инициализацию, очистку и обработку событий. Функция OnInit создает панель TrendLoom, используя входные параметры. Если создать панель не удалось, советник возвращает ошибку инициализации.
int OnInit() { if(!TrendPanel.CreateTrendPanel(0, "TrendLoom Panel", PanelX, PanelY, PanelX + PanelWidth + 20, PanelY + 400)) { Print("Failed to create TrendLoom Panel."); return INIT_FAILED; } return INIT_SUCCEEDED; }
Функция OnDeinit выполняет очистку, уничтожая панель при удалении советника или закрытии графика.
void OnDeinit(const int reason) { TrendPanel.Destroy(reason); }
Наконец, функция OnChartEvent перенаправляет события графика обработчику событий панели, чтобы интерфейс оставался отзывчивым.
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { TrendPanel.ChartEvent(id, lparam, dparam, sparam); }
В MetaEditor необходимые файлы хранятся в папке include. Для доступа к указанным файлам, как показано в фрагменте кода, обратитесь к подпапкам, изображенным на скриншотах ниже. Такая организация гарантирует, что компилятор найдет файлы элементов управления диалогом, кнопкой, меткой и панелью в папке include/Controls, а элементы управления объектами графика — в папке include/ChartObjects.
#include <Controls/Dialog.mqh> #include <Controls/Button.mqh> #include <Controls/Label.mqh> #include <Controls/Panel.mqh> #include <ChartObjects/ChartObjectsTxtControls.mqh> // Adjusted include path (singular folder)
Шаг 1

Рис 2. Шаг 1
Шаг 2

Рис. 3. Шаг 2
Код MQL5
//+------------------------------------------------------------------+ //| TrendLoom EA.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.00" #property strict #include <Controls/Dialog.mqh> #include <Controls/Button.mqh> #include <Controls/Label.mqh> #include <Controls/Panel.mqh> #include <ChartObjects/ChartObjectsTxtControls.mqh> // Adjusted include path (singular folder) // Define alignment constants if not already defined #ifndef ALIGN_LEFT #define ALIGN_LEFT 0 #endif #ifndef ALIGN_CENTER #define ALIGN_CENTER 1 #endif #ifndef ALIGN_RIGHT #define ALIGN_RIGHT 2 #endif #define clrSilver 0xC0C0C0 //---- Input parameters ----------------------------------------------- input int PanelX = 10; // Top-left X coordinate of panel input int PanelY = 10; // Top-left Y coordinate of panel input int PanelWidth = 250; // Panel width (for longer text) input int btnWidth = 220; // Button width input int btnHeight = 30; // Button height input int btnSpacing = 5; // Spacing between buttons input color PanelBackgroundColor = clrDimGray; // Panel background color input color PanelHeaderColor = clrBlueViolet; // Panel header text color input color ButtonBgColor = clrBlack; // Button background color input color ButtonTextColor = clrBlueViolet; // Button text color input color AnalysisTextColor = clrLime; // Analysis result text color //---- Button Names and Texts (7 analysis options) -------------------- string buttonNames[7] = { "btnShortTerm", "btnScalping", "btnSwing", "btnTrend", "btnMTFTrend", "btnShortScalper", "btnLongTerm" }; string buttonTexts[7] = { "Short Term Focus\n(M1, M5, M15)", "Scalping/Intraday\n(M5, M15, H1)", "Swing Trading\n(M15, H1, H4)", "Trend Trading\n(H1, H4, D1)", "MTF Trend Confirm\n(H1, H4, W1)", "Short Scalper/Mid Trend\n(M5, H1, D1)", "Long Term Trend\n(H1, D1, W1)" }; // Global object names for panel header and analysis label #define PANEL_BG "PanelBG" #define PANEL_HEADER "PanelHeader" #define ANALYSIS_LABEL "AnalysisResult" //--- Helper function declarations double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift); string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3); //------------------------------------------------------------------------------ // CTrendLoomPanel class - A modern, modular panel for TrendLoom EA //------------------------------------------------------------------------------ class CTrendLoomPanel : public CAppDialog { private: CLabel m_lblHeader; CPanel m_panelMain; CButton m_btnShortTerm; CButton m_btnScalping; CButton m_btnSwing; CButton m_btnTrend; CButton m_btnMTFTrend; CButton m_btnShortScalper; CButton m_btnLongTerm; CLabel m_lblResults; public: // Create the TrendLoom Panel dialog bool CreateTrendPanel(const long chart, const string name, const int x1, const int y1, const int x2, const int y2) { if(!CAppDialog::Create(chart, name, 0, x1, y1, x2, y2)) { Print("Failed to create TrendLoom dialog."); return false; } // Create header label if(!m_lblHeader.Create(0, "TrendLoomHeader", 0, 10, 10, x2 - x1 - 20, 30)) { Print("Failed to create header label."); return false; } m_lblHeader.Text("TrendLoom EA"); m_lblHeader.Color(PanelHeaderColor); m_lblHeader.FontSize(14); m_lblHeader.Font("Segoe UI"); Add(m_lblHeader); // Set header text alignment to center using ObjectSetInteger if(!ObjectSetInteger(0L, m_lblHeader.Name(), OBJPROP_ALIGN, (long)ALIGN_CENTER)) Print("Failed to set header alignment"); // Create main panel background int panelBottom = 50 + (btnHeight + btnSpacing) * 7 + btnSpacing; if(!m_panelMain.Create(0, "TrendLoomPanel", 0, 10, 50, x2 - x1 - 10, panelBottom)) { Print("Failed to create main panel."); return false; } m_panelMain.Color(PanelBackgroundColor); m_panelMain.BorderType(BORDER_RAISED); m_panelMain.ColorBorder(clrSilver); Add(m_panelMain); // Starting coordinates for buttons int btnX = 20; // relative to dialog int btnY = 60; int buttonWidth = btnWidth; int buttonHeight = btnHeight; // Create each button with a modern look if(!m_btnShortTerm.Create(0, buttonNames[0], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight)) return false; m_btnShortTerm.Text(buttonTexts[0]); m_btnShortTerm.Font("Segoe UI"); m_btnShortTerm.FontSize(12); m_btnShortTerm.Color(ButtonBgColor); Add(m_btnShortTerm); btnY += buttonHeight + btnSpacing; if(!m_btnScalping.Create(0, buttonNames[1], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight)) return false; m_btnScalping.Text(buttonTexts[1]); m_btnScalping.Font("Segoe UI"); m_btnScalping.FontSize(12); m_btnScalping.Color(ButtonBgColor); Add(m_btnScalping); btnY += buttonHeight + btnSpacing; if(!m_btnSwing.Create(0, buttonNames[2], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight)) return false; m_btnSwing.Text(buttonTexts[2]); m_btnSwing.Font("Segoe UI"); m_btnSwing.FontSize(12); m_btnSwing.Color(ButtonBgColor); Add(m_btnSwing); btnY += buttonHeight + btnSpacing; if(!m_btnTrend.Create(0, buttonNames[3], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight)) return false; m_btnTrend.Text(buttonTexts[3]); m_btnTrend.Font("Segoe UI"); m_btnTrend.FontSize(12); m_btnTrend.Color(ButtonBgColor); Add(m_btnTrend); btnY += buttonHeight + btnSpacing; if(!m_btnMTFTrend.Create(0, buttonNames[4], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight)) return false; m_btnMTFTrend.Text(buttonTexts[4]); m_btnMTFTrend.Font("Segoe UI"); m_btnMTFTrend.FontSize(12); m_btnMTFTrend.Color(ButtonBgColor); Add(m_btnMTFTrend); btnY += buttonHeight + btnSpacing; if(!m_btnShortScalper.Create(0, buttonNames[5], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight)) return false; m_btnShortScalper.Text(buttonTexts[5]); m_btnShortScalper.Font("Segoe UI"); m_btnShortScalper.FontSize(12); m_btnShortScalper.Color(ButtonBgColor); Add(m_btnShortScalper); btnY += buttonHeight + btnSpacing; if(!m_btnLongTerm.Create(0, buttonNames[6], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight)) return false; m_btnLongTerm.Text(buttonTexts[6]); m_btnLongTerm.Font("Segoe UI"); m_btnLongTerm.FontSize(12); m_btnLongTerm.Color(ButtonBgColor); Add(m_btnLongTerm); btnY += buttonHeight + btnSpacing; // Create results label below the buttons if(!m_lblResults.Create(0, "TrendResults", 0, btnX, btnY, btnX + buttonWidth, btnY + 30)) return false; m_lblResults.Text("Analysis Result: [Waiting for Input]"); m_lblResults.Font("Segoe UI"); m_lblResults.FontSize(12); m_lblResults.Color(AnalysisTextColor); Add(m_lblResults); // Set results text alignment to left using ObjectSetInteger if(!ObjectSetInteger(0L, m_lblResults.Name(), OBJPROP_ALIGN, (long)ALIGN_LEFT)) Print("Failed to set results alignment"); Show(); return true; } // Process events (button clicks) bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(sparam == "btnShortTerm") { string res = AnalyzeTimeframes(PERIOD_M1, PERIOD_M5, PERIOD_M15); string out = "Short Term Focus: " + res; UpdateResults(out); Alert(out); return true; } else if(sparam == "btnScalping") { string res = AnalyzeTimeframes(PERIOD_M5, PERIOD_M15, PERIOD_H1); string out = "Scalping/Intraday: " + res; UpdateResults(out); Alert(out); return true; } else if(sparam == "btnSwing") { string res = AnalyzeTimeframes(PERIOD_M15, PERIOD_H1, PERIOD_H4); string out = "Swing Trading: " + res; UpdateResults(out); Alert(out); return true; } else if(sparam == "btnTrend") { string res = AnalyzeTimeframes(PERIOD_H1, PERIOD_H4, PERIOD_D1); string out = "Trend Trading: " + res; UpdateResults(out); Alert(out); return true; } else if(sparam == "btnMTFTrend") { string res = AnalyzeTimeframes(PERIOD_H1, PERIOD_H4, PERIOD_W1); string out = "MTF Trend Confirm: " + res; UpdateResults(out); Alert(out); return true; } else if(sparam == "btnShortScalper") { string res = AnalyzeTimeframes(PERIOD_M5, PERIOD_H1, PERIOD_D1); string out = "Short Scalper/Mid Trend: " + res; UpdateResults(out); Alert(out); return true; } else if(sparam == "btnLongTerm") { string res = AnalyzeTimeframes(PERIOD_H1, PERIOD_D1, PERIOD_W1); string out = "Long Term Trend: " + res; UpdateResults(out); Alert(out); return true; } return false; } bool ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { return OnEvent(id, lparam, dparam, sparam); } // Update the results label and refresh the chart void UpdateResults(const string &result) { m_lblResults.Text("Analysis Result: " + result); ChartRedraw(); } }; // Global instance of the TrendLoom Panel CTrendLoomPanel TrendPanel; //------------------------------------------------------------------------------ // Helper functions (core analysis logic) //------------------------------------------------------------------------------ double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift) { int handle = iMA(symbol, timeframe, period, 0, MODE_SMA, PRICE_CLOSE); if(handle == INVALID_HANDLE) { Print("Failed to create iMA handle for timeframe ", timeframe); return 0.0; } double sma[]; // dynamic array to store SMA values if(CopyBuffer(handle, 0, shift, 1, sma) <= 0) { Print("Failed to copy buffer for timeframe ", timeframe); IndicatorRelease(handle); return 0.0; } double result = sma[0]; IndicatorRelease(handle); return result; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3) { int period = 50; int shift = 1; // last completed candle double price1 = iClose(_Symbol, tf1, shift); double sma1 = GetSMA(_Symbol, tf1, period, shift); int signal1 = (price1 > sma1) ? 1 : (price1 < sma1 ? -1 : 0); double price2 = iClose(_Symbol, tf2, shift); double sma2 = GetSMA(_Symbol, tf2, period, shift); int signal2 = (price2 > sma2) ? 1 : (price2 < sma2 ? -1 : 0); double price3 = iClose(_Symbol, tf3, shift); double sma3 = GetSMA(_Symbol, tf3, period, shift); int signal3 = (price3 > sma3) ? 1 : (price3 < sma3 ? -1 : 0); int sum = signal1 + signal2 + signal3; if(sum >= 2) return "BUY"; else if(sum <= -2) return "SELL"; else return "NEUTRAL"; } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { if(!TrendPanel.CreateTrendPanel(0, "TrendLoom Panel", PanelX, PanelY, PanelX + PanelWidth + 20, PanelY + 400)) { Print("Failed to create TrendLoom Panel."); return INIT_FAILED; } return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { TrendPanel.Destroy(reason); } //+------------------------------------------------------------------+ //| Chart Event Handler | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { TrendPanel.ChartEvent(id, lparam, dparam, sparam); } //+------------------------------------------------------------------+
Результаты
Для каждого трейдера крайне важно тщательно тестировать свои системы, прежде чем использовать их в реальных сделках. Тестирование включает в себя анализ исторических данных, чтобы увидеть, как система работала бы без риска вложения средств. Вы также можете использовать демо-счета для наблюдения за реальной производительностью в реальном времени. Это поможет вам разработать и улучшить более надежный инструмент, который вы сможете уверенно использовать на реальном счете. Лично я предпочитаю потратить значительное время на тестирование и доработку советника для получения более надежных результатов.
В этом разделе я представляю результаты тестирования советника, работающего на графике. Я протестировал его на показателе волатильности 75 (1 сек), и это дало замечательные и прибыльные результаты. Все кнопки работают как положено, и аналитические данные обновляются практически мгновенно при нажатии кнопки. Давайте рассмотрим первый тест ниже.

Рис 4. Тестирование при Volatility 75 (1 сек)
Ниже представлена диаграмма, иллюстрирующая поведение рынка после совершения сделки на основе полученного сигнала. Здесь показано продолжение сделки, показанной на GIF-анимации выше. Я использовал таймфрейм M1, чтобы представить более широкий обзор сделок.

Рис. 5. Тестирование на V 75 (1 сек)
Заключение
Создав и протестировав советник, я могу с уверенностью подтвердить его пользу в анализе рынка. Быстрая обработка сигналов и общая оценка тренда позволили добиться впечатляющих результатов по индексам волатильности. Однако этот инструмент служит скорее вспомогательным средством, чем конечным источником сигнала. Я рекомендую вам тщательно протестировать его и настроить параметры в соответствии с вашими предпочтениями. Вы также можете дополнительно изменить его, чтобы настроить внешний вид кнопок. Используйте его для подтверждения вашей общей стратегии. В этой роли инструмент наиболее эффективен.
| Дата | Название инструмента | Описание | Версия | Обновления | Примечания |
|---|---|---|---|---|---|
| 01/10/24 | Chart Projector | Скрипт для наложения эффекта призрака на движение цены за предыдущий день. | 1.0 | Первоначальная версия | Инструмент номер 1 |
| 18/11/24 | Analytical Comment | Предоставляет информацию за предыдущий день в табличном формате, а также прогнозирует будущее направление рынка. | 1.0 | Первоначальная версия | Инструмент номер 2 |
| 27/11/24 | Analytics Master | Регулярное обновление рыночных показателей каждые два часа | 1.01 | Вторая версия | Инструмент номер 3 |
| 02/12/24 | Analytics Forecaster | Регулярное обновление рыночных показателей каждые два часа с интеграцией с Telegram | 1.1 | Третья версия | Инструмент номер 4 |
| 09/12/24 | Volatility Navigator | Советник анализирует рыночные условия с помощью полос Боллинджера, RSI и ATR. | 1.0 | Первоначальная версия | Инструмент номер 5 |
| 19/12/24 | Mean Reversion Signal Reaper | Анализирует рынок и генерирует сигналы, используя стратегию возврата к среднему | 1.0 | Первоначальная версия | Инструмент номер 6 |
| 9/01/25 | Signal Pulse | Анализирует несколько таймфреймов | 1.0 | Первоначальная версия | Инструмент номер 7 |
| 17/01/25 | Metrics Board | Панель с кнопками для анализа | 1.0 | Первоначальная версия | Инструмент номер 8 |
| 21/01/25 | External Flow | Аналитика с помощью внешних библиотек | 1.0 | Первоначальная версия | Инструмент номер 9 |
| 27/01/25 | VWAP | Взвешенная по объему средняя цена | 1.3 | Первоначальная версия | Инструмент номер 10 |
| 02/02/25 | Heikin Ashi | Сглаживание тренда и идентификация сигналов разворота | 1.0 | Первоначальная версия | Инструмент номер 11 |
| 04/02/25 | FibVWAP | Генерация сигнала с помощью анализа Python | 1.0 | Первоначальная версия | Инструмент номер 12 |
| 14/02/25 | RSI DIVERGENCE | Дивергенция цены и RSI | 1.0 | Первоначальная версия | Инструмент номер 13 |
| 17/02/25 | Parabolic Stop and Reverse (PSAR) | Автоматизация стратегии PSAR | 1.0 | Первоначальная версия | Инструмент номер 14 |
| 20/02/25 | Скрипт Quarters Drawer | Нанесение уровней четвертей на график | 1.0 | Первоначальная версия | Инструмент номер 15 |
| 27/02/25 | Intrusion Detector | Обнаружение и оповещение о достижении ценой уровней четвертей | 1.0 | Первоначальная версия | Инструмент номер 16 |
| 27/02/25 | TrendLoom Tool | Панель мультитаймфреймового анализа | 1.0 | Первоначальная версия | Инструмент номер 17 |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/17329
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Алгоритм оптимизации одуванчика — Dandelion Optimizer (DO)
Разработка инструментария для анализа движения цен (Часть 15): Введение в теорию четвертей (II) — советник Intrusion Detector
Реализация механизма безубыточности в MQL5 (Часть 1): Базовый класс и режим безубытка по фиксированным пунктам
Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (EEMFlow)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Вау, фантастика, я вижу, что в это вложено много усилий, спасибо, что поделились своим подходом и кодом.