
Разработка советника для мониторинга точек входа в свинг-сделки
Содержание:
- Введение
- Краткая история BTCUSD с 2021 по 2024 год
- Разработка советника для мониторинга точек входа в свинг-сделки
- Шаг 1: Знакомство со стратегией EMA 100
- Шаг 2: Индикатор для мониторинга
- Шаг 3: Разработка советника
- Тестирование и оптимизация
- Результаты и анализ
- Заключение
Введение
BTCUSD является одной из наиболее ярких торговых пар со значительными долгосрочными перспективами. Сегодня мы выбрали ее в качестве примера, на котором будет основан наш процесс разработки.
Цена биткоина характеризуется высокой волатильностью, движимой рыночным сентиментом, макроэкономическими факторами и развитием механизмов регулирования. Выявление прибыльных уровней входа среди таких колебаний является нетривиальной задачей, особенно для трейдеров, опирающихся исключительно на ручной анализ. К примеру, за последние два года цена BTC затронула диапазон от низов около $16 000 до исторического максимума $99 645,39 в ноябре 2024 года. В течение этого периода возникало несколько основных возможностей для входа по EMA 100, стратегии, предлагающей ценную информацию для долгосрочных торговых стратегий.
Решением для вызова, определенного выше, является разработка советника на языке MQL5 для мониторинга сигналов на вход в долгосрочные сделки. Этот советник будет:
- Непрерывно отслеживать ценовые движения указанной пары.
- Использовать EMA 100 в качестве динамического уровня поддержки или сопротивления, выявляя таким образом потенциальные возможности для входа.
- Предупреждать трейдеров в моменты соблюдения определенных условий, таких как отскок цены от EMA 100.
Этот инструмент позволит автоматизировать анализ, чтобы трейдеры могли сконцентрироваться на принятии решений вместо постоянного мониторинга.
На изображении ниже показаны ключевые уровни поддержки для BTC в соответствии со 100-дневной EMA.
BTCUSD, H4: Курс биткоина к доллару США: Отскок цены от EMA 100
Краткая история BTCUSD с 2021 по 2024 год
В период с 2021 по 2024 год биткоин претерпевал значительные изменения в цене. После резкого падения в 2022 году, когда биткоин закрылся ниже $20 000 в связи с повышением процентных ставок и спадами на рынке, в 2023 году биткоин отскочил от уровня $16 530 и достиг $42 258. В 2024 году биткоин взлетел после одобрения спотовых ETF на биткоин и снижения ставки Федеральной резервной системы США, достигнув в ноябре пика на уровне $99 645,39.
На момент написания данной статьи пара торгуется около $97 300, демонстрируя значительный рост в 146,5% по сравнению с ценой годом ранее. Согласно CoinGecko исторический максимум, поставленный в начале декабря 2024 года, составил $99 645,39.
Дневной график BTCUSD за период 2021-2024
Разработка советника для мониторинга точек входа в свинг-сделки
Я разбил процесс разработки на три шага, чтобы оптимизировать процесс создания полноценного советника. Первый шаг заключается в знакомстве со скользящей средней, которую мы будем использовать в качестве основы для разработки нашего собственного индикатора. Этот индикатор будет представлять собой автономный инструмент, а также послужит основой для создания нашего советника для мониторинга на последующих шагах.
Шаг 1: Знакомство со стратегией EMA 100
Экспоненциальная скользящая средняя (EMA) – это широко используемый индикатор, который придает недавним данным больший вес. В частности, EMA 100 представляет собой критический уровень для торговли и зачастую выступает как сильный уровень поддержки или сопротивления. Исторически множество прибыльные возможности для входа в биткоин наступали в моменты отскока цены от EMA 100, особенно в периоды сильной волатильности.
Шаг 2: Индикатор для мониторинга
Поскольку мы используем экспоненциальную скользящую среднюю (EMA), встроенную в терминал MetaTrader 5, я решил сперва разработать индикатор для мониторинга, основанный на этом встроенном инструменте. Данный подход упрощает процесс выявления ключевых зон интереса при движении цены. По моему опыту, индикатор может отправлять алерты через уведомления в терминале, пуш-уведомления и даже по электронной почте.
Однако ему недостает способности обрабатывать веб-запросы, необходимой для продвинутых алерт-сервисов, таких как интеграция с популярными социальными сетями. Чтобы справиться с этим ограничением, мы перейдем к шагу 3, на котором внедрим индикатор в советник. Это преобразование предлагает более надежный функционал, включая бесперебойную коммуникацию через Telegram, тем самым обеспечивая универсальность и эффективность системы мониторинга.
Процесс разработки нашего индикатора для мониторинга подразделяется на следующие составляющие:
Свойства и метаданные:
В данном разделе определяются важнейшие метаданные для советника, включая правообладателя, ссылку на профиль автора, номер версии и краткое описание назначения индикатора. Данная информация критически важна для документации и позволяет пользователям быстро понять идею автора и предполагаемый функционал.
#property copyright "Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.0" #property description "EMA 100 Monitoring Indicator"
В этой части мы настроим визуальное представление индикатора на торговом графике. Директива #property indicator_chart_window указывает, что советник будет работать в главном окне графика. Определив два буфера для индикаторов (indicator_buffers 2), мы подготовим возможность отображения двух различных сигналов. Свойства indicator_type1 и indicator_type2 указывают, что оба индикатора будут отображаться в виде стрелок с различными цветами (оранжевый и синий) и метками, гласящими "Ищите отскок от EMA 100". Такая конфигурация повышает прозрачность для трейдеров, предоставляя мгновенные визуальные сигналы о потенциальных торговых возможностях, которые основаны на взаимодействии цены с экспоненциальной скользящей средней (EMA).
///Properties and 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 "Look for EMA 100 bounce " #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Look for EMA 100 bounce "
Определение буферов
В данном разделе приводится определение буферов для индикаторов, которые хранят значения для сигналов, генерируемых советником. Buffer1 и Buffer2 объявлены в виде массивов типа double, которые хранят данные для двух типов сигналов, относящихся к движениям цены и EMA. Константы PLOT_MAXIMUM_BARS_BACK и OMIT_OLDEST_BARS установлены для управления процессом обработки исторических данных и гарантируют, что программа будет работать эффективно, не захламляя систему устаревшими данными. Такой подход помогает сохранить производительность, при этом предоставляя пользователю актуальную и своевременную информацию.
#define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[];
Входные параметры:
В этой части мы определяем настраиваемые пользователем входные параметры, которые повышают гибкость советника. Строка input int EMA_Period = 100; позволяет пользователю указать период для расчета экспоненциальной скользящей средней, что позволяет адаптировать советник под различные торговые стратегии. Кроме того, такие флаги как Audible_Alerts и Push_Notifications устанавливаются по умолчанию на true, что обеспечивает отправку алертов и уведомлений о значимых рыночных событиях в реальном времени. Объявлены также и другие переменные, такие как Low, High, и MA_handle, которые хранят ценовые данные и используются для расчетов скользящей средней, играя тем самым важнейшую роль в операциях советника.
input int EMA_Period = 100; datetime time_alert; //used when sending alert bool Audible_Alerts = true; bool Push_Notifications = true; double myPoint; //initialized in OnInit double Low[]; int MA_handle; double MA[]; double High[];
Функция алертов:
Функция myAlert разработана для централизации управления алертами в советнике. Она принимает два параметра: тип, который определяет вид алерта (например, "print", "error", "indicator"), и сообщение, которое содержит текст алерта. В зависимости от типа функция либо печатает сообщение для отладки либо отправляет алерты, связанные с изменениями на рынке. Данный подход повышает организованность и читаемость кода, упрощая технические работы. Благодаря предоставлению слышимых алертов и пуш-уведомлений данная функция гарантирует, что пользователи будут в курсе важных движений на рынках, что крайне важно для своевременного принятия торговых решений.
void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } else if(type == "indicator") { Print(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); if(Audible_Alerts) Alert(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); if(Push_Notifications) SendNotification(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } }
Функция инициализации:
Функция OnInit выступает в качестве точки входа, когда советник загружается. Она инициализирует буферы для индикатора и задает расчеты для экспоненциальной скользящей средней. Использование SetIndexBuffer связывает определенные буферы с графиками индикаторов, обеспечивая тем самым возможность отображать значения на графике. Функция также проверяет успешность создания хэндла скользящей средней (MA_handle), что позволяет исправлять ошибки и повышать надежность. Если в ходе инициализации возникнут какие-либо проблемы, выводятся явные сообщения об ошибках, которые упростят пользователям их устранение. Такая настройка крайне важная для обеспечения надлежащей работы советника сразу после запуска.
//+------------------------------------------------------------------+ //| 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, 233); 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, 234); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, EMA_Period, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); }
Функция расчета:
Функция OnCalculate является сердцем советника, в котором прописана логика расчета значений индикаторов. Функция обрабатывает рыночные данные, получает информацию о ценах и рассчитывает скользящую среднюю. Функция начинается с определения того, сколько всего показателей необходимо обработать, исходя из общего количества показателей и количества ранее обработанных показателей. Затем функция инициализирует буферы и извлекает необходимые данные, такие как минимальная и максимальная цена, перед началом основного цикла. Этот цикл проходит по ценовым данным, проверяя условия для генерации торговых сигналов, основанные на взаимодействиях цены с EMA. Эффективность данной функции крайне важна, поскольку она позволяет советнику динамически реагировать на изменения на рынке в реальном времени.
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 Time[]; if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, 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(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);
Основная логика:
В функции OnCalculate цикл основной логики анализирует движения цены по отношению к EMA. Он проверяет определенные условия, например, когда минимальная цена пересечет EMA вниз, или когда максимальная цена пересечет EMA вверх. Когда эти условия выполняются, соответствующие буферы (Buffer1 для отскоков под EMA и Buffer2 для отскоков над ней) заполняются текущими минимальными или максимальными ценами, и создаются алерты для пользователя. Этот механизм является основой для предоставления требующих реагирования торговых сигналов, что позволяет трейдерам принимать информированные решения на основе технического анализа. Четкий и структурированный подход к определению значений индикаторов гарантирует, что пользователи будут получать своевременную и актуальную информацию о потенциальных торговых возможностях.
//--- 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(Low[i] < MA[i] && Low[i+1] > MA[i+1] //Candlestick Low crosses below Moving Average ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Look for EMA 100 bounce "); //Alert on next bar open time_alert = Time[1]; } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(High[i] > MA[i] && High[i+1] < MA[i+1] //Candlestick High crosses above Moving Average ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Look for EMA 100 bounce "); //Alert on next bar open time_alert = Time[1]; } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); } //+------------------------------------------------------------------+
Полный код индикаторов представлен здесь, без ошибок:
#property copyright "Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.0" #property description "EMA 100 Monitoring Indicator" //--- 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 "Look for EMA 100 bounce " #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Look for EMA 100 bounce " #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; input int EMA_Period = 100; datetime time_alert; //used when sending alert bool Audible_Alerts = true; bool Push_Notifications = true; double myPoint; //initialized in OnInit double Low[]; int MA_handle; double MA[]; double High[]; void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } else if(type == "indicator") { Print(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); if(Audible_Alerts) Alert(type+" | EMA 100 Monitor @ "+Symbol()+","+IntegerToString(Period())+" | "+message); if(Push_Notifications) SendNotification(type+" | EMA 100 Monitor @ "+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, 233); 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, 234); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, EMA_Period, 0, MODE_SMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", 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 Time[]; if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, 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(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 //Indicator Buffer 1 if(Low[i] < MA[i] && Low[i+1] > MA[i+1] //Candlestick Low crosses below Moving Average ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Look for EMA 100 bounce "); //Alert on next bar open time_alert = Time[1]; } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(High[i] > MA[i] && High[i+1] < MA[i+1] //Candlestick High crosses above Moving Average ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High if(i == 1 && Time[1] != time_alert) myAlert("indicator", "Look for EMA 100 bounce "); //Alert on next bar open time_alert = Time[1]; } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); } //+------------------------------------------------------------------+
Шаг 3: Разработка советника
В данном разделе вы ознакомитесь с процессом разработки простого, но эффективного советника для мониторинга точек входа в свинг-сделки на языке MQL5. Данный советник создан для мониторинга рыночных цен (с особым акцентом на биткоине в качестве примера) и для отправки алертов на основе заранее определенных условий.
Чтобы упростить этот процесс, мы опустим информацию о метаданных, поскольку их мы подробно обсудили на этапе разработки индикаторов. Давайте разберем код пошагово и убедимся, что каждая часть проста для понимания и реализации.
1. Входные параметры:
input string IndicatorName = "ema100_monitoring_indicator"; // Name of the custom indicator input bool EnableTerminalAlerts = true; input bool EnablePushNotifications = true; input bool EnableTelegramAlerts = false; input string TelegramBotToken = "YOUR_BOT_TOKEN"; // Replace with your bot token input string TelegramChatID = "YOUR_CHAT_ID"; // Replace with your chat ID
В данной части мы определяем различные кастомизируемые входные параметры, которые повышают гибкость советника и удобство пользования им. Параметр IndicatorName позволяет нам указать имя пользовательского индикатора, который мы хотим отслеживать, значение по умолчанию – "Bitcoin Monitor". Булевы флаги EnableTerminalAlerts, EnablePushNotifications и EnableTelegramAlerts позволяют нам производить индивидуальную настройку алертов. Например, мы можем выбрать получать уведомления непосредственно в торговом терминале, на наше мобильное устройство или через Telegram. Кроме того, чтобы получать алерты в Telegram мы должны предоставить токен нашего Telegram-бота и идентификатором чата. Такая кастомизация позволит другим пользователям оптимизировать их торговый опыт в соответствии с их предпочтениями и нуждами.
2. Хэндлы индикаторов:
int indicatorHandle = INVALID_HANDLE; int emaHandle = INVALID_HANDLE;
В этом разделе объявляются переменные, необходимые для управления индикаторами, которые используются в советнике. Переменные indicatorHandle и emaHandle будут хранить ссылки на пользовательский индикатор и на экспоненциальную скользящую среднюю (EMA), соответственно. Оба хэндла инициализируются как INVALID_HANDLE, что означает, что им еще не было присвоено значение. Данная настройка крайне важна для функционала советника, поскольку позволяет программе взаимодействовать с указанными индикаторами и получать релевантные рыночные данные для анализа.
3. Функция алертов:
void AlertMessage(string message) { if (EnableTerminalAlerts) Alert(message); if (EnablePushNotifications) SendNotification(message); if (EnableTelegramAlerts) SendTelegramMessage(message); }
Функция AlertMessage играет ключевую роль в управлении алертами в советнике. Данная функция принимает строковый параметр – сообщение, которое содержит текст отправляемого алерта. Она проверяет пользовательские настройки типа алертов (алерты в терминале, пуш-уведомления или сообщения в Telegram) и отправляет сообщение соответствующим способом. Благодаря централизации управления алертами в данной функции код становится более организованным и простым в обращении. Данный функционал особенно важен для трейдеров, полагающихся на мгновенные уведомления для принятия информированных решений на основе движений рынка.
4. Алерты в Telegram:
void SendTelegramMessage(string message) { if (EnableTelegramAlerts) { string url = "https://api.telegram.org/bot" + TelegramBotToken + "/sendMessage?chat_id=" + TelegramChatID + "&text=" + message; int timeout = 5000; ResetLastError(); char postData[]; uchar result[]; string response; int res = WebRequest("GET", url, NULL, timeout, postData, result, response); if (res != 200) { Print("Telegram WebRequest failed. Error: ", GetLastError(), ", HTTP Code: ", res); } else { Print("Telegram message sent successfully: ", response); } } }
Чтобы упростить коммуникацию с пользователями, реализована функция SendTelegramMessage. Данная функция составляет URL, использующий Telegram API для отправки сообщений в указанный чат. Сперва она проверяет, что включены алерты в Telegram. Если это так, функция подготавливает и отправляет GET-запрос на сервер Telegram с составленным URL, а также токеном бота и идентификатором чата. Функция также обрабатывает потенциальные ошибки при запросе, предоставляя пользователю обратную связь в случае, если сообщение не удается отправить. Этот функционал позволяет пользователям получать алерты непосредственно в Telegram, что повышает их доступность и удобство.
5. Функция инициализации:
int OnInit() { Print("Bitcoin Monitoring EA started."); // Attach the custom indicator to the chart indicatorHandle = iCustom(_Symbol, _Period, IndicatorName); if (indicatorHandle == INVALID_HANDLE) { Print("Failed to attach indicator: ", IndicatorName, ". Error: ", GetLastError()); return(INIT_FAILED); } // Attach built-in EMA 100 to the chart emaHandle = iMA(_Symbol, _Period, 100, 0, MODE_EMA, PRICE_CLOSE); if (emaHandle == INVALID_HANDLE) { Print("Failed to create EMA 100. Error: ", GetLastError()); return(INIT_FAILED); } // Add EMA 100 to the terminal chart if (!ChartIndicatorAdd(0, 0, emaHandle)) { Print("Failed to add EMA 100 to the chart. Error: ", GetLastError()); } return(INIT_SUCCEEDED); }
Функция OnInit выполняется при первом запуске советника. Она отвечает за настройку необходимых индикаторов и обеспечивает готовность советника к работе. В рамках данной функции пользовательский индикатор прикрепляется к графику через его имя, и проверяется хэндл, чтобы подтвердить успешное прикрепление. Если прикрепление не удастся, будет выведено сообщение об ошибке, помогающее диагностировать проблему. Кроме того, функция создает EMA с периодом 100 и проверяет успешность ее создания перед добавлением ее на график. Корректная инициализация крайне важная для функционала советника, поскольку обеспечивает, что все компоненты корректно настроены и готовы к обработке рыночных данных.
6. Функция деинициализации:
void OnDeinit(const int reason) { Print(" EA stopped."); if (indicatorHandle != INVALID_HANDLE) { IndicatorRelease(indicatorHandle); } if (emaHandle != INVALID_HANDLE) { IndicatorRelease(emaHandle); } }
Функция OnDeinit вызывается при удалении советника с графика либо при закрытии терминала. Ее главной целью является освобождение ресурсов и предотвращение утечек памяти. Данная функция проверяет, действительны ли хэндлы индикаторов, и если это так, освобождает их, чтобы освободить ресурсы системы. Функция также выводит сообщение о том, что советник остановлен, тем самым давая пользователям явную обратную связь о статусе советника. Корректная деинициализация крайне важна для поддержания оптимальной производительности и порядка в торговой среде.
7. Основная логика:
void OnTick() { static datetime lastAlertTime = 0; // Prevent repeated alerts for the same signal if (indicatorHandle == INVALID_HANDLE || emaHandle == INVALID_HANDLE) return; double buffer1[], buffer2[]; ArraySetAsSeries(buffer1, true); ArraySetAsSeries(buffer2, true); // Read data from the custom indicator if (CopyBuffer(indicatorHandle, 0, 0, 1, buffer1) < 0) { Print("Failed to copy Buffer1. Error: ", GetLastError()); return; } if (CopyBuffer(indicatorHandle, 1, 0, 1, buffer2) < 0) { Print("Failed to copy Buffer2. Error: ", GetLastError()); return; } // Check for signals in Buffer1 if (buffer1[0] != EMPTY_VALUE && TimeCurrent() != lastAlertTime) { string message = "Signal detected: Look for EMA 100 bounce (Low). Symbol: " + _Symbol; AlertMessage(message); lastAlertTime = TimeCurrent(); } // Check for signals in Buffer2 if (buffer2[0] != EMPTY_VALUE && TimeCurrent() != lastAlertTime) { string message = "Signal detected: Look for EMA 100 bounce (High). Symbol: " + _Symbol; AlertMessage(message); lastAlertTime = TimeCurrent(); } // Debugging EMA 100 value double emaValueArray[]; ArraySetAsSeries(emaValueArray, true); // Ensure it's set as series if (CopyBuffer(emaHandle, 0, 0, 1, emaValueArray) > 0) { Print("EMA 100 Current Value: ", emaValueArray[0]); } else { Print("Failed to read EMA 100 buffer. Error: ", GetLastError()); } }
Функция OnTick содержит основную логику советника и выполняется каждый раз, когда рынок получает новый тик данных. Данная функция проверяет действительность хэндлов индикаторов перед тем, как приступать к их расчету. Она инициализирует массивы для хранения данных от пользовательского индикатора и извлекает последние значения из буферов индикаторов. Если в каком-либо из буферов будет обнаружен сигнал, функция создает алерт через функцию AlertMessage, уведомляя пользователей о потенциальных торговых возможностях. Кроме того, функция получает текущее значение EMA для целей отладки, что обеспечивает прозрачность функционирования советника. Такой анализ в режиме реального времени позволяет советнику быстро реагировать на рыночные изменения, делая его ценным инструментом для трейдеров.
Итак, вот полный код нашего советника:
//+------------------------------------------------------------------+ //| Bitcoin Monitoring Expert Advisor | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com/en/users/billionaire2024/seller | //+------------------------------------------------------------------+ #property copyright "Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.0" #property description "BTCUSD Monitoring Expert Advisor" //--- Input parameters input string IndicatorName = "ema100_monitoring_indicator"; // Name of the custom indicator input bool EnableTerminalAlerts = true; input bool EnablePushNotifications = true; input bool EnableTelegramAlerts = false; input string TelegramBotToken = "YOUR_BOT_TOKEN"; // Replace with your bot token input string TelegramChatID = "YOUR_CHAT_ID"; // Replace with your chat ID //--- Indicator handles int indicatorHandle = INVALID_HANDLE; int emaHandle = INVALID_HANDLE; //--- Alert function void AlertMessage(string message) { if (EnableTerminalAlerts) Alert(message); if (EnablePushNotifications) SendNotification(message); if (EnableTelegramAlerts) SendTelegramMessage(message); } //--- Telegram Alerting void SendTelegramMessage(string message) { if (EnableTelegramAlerts) { string url = "https://api.telegram.org/bot" + TelegramBotToken + "/sendMessage?chat_id=" + TelegramChatID + "&text=" + message; int timeout = 5000; ResetLastError(); char postData[]; uchar result[]; string response; int res = WebRequest("GET", url, NULL, timeout, postData, result, response); if (res != 200) { Print("Telegram WebRequest failed. Error: ", GetLastError(), ", HTTP Code: ", res); } else { Print("Telegram message sent successfully: ", response); } } } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { Print("Bitcoin Monitoring EA started."); // Attach the custom indicator to the chart indicatorHandle = iCustom(_Symbol, _Period, IndicatorName); if (indicatorHandle == INVALID_HANDLE) { Print("Failed to attach indicator: ", IndicatorName, ". Error: ", GetLastError()); return(INIT_FAILED); } // Attach built-in EMA 100 to the chart emaHandle = iMA(_Symbol, _Period, 100, 0, MODE_EMA, PRICE_CLOSE); if (emaHandle == INVALID_HANDLE) { Print("Failed to create EMA 100. Error: ", GetLastError()); return(INIT_FAILED); } // Add EMA 100 to the terminal chart if (!ChartIndicatorAdd(0, 0, emaHandle)) { Print("Failed to add EMA 100 to the chart. Error: ", GetLastError()); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Print("Bitcoin Monitoring EA stopped."); if (indicatorHandle != INVALID_HANDLE) { IndicatorRelease(indicatorHandle); } if (emaHandle != INVALID_HANDLE) { IndicatorRelease(emaHandle); } } void OnTick() { static datetime lastAlertTime = 0; // Prevent repeated alerts for the same signal if (indicatorHandle == INVALID_HANDLE || emaHandle == INVALID_HANDLE) return; double buffer1[], buffer2[]; ArraySetAsSeries(buffer1, true); ArraySetAsSeries(buffer2, true); // Read data from the custom indicator if (CopyBuffer(indicatorHandle, 0, 0, 1, buffer1) < 0) { Print("Failed to copy Buffer1. Error: ", GetLastError()); return; } if (CopyBuffer(indicatorHandle, 1, 0, 1, buffer2) < 0) { Print("Failed to copy Buffer2. Error: ", GetLastError()); return; } // Check for signals in Buffer1 if (buffer1[0] != EMPTY_VALUE && TimeCurrent() != lastAlertTime) { string message = "Signal detected: Look for EMA 100 bounce (Low). Symbol: " + _Symbol; AlertMessage(message); lastAlertTime = TimeCurrent(); } // Check for signals in Buffer2 if (buffer2[0] != EMPTY_VALUE && TimeCurrent() != lastAlertTime) { string message = "Signal detected: Look for EMA 100 bounce (High). Symbol: " + _Symbol; AlertMessage(message); lastAlertTime = TimeCurrent(); } // Debugging EMA 100 value double emaValueArray[]; ArraySetAsSeries(emaValueArray, true); // Ensure it's set as series if (CopyBuffer(emaHandle, 0, 0, 1, emaValueArray) > 0) { Print("EMA 100 Current Value: ", emaValueArray[0]); } else { Print("Failed to read EMA 100 buffer. Error: ", GetLastError()); } }
Тестирование и оптимизация
После успешной компиляции кода мы приступили к его тестированию с помощью тестера стратегий в терминале MetaTrader 5. На изображениях ниже демонстрируются процесс и результаты тестирования.
Советник для мониторинга биткоина: прогон в тестере стратегий
В ходе запуска в тестере стратегий мы успешно продемонстрировали возможности советника по мониторингу цены в реальном времени. Ниже приведена иллюстрация, демонстрирующая процесс работы советника и ее эффективность.
Тиковый мониторинг изменений цены биткоина: 2022 год
Результаты и анализ
Мы успешно продемонстрировали работу индикатора, пронаблюдав его взаимодействие с EMA 100 на больших таймфреймах, в частности на H4 и D1. Система продемонстрировала способность отправлять алерты тремя различными способами, в том числе в виде Telegram-уведомлений. Цена стабильно отскакивала от выбранной EMA, как видно из наших иллюстраций. На изображении ниже показан запуск советника и индикатора в терминале MetaTrader 5, демонстрирующий их интеграцию и функционал.
Добавление советника и индикатора на график
Заключение
Советник для мониторинга, разработанный нами в этой статье, послужит ценным инструментом для каждого трейдера. Автоматизируя мониторинг цены и интегрируя такие стратегии, как EMA 100, он позволяет минимизировать ручную работу, требуемую для выявления торговых возможностей. Хотя мы разработали советник для BTCUSD, его можно адаптировать и под другие инструменты, а также кастомизировать под дополнительные индикаторы. Данный проект служит простой и мотивирующей основу для начинающих. Пределов совершенству нет – попробуйте различные подходы.
Скачайте прикрепленные советник и индикатор, протестируйте их на исторических данных с предпочитаемыми настройками и улучшите его под вашу торговую стратегию. Будьте в авангарде динамичного мира трейдинга, сочетая технический анализ с автоматизацией. Пожалуйста, учтите, что данная система предназначена исключительно для целей мониторинга и алертов, на данном этапе в нее не заложен какой-либо торговый функционал. Наши контакты в Telegram здесь: ссылка 1 и ссылка 2.
Таблица с прикрепленными файлами:
Файлы | Описание |
---|---|
ema100_monitoring_indicator.mq5 | Пользовательский индикатор, основанный на стратегии отскока от EMA 100 |
bitcoin_monitoring_expert.mq5 | Советник, реализующий функционал для алертов в Telegram посредством WebRequest и осуществляющий непрерывный мониторинг. |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/16563




- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования