WebRequest для отправки JSON-сообщений на предварительно настроенный Discord Webhook URL. Это позволяет получать уведомления о сделках в реальном времени прямо в ваш Discord канал.Исходный код
Представленный ниже код является полноценным MQL5 советником, который отслеживает торговые сделки, совершенные им самим на текущем символе, и отправляет детали этих сделок в указанный Discord канал. Он включает в себя логику инициализации, деинициализации и обработку торговых событий OnTrade.
//+------------------------------------------------------------------+
//| DiscordLogger_WebRequest.mq5 |
//| Copyright 2023, FinFluct |
//| https://finfluct.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, FinFluct"
#property link "https://finfluct.com"
#property version "1.00"
#property description "Интеграция MQL5 советника с Discord для логирования сделок через WebRequest."
//--- Входные параметры
input string Inp_DiscordWebhookURL = "YOUR_DISCORD_WEBHOOK_URL_HERE"; // URL Discord Webhook
input string Inp_DiscordUsername = "MQL5 Trade Logger"; // Имя пользователя для сообщений в Discord
input string Inp_DiscordAvatarURL = ""; // URL аватара для сообщений (опционально)
//+------------------------------------------------------------------+
//| Global variables |
//+------------------------------------------------------------------+
string last_deal_ticket = ""; // Для отслеживания последней обработанной сделки
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Проверка на корректность URL
if (StringLen(Inp_DiscordWebhookURL) < 10 || StringFind(Inp_DiscordWebhookURL, "discord.com/api/webhooks") == -1)
{
Print("Ошибка: Некорректный URL Discord Webhook. Пожалуйста, проверьте настройки.");
return INIT_FAILED;
}
Print("Discord Logger Initialized. Webhook URL: ", Inp_DiscordWebhookURL);
SendDiscordMessage("Советник '" + MQL5InfoString(MQL5_PROGRAM_NAME) + "' запущен на " + Symbol() + " " + EnumToString(Period()) + ".");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
SendDiscordMessage("Советник '" + MQL5InfoString(MQL5_PROGRAM_NAME) + "' остановлен на " + Symbol() + " " + EnumToString(Period()) + ". Причина: " + EnumToString((ENUM_REASON_PROGRAM)reason) + ".");
}
//+------------------------------------------------------------------+
//| Trade event function |
//+------------------------------------------------------------------+
void OnTrade()
{
// Проверяем новые сделки
HistorySelect(0, TimeCurrent());
int total_deals = HistoryDealsTotal();
for (int i = total_deals - 1; i >= 0; i--)
{
ulong deal_ticket = HistoryDealGetTicket(i);
if (deal_ticket == 0) continue;
// Проверяем, была ли эта сделка уже обработана
if (LongToString(deal_ticket) == last_deal_ticket) break; // Если нашли последнюю обработанную, выходим
ENUM_DEAL_TYPE deal_type = (ENUM_DEAL_TYPE)HistoryDealGetInteger(deal_ticket, DEAL_TYPE);
ENUM_DEAL_ENTRY deal_entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket, DEAL_ENTRY);
string deal_symbol = HistoryDealGetString(deal_ticket, DEAL_SYMBOL);
double deal_volume = HistoryDealGetDouble(deal_ticket, DEAL_VOLUME);
double deal_price = HistoryDealGetDouble(deal_ticket, DEAL_PRICE);
long deal_order = HistoryDealGetInteger(deal_ticket, DEAL_ORDER);
datetime deal_time = (datetime)HistoryDealGetInteger(deal_ticket, DEAL_TIME);
// Фильтруем только сделки, относящиеся к текущему символу
if (deal_symbol != Symbol()) continue;
// Получаем информацию об ордере, чтобы узнать магик
long order_magic = 0;
if (HistoryOrderSelect(deal_order))
{
order_magic = HistoryOrderGetInteger(deal_order, ORDER_MAGIC);
}
else if (OrderSelect(deal_order, SELECT_BY_TICKET, MODE_TRADES)) // Если ордер еще активен
{
order_magic = OrderGetInteger(ORDER_MAGIC);
}
// Если магик ордера не совпадает с магиком советника, пропускаем
if (order_magic != ExpertMagicNumber()) continue;
string message = "";
string deal_type_str = "";
switch (deal_type)
{
case DEAL_TYPE_BUY:
deal_type_str = "Покупка";
break;
case DEAL_TYPE_SELL:
deal_type_str = "Продажа";
break;
case DEAL_TYPE_BALANCE:
deal_type_str = "Баланс";
break;
case DEAL_TYPE_CREDIT:
deal_type_str = "Кредит";
break;
case DEAL_TYPE_CHARGE:
deal_type_str = "Комиссия";
break;
case DEAL_TYPE_CORRECTION:
deal_type_str = "Коррекция";
break;
case DEAL_TYPE_COMMISSION:
deal_type_str = "Комиссия";
break;
case DEAL_TYPE_DIVIDEND:
deal_type_str = "Дивиденд";
break;
case DEAL_TYPE_TAX:
deal_type_str = "Налог";
break;
case DEAL_TYPE_AGENT_COMMISSION:
deal_type_str = "Агентская комиссия";
break;
default:
deal_type_str = "Неизвестно";
break;
}
string deal_entry_str = "";
switch (deal_entry)
{
case DEAL_ENTRY_IN:
deal_entry_str = "Вход";
break;
case DEAL_ENTRY_OUT:
deal_entry_str = "Выход";
break;
case DEAL_ENTRY_INOUT:
deal_entry_str = "Закрытие/Разворот";
break;
case DEAL_ENTRY_STATE:
deal_entry_str = "Состояние";
break;
default:
deal_entry_str = "Неизвестно";
break;
}
message = StringFormat(
"**%s** | **%s** | `%s` | Объем: `%.2f` | Цена: `%.5f` | Тикет: `%s` | Время: `%s`",
deal_entry_str,
deal_type_str,
deal_symbol,
deal_volume,
deal_price,
LongToString(deal_ticket),
TimeToString(deal_time, TIME_DATE|TIME_SECONDS)
);
SendDiscordMessage(message);
last_deal_ticket = LongToString(deal_ticket); // Обновляем последний обработанный тикет
}
}
//+------------------------------------------------------------------+
//| Function to send message to Discord |
//+------------------------------------------------------------------+
void SendDiscordMessage(string message)
{
string headers = "Content-Type: application/json";
string data = "{\"content\":\"" + message + "\", \"username\":\"" + Inp_DiscordUsername + "\"";
if (StringLen(Inp_DiscordAvatarURL) > 0)
{
data += ", \"avatar_url\":\"" + Inp_DiscordAvatarURL + "\"";
}
data += "}";
char post_data[];
StringToCharArray(data, post_data);
char result_headers[];
char result_data[];
int res_code;
// Домен для WebRequest должен быть добавлен в список разрешенных в настройках терминала (Tools -> Options -> Expert Advisors)
string domain = StringSubstr(Inp_DiscordWebhookURL, StringFind(Inp_DiscordWebhookURL, "://") + 3);
domain = StringSubstr(domain, 0, StringFind(domain, "/"));
int timeout = 5000; // 5 секунд таймаут
int handle = WebRequest("POST", Inp_DiscordWebhookURL, headers, timeout, post_data, result_headers, result_data);
if (handle == -1)
{
Print("WebRequest failed. Error: ", GetLastError());
}
else
{
// В MQL5 WebRequest возвращает HTTP статус в первых 4 байтах result_headers
res_code = CharArrayToInt(result_headers, 0);
string response_body = CharArrayToString(result_data);
if (res_code >= 200 && res_code < 300)
{
Print("Сообщение успешно отправлено в Discord. Статус: ", res_code);
}
else
{
Print("Ошибка отправки сообщения в Discord. Статус: ", res_code, ", Ответ: ", response_body);
}
}
}
Разбор параметров
Inp_DiscordWebhookURL: Это критически важный параметр. Сюда необходимо вставить URL вашего Discord Webhook, который вы создадите в настройках канала Discord. Пример:https://discord.com/api/webhooks/123456789012345678/abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890.Inp_DiscordUsername: Имя, которое будет отображаться в Discord рядом с сообщениями от вашего советника. По умолчанию:MQL5 Trade Logger.Inp_DiscordAvatarURL: (Опционально) URL изображения, которое будет использоваться в качестве аватара для сообщений от советника. Если оставить пустым, будет использоваться стандартный аватар Webhook.
Как запустить
Для успешной интеграции и запуска советника выполните следующие шаги:
- Создайте Discord Webhook:
- Откройте ваш Discord сервер и перейдите в настройки нужного канала (щелкните правой кнопкой мыши по каналу -> 'Редактировать канал' -> 'Интеграции').
- Нажмите 'Вебхуки' -> 'Новый вебхук'.
- Дайте ему имя (например, 'MQL5 Logger'), выберите канал, в который будут приходить сообщения, и при желании загрузите изображение.
- Скопируйте 'URL вебхука'. Это значение вам понадобится для параметра
Inp_DiscordWebhookURLв советнике.
- Настройте MetaTrader 5 для
WebRequest:- В MetaTrader 5 перейдите в 'Сервис' -> 'Настройки' (или нажмите
Ctrl+O). - Перейдите на вкладку 'Советники'.
- Установите флажок 'Разрешить WebRequest для перечисленных URL'.
- В поле ниже добавьте домен
discord.com. Это необходимо, чтобы MQL5 мог отправлять запросы на серверы Discord.
- В MetaTrader 5 перейдите в 'Сервис' -> 'Настройки' (или нажмите
- Установите и настройте советник:
- Скопируйте предоставленный MQL5 код в новый файл в MetaEditor (Файл -> Создать -> Советник (Шаблон) -> Далее -> Имя:
DiscordLogger_WebRequest.mq5-> Готово). - Сохраните и скомпилируйте код (кнопка 'Компилировать' или
F7). - Перетащите скомпилированный советник (
DiscordLogger_WebRequest.ex5) из 'Навигатора' на график торгового инструмента, на котором вы хотите отслеживать сделки. - В окне настроек советника (вкладка 'Входные параметры') вставьте скопированный URL вебхука в поле
Inp_DiscordWebhookURL. При желании измените имя пользователя и аватар. - Убедитесь, что на вкладке 'Общие' установлен флажок 'Разрешить алгоритмическую торговлю'.
- Нажмите 'ОК'.
- Скопируйте предоставленный MQL5 код в новый файл в MetaEditor (Файл -> Создать -> Советник (Шаблон) -> Далее -> Имя:
- Запуск на VPS:
Для круглосуточного логирования и стабильной работы крайне рекомендуется размещать MetaTrader 5 с советником на виртуальном частном сервере (VPS). Это обеспечит бесперебойную работу терминала и, соответственно, непрерывное логирование сделок в Discord, независимо от состояния вашего локального компьютера.
Помимо логирования, вы можете использовать
WebRequestдля интеграции с другими сервисами, например, для получения данных из экономического календаря или для отправки сигналов, которые могут быть дополнительно обработаны, например, с использованием методов K-Means для фильтрации ложных сигналов.
Теперь все сделки, совершенные вашим советником на этом графике, будут автоматически отправляться в ваш Discord канал, предоставляя вам удобный способ мониторинга торговой активности в реальном времени.




