
MQL5-советник, интегрированный в Telegram (Часть 1): Отправка сообщений из MQL5 в Telegram
Введение
В статье рассмотрена интеграция Telegram с MetaTrader 5. Для выполнения этой задачи мы создадим советник на языке MetaQuotes Language 5 (MQL5). Наша главная задача — создать торгового помощника, который работает в реальном времени и держит нас в курсе событий через чат в Telegram. Бот Telegram, который мы создадим, будет действовать как сервер обновлений, отправляя нам ценную информацию, которая поможет нам принимать важные торговые решения.
Мы создадим Telegram-бот и настроим нашего советника для работы с API мессенджера. Для начала настроим BotFather. Это Telegram-бот, который помогает создавать новых ботов и управлять уже существующими. С помощью BotFather мы создадим нового бота и дадим ему имя. Мы также получим токен. Это важный элемент, который мы будем использовать для идентификации и доступа к нашему боту через API. После этого мы получим идентификатор чата и будем использовать эти два элемента для доступа к API и его работы.
В статье предлагается комплексное руководство по разработке. Мы покажем вам, как написать и реализовать советника, который установит двустороннюю связь между MetaTrader 5 и Telegram. Мы ответим не только на вопрос "как", но и на вопрос "почему", чтобы вы поняли технические и практические аспекты интеграции. Мы также обсудим потенциальные ошибки, которые могут возникнуть во время настройки и эксплуатации, чтобы помочь вам избежать их, а также чтобы вы знали, как с ними бороться, если они произойдут, несмотря на все наши усилия.
Для простоты усвоения статья разбита на следующие разделы:
- Введение в интеграцию MQL5 и Telegram
- Настройка Telegram-бота
- Настройка MetaTrader 5 для общения через Telegram
- Реализация средствами MQL5
- Тестирование интеграции
- Заключение
К концу статьи у вас должно быть четкое понимание того, как добиться интегрированной, автоматизированной коммуникации между терминалом MetaTrader 5 и Telegram. Конечным продуктом будет являться работающий советник.
Введение в интеграцию MQL5 и Telegram
- Обзор серии и целей:
Цель этой серии статей — объединить торговлю в MetaTrader 5 и отправку мгновенных сообщений в Telegram. К концу серии у вас будет работающий советник на языке MQL5, который сможет отправлять и получать сообщения и даже ретранслировать изображения через торговую платформу на ваш аккаунт Telegram. Каждая часть серии основывается на предыдущей, совершенствуя функциональность советника и общую торговую систему.
- Преимущества интеграции Telegram с MQL5:
Интеграция Telegram с MQL5 имеет ряд преимуществ. Прежде всего она предлагает возможность отправлять мгновенные уведомления. Если вы настроили советник для торговли с помощью MQL5, вы можете запрограммировать его на отправку оповещений через Telegram. Это прекрасно работает, поскольку вы можете настроить свой торговый алгоритм таким образом, что будете получать только оповещения о новых потрясающих торговых возможностях или важных событиях, касающихся открытой позиции. Другим основным способом, с помощью которого вы можете общаться со своим торговым алгоритмом через Telegram, является использование Telegram-бота. Боты предлагают несколько явных преимуществ, когда речь идет о программировании сервиса для отправки оповещений и/или обеспечения ограниченной, но безопасной и защищенной передачи конфиденциальных торговых данных. Кроме того, вы можете делиться всевозможными медиаданными, имеющими отношение к торговле, например, графиками или скриншотами, работающими совместно с ботом, чтобы ваши торговые алгоритмы могли лучше работать. Технически бот передает сообщение между пользователем и сервером. Вот подробная визуализация процессов в хронологии:
- Актуальность в современной торговле:
Сегодняшний мир торговли требует от игроков быстрой адаптации. Это вопрос прибылей и убытков. Трейдеры ищут способы автоматизировать свои стратегии, чтобы быть в курсе событий на рынках, не будучи при этом привязанными к своим рабочим столам. Один из последних подходов к достижению этой цели предполагает использование MQL5, мощного языка программирования, совместно с Telegram, приложением для обмена мгновенными сообщениями, которое можно использовать практически как настраиваемую торговую панель. Такое применение мессенджера для трейдинга позволяет уведомлять пользователя о важных событиях, связанных с любыми счетами, которыми он может управлять. Независимо от того, есть ли у вас команда или нет, возможности однорангового (peer-to-peer) обновления Telegram делают приложение кандидатом на включение в набор инструментов трейдера.
- Закладываем основу серии:
Понимание основных концепций и базовых инструментов интеграции имеет первостепенное значение. Начнем с основ: создания Telegram-бота и настройки MQL5 для отправки сообщений через него. Этот шаг является основополагающим. Он позволяет нам заложить основу, на которой мы сможем создавать более продвинутые, сложные и полезные функции в будущих версиях. К концу первой части у нас будет простая, но функциональная система, способная отправлять текстовые сообщения из нашего советника в Telegram. Этот фундамент не только даст нам практические навыки, но и подготовит нас к решению более сложных задач, таких как отправка изображений и поддержка двунаправленной связи между MQL5 и Telegram. В итоге у нас получится следующая интеграция:
Она послужит основой для остальных частей.
Настройка Telegram-бота
Первым шагом в подключении Telegram к MetaTrader 5 является создание Telegram-бота. Этот бот будет служить посредником для сообщений, отправляемых и получаемых из Telegram и MetaTrader 5. Используя BotFather, мы создадим нового бота, снабдим его необходимыми разрешениями, а затем получим API-токен, который позволит нам общаться с нашим ботом.
Откройте Telegram и введите BotFather в поиске. Это специальный бот для создания и управления другими ботами. Поскольку их может быть много с почти одинаковыми названиями, обязательно введите запрос так, как показано на рисунке.
Начните чат с BotFather и используете команду /newbot для создания нового бота. Затем BotFather предложит вам ввести имя и имя пользователя для вашего бота. После этого вы получаете уникальный API-токен. Это очень важно, поскольку позволяет вашему приложению проходить аутентификацию на серверах Telegram и взаимодействовать с ними. Процесс показан в GIF-изображении внизу.
Настройка бота: После получения API-токена нам необходимо настроить бота в соответствии с нашими потребностями. Мы можем запрограммировать его на распознавание и реагирование на команды с помощью команды BotFather /setcommands. Чтобы открыть бота, вы можете либо выполнить поиск по его имени, либо просто нажать на первую ссылку, предоставленную BotFather, как показано ниже:
Мы также можем дать боту более удобный пользовательский интерфейс. Добавление профиля, описания и фотографии сделает его более привлекательным, но это необязательный шаг. Следующий шаг в настройке бота — убедиться, что он может обрабатывать реальные сообщения в соответствии с нашими требованиями.
Получение идентификатора чата (Chat ID): Чтобы отправлять сообщения от нашего бота напрямую в определенный чат или группу, нам необходимо получить идентификатор чата. Этого можно добиться, отправив сообщение нашему боту, а затем используя метод API Telegram getUpdates для извлечения идентификатора чата. Этот идентификатор нам понадобится, если мы хотим, чтобы наш бот отправлял сообщения не только своему владельцу. Если мы хотим, чтобы бот отправлял сообщения в группу или канал, мы можем сначала добавить бота в группу, а затем использовать те же методы для получения идентификатора чата. Чтобы получить идентификатор чата, мы используем следующий фрагмент кода. Просто скопируйте и замените токен бота на токен вашего бота и запустите его в своем браузере.
//CHAT ID = https://api.telegram.org/bot{BOT TOKEN}/getUpdates //https://api.telegram.org/bot7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc/getUpdates
Вот какие результаты мы получаем:
Как видим, наш результат не содержит никаких обновлений сообщений, даже если мы возвращаем значение true, что указывает на то, что все предоставленные данные верны. Если вы введете в ссылку что-то неправильное, вы получите неверный веб-запрос и получите ложный ответ, как показано ниже:
{"ok":false,"error_code":404,"description":"Not Found"}
В нашем случае мы возвращаем true, но наша структура все равно пуста. Это потому, что нам нужно отправить сообщение боту, чтобы произошло обновление. В нашем случае мы отправляем стартовую команду /start.
После отправки сообщения и повторного обновления ссылки мы получаем обновление. Здесь следует отметить, что сообщения хранятся на сервере Telegram только 24 часа, после чего удаляются. Поэтому, если вы получаете идентификатор чата этим методом, убедитесь, что сообщения были отправлены в течение 24 часов до процесса. Посмотрим на результат:
Мы получаем обновления, но выводимая структура довольно компактна и непривлекательна. Чтобы добиться более удобного для чтения формата, установите флажок Pretty-Print, и у вас должна получиться следующая структура.
{ "ok": true, "result": [ { "update_id": 794283176, "message": { "message_id": 1, "from": { "id": [YOUR ID], "is_bot": false, "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "language_code": "en" }, "chat": { "id": [YOUR ID], "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "type": "private" }, "date": 1722368989, "text": "/start", "entities": [ { "offset": 0, "length": 6, "type": "bot_command" } ] } } ] }
Наш идентификатор чата находится в столбце chat id. На этом этапе, вооружившись токеном бота и идентификатором чата, мы можем создать программу, которая будет отправлять сообщения из MQL5 в созданный нами Telegram-бот.
Настройка MetaTrader 5 для общения через Telegram
Чтобы гарантировать, что наша платформа MetaTrader 5 сможет взаимодействовать с Telegram, нам необходимо добавить URL-адрес API Telegram в список разрешенных URL-адресов в MetaTrader 5. Откройте MetaTrader 5, меню "Сервис". Выберите "Настройки" либо нажмите CTRL + O.
В окне "Настройки" откройте вкладку "Советники". Поставьте галочку в "Разрешить WebRequest для следующих URL" и добавьте URL "https://api.telegram.org" в список. Этот шаг имеет решающее значение, поскольку он предоставляет нашему советнику необходимые разрешения для отправки HTTP-запросов к API Telegram, что позволяет ему отправлять сообщения и обновления нашему Telegram-боту. Настраивая эти параметры, мы обеспечиваем бесперебойную и безопасную связь между нашей платформой MetaTrader 5 и Telegram, что позволяет эффективно контролировать и управлять нашей торговлей в реальном времени.
Теперь мы можем приступить к реализации на MQL5, где мы определим всю логику программы, передающей сообщения из MQL5 в Telegram.
Реализация средствами MQL5
Интеграция будет основана на советнике. В терминале MetaTrader 5 выберите "Сервис" > "Редактор MetaQuotes Language" или просто нажмите F4. Кроме того, вы можете щелкнуть иконку IDE (интегрированная среда разработки) на панели инструментов. Откроется среда разработки на MQL5, которая позволяет писать торговых роботов, технические индикаторы, скрипты и библиотеки функций.
На панели инструментов выберите "Файл" - "Новый файл" или нажмите CTRL + N, чтобы создать новый документ. Также вы можете нажать на иконку "Создать" в панели инструментов. Откроется окно Мастера MQL.
В открывшемся Мастере выберите Советник (шаблон) и нажмите "Далее".
В общих свойствах укажите имя файла вашего советника. Чтобы указать или создать папку, если она не существует, используйте обратную косую черту перед именем советника. По умолчанию указана папка Experts\. Это значит, что наш советник будет создан в папке Experts. Остальные разделы довольно просты, но вы можете перейти по ссылке в нижней части Мастера, чтобы узнать детали.
После указания имени файла советника нажмите "Далее" > "Далее" > "Готово". Теперь мы готовы приступить к написанию кода и созданию нашей программы.
Начнем с определения некоторых метаданных о советнике (EA). Сюда входит название советника, информация об авторских правах и ссылка на сайт MetaQuotes. Мы также указываем версию советника. Сейчас это 1.00.
//+------------------------------------------------------------------+ //| TG NOTIFICATIONS EA.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00"
При загрузке программы отображается следующая информация.
Далее мы определяем несколько констант, которые будут использоваться в нашем коде.
const string TG_API_URL = "https://api.telegram.org"; const string botTkn = "7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc"; const string chatID = "{YOUR CHAT ID}";
Здесь константа TG_API_URL содержит базовый URL для API Telegram, который необходим для отправки HTTP-запросов к серверам Telegram. Константа botTkn содержит уникальный токен для нашего Telegram-бота, предоставленный BotFather и необходимый для аутентификации. Константа chatID — это уникальный идентификатор чата Telegram, в который мы хотим отправлять сообщения. Здесь мы вводим свой идентификатор чата, полученный с помощью API Telegram-метода getUpdates. Обратите внимание, что мы использовали константные строковые переменные. Ключевое слово const гарантирует, что наши переменные останутся целыми и неизменными после определения. Таким образом, нам не придется переопределять их снова, и они сохранят свои инициализационные значения на протяжении всего кода. Таким образом, мы экономим время и место, поскольку нам не приходится вводить их заново каждый раз, когда нам нужны значения, мы просто вызываем необходимые переменные, и, опять же, вероятность неправильного ввода их значений значительно снижается.
Наш код будет в основном основан на разделе инициализации советника, поскольку мы хотим делать быстрые иллюстрации, не дожидаясь тиков на графике, чтобы генерировать сигналы. Таким образом, обработчик событий OnInit будет содержать большую часть структуры кода.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ ... return(INIT_SUCCEEDED); }
Функция OnInit представляет собой обработчик событий, который вызывается для экземпляра инициализации советника при выполнении необходимых инициализаций.
Для связи с сервером Telegram мы используем встроенную функцию MQL5 WebRequest. Она по сути представляет собой перегруженную функцию целочисленного типа и имеет две формы.
Для простоты мы будем использовать вторую версию. Давайте разберем функцию, чтобы понять, что означает каждый параметр.
int WebRequest( const string method, // HTTP method (e.g., "GET", "POST") const string url, // URL of the web server const string headers, // Optional HTTP headers int timeout, // Request timeout in milliseconds const char &data[], // Data to send with the request char &result[], // Buffer to store the response string &result_headers // Buffer to store the response headers );
Кратко поясним параметры функции WebRequest.
- method - HTTP-метод, используемый для запроса. Типовые методы включают GET и POST. GET обычно используется для извлечения данных с сервера. POST используется для отправки данных на сервер.
- url - URL-адрес веб-сервера, на который отправляется запрос. Он включает в себя протокол (http:// или https://), домен и путь/ресурс, к которому осуществляется доступ.
- headers - необязательные заголовки HTTP для включения в запрос. Заголовки могут предоставлять серверу дополнительную информацию (например, тип контента, токены аутентификации).
- timeout - максимальное время (в миллисекундах) ожидания ответа от сервера. Если сервер не отвечает в течение этого времени, запрос прерывается и возвращается код ошибки. Например, если мы установим тайм-аут в 10 000 миллисекунд, то получим 10 000/1000 = 10 секунд.
- data - данные для отправки вместе с запросом. Для запросов POST это обычно тело запроса (например, данные формы, полезная нагрузка JSON).
- result - буфер для хранения данных ответа от сервера. Массив будет заполнен ответом сервера, который мы затем сможем обработать в нашем коде.
- result_headers - буфер для хранения заголовков ответа от сервера. Эта строка будет заполнена заголовками, отправленными сервером в своем ответе.
Теперь, имея представление о том, для чего используются параметры и зачем они нам нужны, давайте продолжим определять некоторые наиболее необходимые переменные, которые мы будем использовать.
char data[]; char res[]; string resHeaders; string msg = "EA INITIALIZED ON CHART "+_Symbol; //https://api.telegram.org/bot{HTTP_API_TOKEN}/sendmessage?chat_id={CHAT_ID}&text={MESSAGE_TEXT} const string url = TG_API_URL+"/bot"+botTkn+"/sendmessage?chat_id="+chatID+ "&text="+msg;
Сначала мы объявляем массивы data и res типа char. Эти массивы будет использоваться в функции WebRequest для хранения данных, отправленных на веб-сервер и полученных с него. Массив data предназначен для любой полезной нагрузки, которую мы захотим отправить с нашим HTTP-запросом, хотя на данный момент мы оставим его пустым. Массив res будет заполнен ответом сервера, что позволит нам обработать и использовать ответ в нашей программе.
Далее мы определяем переменную string с именем resHeaders для хранения заголовков HTTP-ответа, который мы получаем от сервера. Заголовки HTTP-ответа содержат важные метаданные об ответе, такие как тип контента, информация о сервере и коды состояния. Собирая эти заголовки, мы можем получить больше информации об ответе и обработать его соответствующим образом с помощью нашего советника.
Затем мы создаем строковую переменную msg, содержащую сообщение, которое мы хотим отправить в Telegram. В этом случае выводится сообщение EA INITIALIZED ON CHART (советник инициализирован на графике), за которым следует символ текущего графика, представленный встроенной переменной _Symbol. Переменная _Symbol содержит имя символа финансового инструмента, для которого запущен советник, например AUDUSD или GBPUSD. Включая эту информацию в наше сообщение, мы предоставляем четкий и конкретный контекст произошедшего действия или события, что может быть особенно полезно для мониторинга и журналирования. Это произвольное значение, которое мы хотим отобразить при инициализации программы, поэтому вы можете указать свое собственное.
Затем мы создаем (URL), необходимый для выполнения запроса к API Telegram. Начнем с базового URL-адреса, хранящегося в константе TG_API_URL, то есть https://api.telegram.org. Затем мы добавляем путь к методу API sendMessage, включая токен нашего бота (botTkn). Этот токен уникально идентифицирует и аутентифицирует нашего бота на серверах Telegram, гарантируя, что запрос является действительным и авторизованным. Путь URL выглядит следующим образом: "/bot<botTkn>/sendmessage". Вместо <botTkn> подставляется токен бота.
Далее мы добавляем параметры запроса к URL. Первый параметр — chat_id, который указывает уникальный идентификатор чата Telegram, куда мы хотим отправить наше сообщение. Он хранится в константе chatID. Вторым параметром является текст, содержащий фактическое сообщение, которое мы хотим отправить, хранящееся в переменной msg. Эти параметры объединяются с базовым URL-адресом для формирования полного URL-адреса запроса. Окончательный URL выглядит так: "https://api.telegram.org/bot<botTkn>/sendmessage?chat_id=<chatID>&text=<msg>", где вместо <botTkn>, <chatID> и <msg> указываются соответствующие значения.
Наконец, мы вызываем функцию для осуществления связи путем передачи необходимых аргументов.
int send_res = WebRequest("POST",url,"",10000,data,res,resHeaders);
Здесь мы используем функцию WebRequest для отправки HTTP-запроса POST на указанный URL. Нам необходимо использовать эту функцию для взаимодействия с внешним веб-сервисом, например API Telegram. Нам необходимо указать метод HTTP. В данном случае это POST. Мы используем этот метод при отправке данных на сервер, который выполняет какое-либо действие. Необходимое для нас действие — отправка сообщения в чат Telegram. Мы предоставляем переменную url, которую мы создали ранее в коде. Используемый нами URL-адрес содержит базовый адрес API Telegram, наш уникальный токен бота, метод API sendMessage, идентификатор чата, в который мы хотим отправить сообщение, и текст самого сообщения.
Затем мы указываем, что параметр headers представляет собой пустую строку, что означает, что для этого запроса не нужны дополнительные заголовки HTTP. Таймаут устанавливается на 10 секунд, что обычно составляет 10*1000 = 10 000 миллисекунд. Это довольно большое значение, учитывая, что сейчас серверы обычно должны отвечать в течение нескольких секунд. Этот таймаут предотвращает бесконечное зависание запроса и позволяет советнику сохранять отзывчивость. Далее мы передаем массив данных и массив ответа в функцию. Массив данных содержит любую дополнительную информацию, которую мы хотим отправить с запросом, а массив ответов мы используем для хранения результата запроса. Наконец, мы передаем строку заголовка ответа, которую функция также использует для "хранения" заголовка ответа, отправленного сервером.
Функция возвращает целочисленный код состояния, хранящийся в переменной send_res, который указывает, был ли запрос успешным или произошла ошибка. Используя результаты, мы можем проверить, было ли сообщение успешно отправлено, и если нет, сообщить о возникшей ошибке.
После выполнения HTTP-запроса мы можем обработать ответ, проверив код состояния, сохраненный в переменной send_res. Для этого мы можем использовать условные операторы, чтобы определить результат нашего запроса и предпринять соответствующие действия на основе возвращенного кода состояния.
if (send_res == 200){ Print("TELEGRAM MESSAGE SENT SUCCESSFULLY"); }
Здесь, если наша переменная содержит код состояния 200, то запрос был успешным. Это значит, что наше сообщение попало в указанный чат Telegram. Итак, в этом случае мы выводим на терминал что-то вроде "TELEGRAM MESSAGE SENT SUCCESSFULLY" (сообщение в Telegram успешно отправлено).
else if (send_res == -1){ if (GetLastError()==4014){ Print("PLEASE ADD THE ",TG_API_URL," TO THE TERMINAL"); } Print("UNABLE TO SEND THE TELEGRAM MESSAGE"); }
Если результат не равен 200, мы проверяем, равен ли он -1. Этот статус говорит нам, что с HTTP-запросом что-то пошло не так. Мы не можем просто оставить конечного пользователя на этом экране с ошибкой. Мы можем сделать наши сообщения об ошибках немного более подробными.
Сначала мы проверяем конкретную ошибку (сообщение), полученную при сбое вызова функции. Используем функцию GetLastError для извлечения кода ошибки, сообщающего нам, что пошло не так. Затем мы интерпретируем вероятный сценарий (что означает код ошибки) и выводим сообщение пользователю, которое поможет ему устранить проблему, вызвавшую ошибку. В этом случае, если код ошибки равен 4014, мы понимаем, что URL-адрес не указан и не включен на терминале. Поэтому мы информируем пользователя о необходимости добавить и включить правильный URL-адрес в своем торговом терминале.
Если проблема не связана с ограничением URL (GetLastError не выдает 4014), мы не останавливаемся. Мы выводим сообщению (пользователю!), в котором четко излагается суть ошибки: "UNABLE TO SEND THE TELEGRAM MESSAGE" (не удалось отправить сообщение в Telegram). Мы даже улавливаем случайные "аномальные" условия ответа.
else if (send_res != 200){ Print("UNEXPECTED RESPONSE ",send_res," ERR CODE = ",GetLastError()); }
Если send_res не равен 200 и не равен -1 (что указывает на очевидную проблему, связанную с ограничением URL), то нам предстоит поломать голову. Если все прошло хорошо, мы возвращаем полученное целочисленное значение.
return(INIT_SUCCEEDED);
Давайте проверим и посмотрим, все ли получится.
В чате Telegram-бота мы получаем следующее:
В торговом терминале мы получаем следующее:
Нам удалось отправить сообщение с торгового терминала на сервер Telegram, который ретранслировал его в чат Telegram, что означает, что все прошло успешно.
Полный исходный код, отвечающий за отправку сообщения из торгового терминала в чат Telegram через бота, выглядит следующим образом:
//+------------------------------------------------------------------+ //| TG NOTIFICATIONS EA.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" // Define constants for Telegram API URL, bot token, and chat ID const string TG_API_URL = "https://api.telegram.org"; // Base URL for Telegram API const string botTkn = "7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc"; // Telegram bot token const string chatID = "{YOUR CHAT ID}"; // Chat ID for the Telegram chat // The following URL can be used to get updates from the bot and retrieve the chat ID // CHAT ID = https://api.telegram.org/bot{BOT TOKEN}/getUpdates // https://api.telegram.org/bot7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc/getUpdates //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { char data[]; // Array to hold data to be sent in the web request (empty in this case) char res[]; // Array to hold the response data from the web request string resHeaders; // String to hold the response headers from the web request string msg = "EA INITIALIZED ON CHART " + _Symbol; // Message to send, including the chart symbol // Construct the URL for the Telegram API request to send a message // Format: https://api.telegram.org/bot{HTTP_API_TOKEN}/sendmessage?chat_id={CHAT_ID}&text={MESSAGE_TEXT} const string url = TG_API_URL + "/bot" + botTkn + "/sendmessage?chat_id=" + chatID + "&text=" + msg; // Send the web request to the Telegram API int send_res = WebRequest("POST", url, "", 10000, data, res, resHeaders); // Check the response status of the web request if (send_res == 200) { // If the response status is 200 (OK), print a success message Print("TELEGRAM MESSAGE SENT SUCCESSFULLY"); } else if (send_res == -1) { // If the response status is -1 (error), check the specific error code if (GetLastError() == 4014) { // If the error code is 4014, it means the Telegram API URL is not allowed in the terminal Print("PLEASE ADD THE ", TG_API_URL, " TO THE TERMINAL"); } // Print a general error message if the request fails Print("UNABLE TO SEND THE TELEGRAM MESSAGE"); } else if (send_res != 200) { // If the response status is not 200 or -1, print the unexpected response code and error code Print("UNEXPECTED RESPONSE ", send_res, " ERR CODE = ", GetLastError()); } return(INIT_SUCCEEDED); // Return initialization success status } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Code to execute when the expert is deinitialized } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Code to execute on every tick event } //+------------------------------------------------------------------+
В следующем подразделе изменим код для нескольких различных форматов сообщений, чтобы мы могли увидеть объем отправляемых сообщений, ошибки, которые могут быть допущены, и посмотреть, как их можно преодолеть.
Тестирование интеграции
Чтобы убедиться, что наш советник правильно отправляет сообщения в Telegram, нам необходимо тщательно протестировать интеграцию. Одним из важнейших аспектов тестирования является проверка поведения советника при неверных настройках, например, когда в торговом терминале отключен флажок "Разрешить WebRequest для следующих URL". Чтобы убедиться, что мы все сделали правильно, давайте отключим флажок.
Если запустить программу, то получим сообщение об ошибке, сообщающее пользователю, что связь может быть установлена только в том случае, если предоставленная ссылка включена и разрешена в торговом терминале.
Мы не только информируем об ошибке, но и предлагаем пользователю эффективное решение.
Теперь, когда мы можем выявить и устранить ошибки, давайте приступим к созданию более креативных, понятных и интересных форматов сообщений. Для начала давайте в наше первоначальное сообщение эмодзи.
//--- Simple Notification with Emoji: string msg = "🚀 EA INITIALIZED ON CHART " + _Symbol + " 🚀";
Здесь мы просто добавляем два эмодзи ракеты к исходному сообщению. Вот что мы получаем после компиляции:
Простое сообщение с эмодзи было успешно отправлено. Чтобы получить символы эмодзи, просто нажмите одновременно клавиши Windows + точка. Теперь мы можем продолжать и изменять наши уведомления, чтобы включать торговые сигналы, такие как BUY (покупка) или SELL (продажа), информацию о балансе счета, открытии сделок, изменении торговых уровней, такие как стоп-лосс и тейк-профит, ежедневную сводку по результатам и информацию об обновлении статуса счета. Это всего лишь произвольные сообщения, которые можно изменять в соответствии со своим стилем торговли. Введем их с помощью следующего кода.
//--- Simple Notification with Emoji: string msg = "🚀 EA INITIALIZED ON CHART " + _Symbol + " 🚀"; //--- Buy/Sell Signal with Emoji: string msg = "📈 BUY SIGNAL GENERATED ON " + _Symbol + " 📈"; string msg = "📉 SELL SIGNAL GENERATED ON " + _Symbol + " 📉"; //--- Account Balance Notification: double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE); string msg = "💰 Account Balance: $" + DoubleToString(accountBalance, 2) + " 💰"; //--- Trade Opened Notification: string orderType = "BUY"; // or "SELL" double lotSize = 0.1; // Example lot size double price = 1.12345; // Example price string msg = "🔔 " + orderType + " order opened on " + _Symbol + "; Lot size: " + DoubleToString(lotSize, 2) + "; Price: " + DoubleToString(price, 5) + " 🔔"; //--- Stop Loss and Take Profit Update: double stopLoss = 1.12000; // Example stop loss double takeProfit = 1.13000; // Example take profit string msg = "🔄 Stop Loss and Take Profit Updated on " + _Symbol + "; Stop Loss: " + DoubleToString(stopLoss, 5) + "; Take Profit: " + DoubleToString(takeProfit, 5) + " 🔄"; //--- Daily Performance Summary: double profitToday = 150.00; // Example profit for the day string msg = "📅 Daily Performance Summary 📅; Symbol: " + _Symbol + "; Profit Today: $" + DoubleToString(profitToday, 2); //--- Trade Closed Notification: string orderType = "BUY"; // or "SELL" double profit = 50.00; // Example profit string msg = "❌ " + orderType + " trade closed on " + _Symbol + "; Profit: $" + DoubleToString(profit, 2) + " ❌"; //--- Account Status Update: double accountEquity = AccountInfoDouble(ACCOUNT_EQUITY); double accountFreeMargin = AccountInfoDouble(ACCOUNT_FREEMARGIN); string msg = "📊 Account Status 📊; Equity: $" + DoubleToString(accountEquity, 2) + "; Free Margin: $" + DoubleToString(accountFreeMargin, 2);
При запуске этого фрагмента кода с форматами сообщений по отдельности мы получаем следующую сумму результатов:
Из приведенного выше фрагмента кода и изображения видно, что интеграция прошла успешно. Таким образом, мы достигли поставленной цели — отправки сообщений с торговых терминалов в чат телеграм-бота. Если вы хотите отправлять сообщения в канал или группу Telegram, вам просто нужно добавить бота в группу или канал и сделать его администратором. Например, мы создали группу, назвали ее Forex Algo Trader Group и снабдили логотипом. После этого мы сделали бота администратором.
Однако даже если вы повысите уровень бота до администратора, вам все равно придется получить идентификатор чата для конкретной группы. При использовании идентификатора чата самого бота, сообщения всегда будут пересылаться на него, а не в нужную группу. Таким образом, процесс получения идентификатора группы аналогичен описанному выше.
// The following URL can be used to get updates from the bot and retrieve the chat ID // CHAT ID = https://api.telegram.org/bot{BOT TOKEN}/getUpdates https://api.telegram.org/bot7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc/getUpdates
Нам просто нужно отправить сообщение группе и запустить код в браузере. Сообщение, которое мы отправили:
В браузере мы получаем следующую информацию в структурированном формате:
{ "ok": true, "result": [ { "update_id": 794283177, "my_chat_member": { "chat": { "id": -4273023945, "title": "Forex Algo Trader Group", "type": "group", "all_members_are_administrators": true }, "from": { "id": <YOUR ID>, "is_bot": false, "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "language_code": "en" }, "date": 1722593740, "old_chat_member": { "user": { "id": <YOUR ID> , "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "status": "left" }, "new_chat_member": { "user": { "id": <YOUR ID>, "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "status": "member" } } }, { "update_id": 794283178, "message": { "message_id": 64, "from": { "id": <FROM ID> , "is_bot": false, "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "language_code": "en" }, "chat": { "id": -4273023945, "title": "Forex Algo Trader Group", "type": "group", "all_members_are_administrators": true }, "date": 1722593740, "new_chat_participant": { "id": <NEW ID> , "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "new_chat_member": { "id": <NEW ID>, "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "new_chat_members": [ { "id": <NEW ID> , "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" } ] } }, { "update_id": 794283179, "my_chat_member": { "chat": { "id": -4273023945, "title": "Forex Algo Trader Group", "type": "group", "all_members_are_administrators": true }, "from": { "id": <FROM ID>, "is_bot": false, "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "language_code": "en" }, "date": 1722593975, "old_chat_member": { "user": { "id": <USER ID>, "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "status": "member" }, "new_chat_member": { "user": { "id": <USER ID>, "is_bot": true, "first_name": "mql5tg_allan_bot", "username": "mql5_tg_allan_bot" }, "status": "administrator", "can_be_edited": false, "can_manage_chat": true, "can_change_info": true, "can_delete_messages": true, "can_invite_users": true, "can_restrict_members": true, "can_pin_messages": true, "can_promote_members": false, "can_manage_video_chats": true, "can_post_stories": false, "can_edit_stories": false, "can_delete_stories": false, "is_anonymous": false, "can_manage_voice_chats": true } } }, { "update_id": 794283180, "message": { "message_id": 65, "from": { "id": <YOUR FROM ID>, "is_bot": false, "first_name": "Forex Algo-Trader", "username": "Forex_Algo_Trader", "language_code": "en" }, "chat": { "id": -4273023945, "title": "Forex Algo Trader Group", "type": "group", "all_members_are_administrators": true }, "date": 1722594029, "text": "MESSAGE TO GET THE CHAT ID" } } ] }
Здесь наш идентификатор чата имеет знак минус перед числом. Это идентификатор, который мы извлекаем и заменяем на исходный. Теперь наш идентификатор чата будет таким:
// Define constants for Telegram API URL, bot token, and chat ID const string TG_API_URL = "https://api.telegram.org"; // Base URL for Telegram API const string botTkn = "7456439661:AAELUurPxI1jloZZl3Rt-zWHRDEvBk2venc"; // Telegram bot token const string chatID = "-4273023945"; // Chat ID for the Telegram chat
При запуске мы получаем следующий результат.
Как видим, нам удалось создать программу на языке MQL5, которая корректно отправляет сообщения из торгового терминала в поле чата Telegram-бота со всей необходимой информацией. Однако сложные сообщения, содержащие символы переноса строки \n или наборы символов стандарта Unicode, такие как коды эмодзи U+1F600, так отправить не удастся. Мы рассмотрим их в следующих частях. А пока давайте сделаем всё просто и прямолинейно.
Заключение
В этой статье мы создали советника, работающего с MQL5 и Telegram. Это позволяет осуществлять связь между терминалом и Telegram-ботом, то есть вы можете отправлять сообщения с терминала боту и с бота на терминал. Это очень круто по двум причинам: во-первых, потому что бот по сути является прокси-сервером между вами и терминалом для отправки и получения сообщений; во-вторых, потому что по какой-то причине этот торговый функционал кажется намного круче, чем отправка сообщения по электронной почте.
Мы также изучили процесс тестирования, выявив возможные ошибки, которые могут возникнуть, если параметры WebRequest установлены неправильно. Мы выяснили причины этих ошибок, а затем исправили их, благодаря чему программа теперь работает с большей надежностью. Она работает плавно и без ошибок, отправляя сообщения с правильной информацией в нужное место в нужное время. Понимание того, "почему" и "как" происходит ошибка, позволяет нам действовать увереннее.
В последующих частях этой серии мы выведем нашу интеграцию на более высокий уровень, создав пользовательский индикатор, генерирующий торговые сигналы. Эти сигналы будут использоваться для отправки сообщений в наш групповой чат в Telegram, предоставляя нам в реальном времени потенциальные торговые возможности. Речь идет не только о том, чтобы улучшить работу нашей торговой стратегии. Речь также идет о демонстрации того, как мы можем объединить MQL5 с Telegram для создания динамического торгового процесса и отправки оповещений. В следующей статье мы продолжаем разрабатывать и совершенствовать интегрированную систему.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/15457





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Ни в коем случае не подвергаю сомнению ваше утверждение,
но позвольте попросить вас привести пример тех данных,
которые есть в "окне данных", но к которым нет доступа из индикатора или советника.
данные буферов индикатора запущенного пользователем.
данные буферов индикатора запущенного пользователем.
Вы пробовали этот пример? https://www.mql5.com/ru/docs/chart_operations/chartindicatorname
данные буферов индикатора запущенного пользователем.
Я подозреваю, что здесь есть какой то подвох, но всё же спрошу.
А что вас не устраивает в запуске хэндла индикатора iCustom() и получения данных из него с помощью CopyBuffer() ?
Что плохого в том, чтобы запустить ручку индикатора iCustom() и получить из нее данные с помощью CopyBuffer()?
Полагаю, необходимость писать код.
Полагаю, необходимость писать код.
Ну думаю не стоит делать поспешных выводов, возможно есть ситуации о которых мы не догадываемся, поэтому я спросил.
Сам же я вижу два решения:
1. То, что написал Рашид, получить имя индикатора и по нему получить хэндл.
2. То что написал я, запустить индикатор виртуально, получить хэндл.
На мой взгляд эти два варианта покрывают практически все возможные ситуации. Но, возможно я ошибаюсь.
ЗЫ. Забавный переводчик)))