
Создание торговой панели администратора на MQL5 (Часть II): Повышение оперативности реагирования и быстрого обмена сообщениями
Содержание:
Введение:
Представьте, что вы пропустили важный рыночный сигнал из–за задержки сообщения - распространенное препятствие, которое лишает трейдеров ценных возможностей и прибыли в быстро меняющейся торговой среде. В этом контексте информация администратора так же важна, как и сами рыночные сигналы. Хотя алгоритмические системы быстры и обладают эмоциональным интеллектом, они не могут заменить тщательный надзор опытных трейдеров, которые постоянно следят за работой системы и принимают критически важные решения.
Сравнение сообщения, вводимого посредством нажатия кнопки и сообщения, вводимого с клавиатуры.
На изображении выше видна проблема: при попытке перетащить панель график перемещается, а кнопка сворачивания не реагирует
Поскольку алгоритмическая торговля доминирует на финансовых рынках, эффективная коммуникация между пользователями торговых систем (трейдерами) и администраторами (людьми, стоящими за торговой системой) стала насущной необходимостью. Ранее мы создавали интерфейсы обмена сообщениями на панели администратора, которые имели ограниченную скорость реагирования, необходимого для выполнения задач в реальном времени, таких как быстрое отправление сообщений, а также нажатие и перетаскивание самой панели, что создавало серьезные проблемы для администраторов, которым необходимо быстро реагировать.
Панель администратора: улучшения, направленные на работу с предыдущей панелью администратора
Цель данной статьи - преодолеть эти коммуникационные барьеры путем внедрения возможности быстрого реагирования в интерфейсе обмена сообщениями администратора с использованием MQL5. Кроме того, она подчеркивает важность быстрого обмена сообщениями для поддержки гибких торговых решений и операционной эффективности.
В настоящем обсуждении мы рассмотрим, как можно использовать MQL5 для повышения оперативности реагирования на сообщения в рамках торговых платформ. Мы проведем вас по ключевым этапам реализации, помогая вам построить более глубокое понимание возможностей, предоставляемых программированием на MQL5. Вместе мы создадим более эффективный интерфейс обмена сообщениями, соответствующий требованиям современной торговли.Чтобы отследить это обсуждение от начала до конца, я рассмотрю следующие вопросы:
- Что такое реагирование в графическом интерфейсе пользователя (GUI)?
- Что такое быстрые сообщения?
Реагирование:
В MQL5 быстродействие графического интерфейса пользователя (GUI) означает, насколько быстро и плавно интерфейс реагирует на действия пользователя, такие как нажатие кнопок, перемещение ползунков или изменение размера панелей. Адаптивный графический интерфейс GUI обеспечивает мгновенную обратную связь с пользователем, делая интерфейс интуитивно понятным и простым в использовании. Это особенно важно в торговых приложениях, где своевременные действия могут иметь решающее значение.
Достижение быстродействия часто требует оптимизации кода для сокращения времени выполнения функций, связанных с GUI, минимизации количества объектов, отображаемых на диаграмме, и использования асинхронной обработки, когда это возможно. Это гарантирует, что основной поток по-прежнему реагирует на вводимые пользователем данные, обеспечивая беспрерывный опыт пользователей во время критически важных торговых операций.
Позвольте мне подробно описать ключевые аспекты реагирования в графическом интерфейсе пользователя на MQL5:
- Немедленная обратная связь: Интерфейс должен мгновенно реагировать на такие действия пользователя, как нажатие кнопок или ввод текста. Между действием пользователя и реагированием системы не должно быть заметной задержки.
- Плавное исполнение: Даже при наличии множества элементов GUI и сложной логики интерфейс должен работать плавно, без задержек и зависаний. Сюда относятся эффективные методы кодирования, позволяющие минимизировать нагрузку на центральный процессор и обеспечить быстрое выполнение пользовательских команд.
- Динамическое обновление: Графический интерфейс должен иметь возможность динамически обновлять элементы, не требуя полной перерисовки всего интерфейса. Например, при достижении нового уровня цен соответствующие элементы (например, метки, строки) должны обновляться плавно, без мерцания.
- Масштабируемость: Интерфейс должен хорошо справляться с изменениями размера или разрешения. Например, если пользователь изменяет размер панели, содержимое должно автоматически изменяться, а возможность дальнейшего использования - поддерживаться.
- Обработка ошибок: Графический интерфейс GUI должен корректно справляться с ошибками, обеспечивая четкую и немедленную обратную связь с пользователем, если что-то пойдет не так, без сбоев или прекращения реагирования.
Быстрые сообщения:
Относятся к шаблонным, часто используемым сообщениям, которые можно отправить всего одним щелчком мыши или минимальным взаимодействием. Эти сообщения, как правило, конфигурируются заранее для удовлетворения частых потребностей в общении, что позволяет пользователям быстро отвечать или отправлять стандартные сообщения без необходимости ввода текста вручную.
Случаи использования быстрых сообщений
- Стандартные ответы: Быстрые сообщения могут использоваться для стандартных ответов или команд, таких как подтверждение торгового сигнала, подтверждение действия или уведомление команды о конкретном событии.
- Уведомления об ошибках: Если при торговле возникает ошибка, может быть немедленно отправлено краткое сообщение типа "Invalid signal" ("Неверный сигнал») или "Error detected" ("Обнаружена ошибка»).
- Программные команды: Быстрые сообщения могут содержать программные команды или инструкции, которые часто используются в торговых операциях, например "Close all positions" ("Закрыть все позиции") или "Activate EA" ("Активировать советник").
Пример:
Предположим, у вас есть панель администратора на MQL5 с несколькими быстрыми сообщениями для автоматической торговой системы. К ним могут относиться:
- Начать мониторинг (Start monitoring): Краткое сообщение о начале мониторинга рыночной конъюнктуры.
- Остановить мониторинг (Stop monitoring): Краткое сообщение об остановке мониторинга.
- Неверный сигнал (Invalid signal): Сообщение, уведомляющее пользователя о том, что обнаружен недопустимый торговый сигнал.
Каждый из них может быть привязан к кнопке на панели. При нажатии на кнопку мгновенно отправляется шаблонное сообщение, что экономит время и обеспечивает постоянную связь.
Реализация средствами MQL5
В MQL5 быстрые сообщения могут быть реализованы на панели обмена сообщениями путем создания кнопок или выпадающих меню, привязанных к определенным заранее написанным текстовым строкам. Когда пользователь нажимает на одну из этих кнопок, соответствующее сообщение автоматически отправляется по нужному каналу связи, такому как Telegram, электронная почта или другой API обмена сообщениями. Некоторые очевидные недостатки, заметные на анимированном изображении во введении, показывающем нашу панель, охватывающие некоторую часть графика, могут раздражать, когда мы хотим получить большую по размеру картину для анализа графика. Для покорения данного сегмента я разделю его на две части:
- Логичное расположение кнопок управления панелью.
- Кодирование кнопок быстрого обмена сообщениями с помощью функции повтора.
Полагаю, вы прочитали Часть I и получили представление о том, откуда мы пришли и куда направляемся.
1. Логичное расположение кнопок управления панелью
Кнопки свёртывания, развёртывания и закрытия
- Наименование кнопок:
Прежде чем идти дальше, здесь мы покажем, как назовем кнопки:
///Global variables
CButton minimizeButton;
CButton maximizeButton;
CButton closeButton;
- Кнопка свёртывания:
Что касается кнопки свёртывания, мы создали ее, используя класс CButton, расположив ее на (375, -22) на графике с размером (30, 22) пикселей. На кнопке отображается символ подчеркивания _, распространенный символ для сворачивания окон. Мы добавили её на админ-панель с помощью функции "adminPanel. Add(minimizeButton)". Назначение этой кнопки - дать возможность пользователям временно скрыть панель администратора из поля зрения, не закрывая ее полностью. В функции "OnMinimizeButtonClick()" мы запрограммировали кнопку так, чтобы она скрывала панель администратора и отображала только кнопки "свернуть", "развернуть" и "закрыть". Она имитирует свёртывание окна, сохраняя при этом доступ к основным элементам управления.
// Create the minimize button if (!minimizeButton.Create(chart_id, "MinimizeButton", 0, 375, -22, 405, 0)) { Print("Failed to create minimize button"); return INIT_FAILED; } minimizeButton.Text("_"); adminPanel.Add(minimizeButton); // Function to handle minimize button click void OnMinimizeButtonClick() { minimized = true; // Hide the full admin panel adminPanel.Hide(); minimizeButton.Show(); maximizeButton.Show(); closeButton.Show(); }
- Кнопка развёртывания:
Для кнопки развертывания мы использовали тот же класс "CButton" и расположили ее рядом с кнопкой "свернуть" на (405, -22). На кнопке отображается символ [ ], обычный символ для развертывания или восстановления окон. Мы добавили его на панель администратора с помощью функции "adminPanel. Add(maximizeButton)". Данная кнопка позволяет пользователям восстановить панель администратора в ее полном размере после того, как она была свернута. В функции "OnMaximizeButtonClick()" нажатие этой кнопки восстанавливает первоначальный размер панели администратора и скрывает кнопки "свернуть", "развернуть" и "закрыть". Это имитирует процесс развёртывания свернутого окна.
// Create the maximize button if (!maximizeButton.Create(chart_id, "MaximizeButton", 0, 405, -22, 435, 0)) { Print("Failed to create maximize button"); return INIT_FAILED; } maximizeButton.Text("[ ]"); adminPanel.Add(maximizeButton); // Function to handle maximize button click void OnMaximizeButtonClick() { if (minimized) { minimizeButton.Hide(); maximizeButton.Hide(); closeButton.Hide(); adminPanel.Show(); } }
- Кнопка закрытия:
Что касается кнопки закрытия, мы создали ее таким же образом, как и две другие кнопки, расположив ее на (435, -22) и изобразив её как X - универсальный символ для закрытия окон. Мы добавили данную кнопку на панель администратора с помощью функции adminPanelAdd(closeButton)". Данная кнопка позволяет пользователям полностью удалить советник (EA) с графика, вызвав ExpertRemove()" в функции "OnCloseButtonClick()". Она обеспечивает простой способ закрыть панель администратора и остановить работу советника, когда пользователь закончит пользоваться панелью.
// Create the close button if (!closeButton.Create(chart_id, "CloseButton", 0, 435, -22, 465, 0)) { Print("Failed to create close button"); return INIT_FAILED; } closeButton.Text("X"); adminPanel.Add(closeButton); // Function to handle close button click void OnCloseButtonClick() { ExpertRemove(); // Completely remove the EA Print("Admin Panel closed."); }2. Кодирование наших кнопок быстрого обмена сообщениями с помощью функции loop (repeat) (цикл (повтор)
Интерфейс с множеством кнопок быстрого обмена сообщениями
Вводные данные для быстрых сообщений:
- Мы использовали несколько входных переменных (от Quick Message1 до QuickMessage8), чтобы сделать сообщения настраиваемыми. Эти входные данные позволяют пользователям изменять текст каждого быстрого сообщения непосредственно из настроек советника, не изменяя основной код. Такая гибкость позволяет легко адаптировать сообщения к различным сценариям торговли или предпочтениям пользователей. Кроме того, расположение кнопок является динамическим, что означает, что вы можете регулировать количество кнопок, их размер или положение, изменяя параметры цикла или массив "quickMessages". Такая структура гарантирует, что панель администратора может быть легко адаптирована к различным потребностям, обеспечивая надежный и удобный интерфейс.
//+------------------------------------------------------------------+ //| Inputs | //+------------------------------------------------------------------+ input string QuickMessage1 = "Updates"; input string QuickMessage2 = "Close all"; input string QuickMessage3 = "In deep profits"; input string QuickMessage4 = "Hold position"; input string QuickMessage5 = "Swing Entry"; input string QuickMessage6 = "Scalp Entry"; input string QuickMessage7 = "Book profit"; input string QuickMessage8 = "Invalid Signal"; input string InputChatId = "Enter Chat ID from Telegram bot API"; // User's Telegram chat ID input string InputBotToken = "Enter BOT TOKEN from your Telegram bot"; // User's Telegram bot token
Реализация цикла:
- Мы создали несколько кнопок быстрого обмена сообщениями, создав массив объектов (CButton) quickMessageButtons[8]) и инициализировав их в цикле. Цикл повторяется по массиву (quickMessages), который содержит шаблонные сообщения. Каждая итерация создает кнопку, присваивает ей метку из функции (quickMessages) и динамически размещает кнопки на основе их индекса. Суть функции повтора каптируется в структуре цикла, который повторяет процесс создания и настройки каждой кнопки, обеспечивая согласованность и эффективность. В MQL5 данный подход сводит к минимуму избыточность за счет использования цикла для выполнения повторяющихся задач, таких как создание нескольких кнопок со схожими характеристиками, что упрощает код и снижает вероятность ошибок.
// Array of predefined quick messages string quickMessages[8] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 }; // Coordinates and dimensions for the buttons int startX = 5, startY = 160, width = 222, height = 65, spacing = 5; // Loop to create and configure quick message buttons for (int i = 0; i < 8; i++) { if (!quickMessageButtons[i].Create(chart_id, "QuickMessageButton" + IntegerToString(i + 1), 0, startX + (i % 2) * (width + spacing), startY + (i / 2) * (height + spacing), startX + (i % 2) * (width + spacing) + width, startY + (i / 2) * (height + spacing) + height)) { Print("Failed to create quick message button ", i + 1); return INIT_FAILED; } quickMessageButtons[i].Text(quickMessages[i]); adminPanel.Add(quickMessageButtons[i]); }
Управление длиной сообщения:
- Реализация функции "Длина символа" включает счетчик символов, который отслеживает количество символов, введенных в поле ввода, и обновляет метку, чтобы отображать текущую длину наряду с максимально допустимой длиной сообщения. Функция (OnInputChange) срабатывает всякий раз при изменении входного текста, извлекая текст, вычисляя его длину с помощью (StringLen), а затем обновляя (charCounter) метку с форматом "current_length/MAX_MESSAGE_LENGTH". Это гарантирует, что пользователи будут знать, сколько символов у них осталось при составлении сообщения, что исключит превышение допустимого лимита. Опционально я использовал 600 символов в качестве максимальной длины.
// Maximum number of characters allowed in a message int MAX_MESSAGE_LENGTH = 600; // Function to update the character counter void OnInputChange() { string text = inputBox.Text(); int currentLength = StringLen(text); charCounter.Text(IntegerToString(currentLength) + "/" + IntegerToString(MAX_MESSAGE_LENGTH)); }
С нашей полностью интегрированной программой можно ознакомиться здесь:
//+------------------------------------------------------------------+ //| Admin Panel.mq5 | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com/en/users/billionaire2024/seller | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property description "A responsive Admin Panel. Send messages to your telegram clients without leaving MT5" #property version "1.09" #include <Trade\Trade.mqh> #include <Controls\Dialog.mqh> #include <Controls\Button.mqh> #include <Controls\Edit.mqh> #include <Controls\Label.mqh> // Use CLabel for displaying text //+------------------------------------------------------------------+ //| Inputs | //+------------------------------------------------------------------+ input string QuickMessage1 = "Updates"; input string QuickMessage2 = "Close all"; input string QuickMessage3 = "In deep profits"; input string QuickMessage4 = "Hold position"; input string QuickMessage5 = "Swing Entry"; input string QuickMessage6 = "Scalp Entry"; input string QuickMessage7 = "Book profit"; input string QuickMessage8 = "Invalid Signal"; input string InputChatId = "Enter Chat ID from Telegram bot API"; // User's Telegram chat ID input string InputBotToken = "Enter BOT TOKEN from your Telegram bot"; // User's Telegram bot token //+------------------------------------------------------------------+ //| Global variables | //+------------------------------------------------------------------+ CDialog adminPanel; CButton sendButton; CButton clearButton; CButton minimizeButton; CButton maximizeButton; CButton closeButton; CButton quickMessageButtons[8]; CEdit inputBox; CLabel charCounter; // Use CLabel for the character counter bool minimized = false; int MAX_MESSAGE_LENGTH = 600; // Maximum number of characters //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { long chart_id = ChartID(); // Create the dialog if (!adminPanel.Create(chart_id, "Admin Panel", 0, 30, 30, 500, 500)) { Print("Failed to create dialog"); return INIT_FAILED; } // Create the input box if (!inputBox.Create(chart_id, "InputBox", 0, 5, 5, 460, 75)) { Print("Failed to create input box"); return INIT_FAILED; } adminPanel.Add(inputBox); // Create the clear button for the input box if (!clearButton.Create(chart_id, "ClearButton", 0, 180, 75, 270, 105)) { Print("Failed to create clear button"); return INIT_FAILED; } clearButton.Text("Clear"); adminPanel.Add(clearButton); // Create the send button for custom messages if (!sendButton.Create(chart_id, "SendButton", 0, 270, 75, 460, 105)) { Print("Failed to create send button"); return INIT_FAILED; } sendButton.Text("Send Message"); adminPanel.Add(sendButton); // Create the character counter label if (!charCounter.Create(chart_id, "CharCounter", 0, 380, 110, 460, 130)) { Print("Failed to create character counter label"); return INIT_FAILED; } charCounter.Text("0/" + IntegerToString(MAX_MESSAGE_LENGTH)); adminPanel.Add(charCounter); // Create the quick message buttons string quickMessages[8] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 }; int startX = 5, startY = 160, width = 222, height = 65, spacing = 5; for (int i = 0; i < 8; i++) { if (!quickMessageButtons[i].Create(chart_id, "QuickMessageButton" + IntegerToString(i + 1), 0, startX + (i % 2) * (width + spacing), startY + (i / 2) * (height + spacing), startX + (i % 2) * (width + spacing) + width, startY + (i / 2) * (height + spacing) + height)) { Print("Failed to create quick message button ", i + 1); return INIT_FAILED; } quickMessageButtons[i].Text(quickMessages[i]); adminPanel.Add(quickMessageButtons[i]); } adminPanel.Show(); // Create the minimize button if (!minimizeButton.Create(chart_id, "MinimizeButton", 0, 375, -22, 405, 0)) { Print("Failed to create minimize button"); return INIT_FAILED; } minimizeButton.Text("_"); adminPanel.Add(minimizeButton); // Create the maximize button if (!maximizeButton.Create(chart_id, "MaximizeButton", 0, 405, -22, 435, 0)) { Print("Failed to create maximize button"); return INIT_FAILED; } maximizeButton.Text("[ ]"); adminPanel.Add(maximizeButton); // Create the close button if (!closeButton.Create(chart_id, "CloseButton", 0, 435, -22, 465, 0)) { Print("Failed to create close button"); return INIT_FAILED; } closeButton.Text("X"); adminPanel.Add(closeButton); adminPanel.Show(); // Enable chart events ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_CREATE, true); ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_DELETE, true); ChartSetInteger(ChartID(), CHART_EVENT_MOUSE_WHEEL, true); ChartRedraw(); Print("Initialization complete"); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { adminPanel.Destroy(); Print("Deinitialization complete"); } //+------------------------------------------------------------------+ //| Expert event handling function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { // Handle different types of events switch (id) { case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") { OnSendButtonClick(); } else if (sparam == "ClearButton") { OnClearButtonClick(); } else if (sparam == "MinimizeButton") { OnMinimizeButtonClick(); } else if (sparam == "MaximizeButton") { OnMaximizeButtonClick(); } else if (sparam == "CloseButton") { OnCloseButtonClick(); } else if (StringFind(sparam, "QuickMessageButton") >= 0) { int index = StringToInteger(StringSubstr(sparam, StringLen("QuickMessageButton"))); OnQuickMessageButtonClick(index - 1); } break; case CHARTEVENT_OBJECT_CHANGE: if (sparam == "InputBox") { OnInputChange(); } break; default: break; } } //+------------------------------------------------------------------+ //| Function to handle custom message send button click | //+------------------------------------------------------------------+ void OnSendButtonClick() { string message = inputBox.Text(); if (message != "") { if (SendMessageToTelegram(message)) Print("Custom message sent: ", message); else Print("Failed to send custom message."); } else { Print("No message entered."); } } //+------------------------------------------------------------------+ //| Function to handle clear button click | //+------------------------------------------------------------------+ void OnClearButtonClick() { inputBox.Text(""); // Clear the text in the input box OnInputChange(); // Update the character counter Print("Input box cleared."); } //+------------------------------------------------------------------+ //| Function to handle quick message button click | //+------------------------------------------------------------------+ void OnQuickMessageButtonClick(int index) { string quickMessages[8] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 }; string message = quickMessages[index]; if (SendMessageToTelegram(message)) Print("Quick Message Button Clicked - Quick message sent: ", message); else Print("Failed to send quick message."); } //+------------------------------------------------------------------+ //| Function to update the character counter | //+------------------------------------------------------------------+ void OnInputChange() { string text = inputBox.Text(); int currentLength = StringLen(text); charCounter.Text(IntegerToString(currentLength) + "/" + IntegerToString(MAX_MESSAGE_LENGTH)); } //+------------------------------------------------------------------+ //| Function to handle minimize button click | //+------------------------------------------------------------------+ void OnMinimizeButtonClick() { minimized = true; // Hide the full admin panel adminPanel.Hide(); minimizeButton.Show(); maximizeButton.Show(); closeButton.Show(); } //+------------------------------------------------------------------+ //| Function to handle maximize button click | //+------------------------------------------------------------------+ void OnMaximizeButtonClick() { if (minimized) { minimizeButton.Hide(); maximizeButton.Hide(); closeButton.Hide(); adminPanel.Show(); } } //+------------------------------------------------------------------+ //| Function to handle close button click | //+------------------------------------------------------------------+ void OnCloseButtonClick() { ExpertRemove(); // Completely remove the EA Print("Admin Panel closed."); } //+------------------------------------------------------------------+ //| Function to send the message to Telegram | //+------------------------------------------------------------------+ bool SendMessageToTelegram(string message) { // Use the input values for bot token and chat ID string botToken = InputBotToken; string chatId = InputChatId; string url = "https://api.telegram.org/bot" + botToken + "/sendMessage"; char post_data[]; // Prepare the message data string jsonMessage = "{\"chat_id\":\"" + chatId + "\", \"text\":\"" + message + "\"}"; // Resize the character array to fit the JSON payload ArrayResize(post_data, StringToCharArray(jsonMessage, post_data)); int timeout = 5000; char result[]; string responseHeaders; // Make the WebRequest int res = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, post_data, result, responseHeaders); if (res == 200) // HTTP 200 OK { Print("Message sent successfully: ", message); return true; } else { Print("Failed to send message. HTTP code: ", res, " Error code: ", GetLastError()); Print("Response: ", CharArrayToString(result)); return false; } }
Тестирование расширенной и адаптивной панели администратора:
Здесь я запустил панель администратора и она работала хорошо, с небольшими недостатками. Посмотрим на изображение ниже.
Индекс волатильности 150s: тестирование панели администратора
Интеграция с Telegram прошла отлично, наши сообщения приходят по щелчку мыши!
Входящие быстрые сообщения в сервисе Telegram
Заключение
В заключение отметим, что интеграция функций быстрого реагирования и обмена сообщениями в панель администратора советника (EA) значительно повышает его полезность и удобство для пользователей. Недавно добавленные кнопки свёртывания, развёртывания и закрытия обеспечивают простой и интуитивно понятный интерфейс, позволяющий пользователям легко управлять видимостью панели и ее работой. Эти функции гарантируют, что панель будет не только функциональной, но и адаптируемой к потребностям пользователя, независимо от того, требуется ли полный обзор или компактный, ненавязчивый дисплей.Реализация функции быстрого обмена сообщениями еще больше упрощает коммуникацию, позволяя пользователям мгновенно отправлять шаблонные сообщения своим клиентам в Telegram, не выходя из среды MetaTrader 5. Эта функция особенно ценна в быстро меняющихся торговых сценариях, где время имеет решающее значение. Возможность панели отправлять пользовательские сообщения в сочетании с удобными кнопками быстрого обмена сообщениями позволяет пользователям поддерживать эффективную коммуникацию с минимальными помехами в своей торговой деятельности.
В целом, эти усовершенствования делают панель администратора более мощным инструментом для трейдеров и администраторов, повышая как эффективность, так и гибкость. Эта эволюция отражает наше стремление предоставлять решения, касающиеся реальных задач в области алгоритмической торговли, которые гарантируют, что пользователи смогут управлять своими торговыми операциями с большим контролем и удобством.
Можно было бы сделать больше, но сегодня мы сделали это здесь. Ниже прилагается исходный файл. Счастливой разработки и торговли, друзья!
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/15418





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