English
preview
Преодоление проблем доступности в торговых инструментах на MQL5 (Часть II): Включению голосовых функций в советнике с помощью Python-движка синтеза речи

Преодоление проблем доступности в торговых инструментах на MQL5 (Часть II): Включению голосовых функций в советнике с помощью Python-движка синтеза речи

MetaTrader 5Примеры |
52 0
Clemence Benjamin
Clemence Benjamin

Содержание:


Введение

В фантастических художественных фильмах мы видели, как роботы разговаривают, и это кажется естественным — речь делает взаимодействие между человеком и его роботизированным компаньоном интуитивно понятным. Пользователь может легко понять, что делает машина, просто прислушавшись. Сегодня мы стремимся устранить большой разрыв между трейдером и его советником. Помощь, которую до сих пор предлагают эти системы, невероятна, но часто кажется, что она слишком негибкая: звуковой сигнал, всплывающее окно или запись в журнале. Чтобы оставаться в курсе событий и лучше представлять картину, нам необходимо повысить эффективность и доступность наших существующих и будущих систем.

Доступность остается проблемой для многих торговых инструментов — независимо от того, есть ли у пользователя нарушения зрения или нет. Не у всех есть время постоянно открывать логи или журнал, чтобы видеть, что делает или сделал советник. Иногда гораздо эффективнее, если система может просто озвучивать важные события. Решения существуют, но в основном они не являются гибкими и представляют собой предварительно записанные WAV—файлы, которые не могут адаптироваться к меняющимся рыночным условиям. 11 ноября 2020 года Александр Федосов опубликовал подробную статью, посвященную голосовым уведомлениям в MQL5. Однако с этим решением остается одна проблема ‑ отсутствие гибкости: каждый звук должен быть подготовлен заранее, и советник не может сказать что-либо, что не было бы записано заранее. Сегодня мы будем использовать технологию TTS, чтобы советник мог динамически озвучивать различные рыночные ситуации, что дает гораздо большую гибкость.

Давайте перечислим основные преимущества обсуждения этой разработки:

  1. Экономия времени на разработку, используя технологию TTS вместо создания звуковых ресурсов (WAV-файлов).
  2. Снизить жесткость речевых оповещений, сделав их динамичными и контекстно-зависимыми.
  3. Советник может выдавать гораздо более подробные оповещения с помощью речи, чем обычное встроенное оповещение.
  4. Это открывает путь для расширенного взаимодействия между пользователем и советником (например, голосовое подтверждение, устные резюме).

Структурная диаграмма и концепция, лежащая в основе этой разработки:

Рис.1. Схема работы голосового контура

Приведенная выше диаграмма иллюстрирует элегантную простоту нашего подхода. Советник, работающий в MetaTrader 5, действует как мозг, который распознает рыночные события — будь то пересечение, фиксация прибыли или предупреждение о марже. Вместо воспроизведения статического WAV‑файла он создает динамическое текстовое сообщение, содержащее данные в реальном времени, такие как текущая цена, название символа, точное время или любая другая переменная, которую мы выбираем. Далее это текстовое сообщение отправляется с помощью HTTP POST-запроса (с использованием функции WebRequest в MQL5) на локальный сервер Python, работающий на том же компьютере. Сервер Python, выступающий в роли голоса, получает текст, обрабатывает его с помощью механизма преобразования текста в речь и немедленно воспроизводит его через аудиосистему компьютера. Весь путь туда и обратно занимает всего миллисекунды, но в результате вы получаете торгового компаньона, который может рассказать вам все, что вам нужно знать, на простом английском языке, когда это наиболее важно.

Что делает эту архитектуру эффективной, так это разделение задач. Советник концентрируется на том, что у него получается лучше всего — на мониторинге рынка, выполнении логических операций и генерации значимых оповещений. Сервер Python справляется со сложной задачей синтеза речи, что значительно превосходит встроенные возможности MQL5. Объединяя эти две технологии с помощью простого HTTP-интерфейса, мы получаем лучшее из обоих миров: тесную интеграцию MQL5 с торговым терминалом и обширную экосистему библиотек Python, включая мощные движки TTS. Более того, этот дизайн полностью локален — никакие данные никогда не покидают ваш компьютер, обеспечивая конфиденциальность и безопасность при одновременном устранении задержек.

Теперь, когда мы поняли концепцию, пришло время засучить рукава и приступить к ее реализации. В следующем разделе мы пошагово разберем реализацию: во-первых, настройки среды Python и создания сервера TTS; во-вторых, разработки советника MQL5 с переиспользуемой функцией; и, в-третьих, включения WebRequest и настройки MetaTrader 5 для локальной HTTP-связи. Затем мы рассмотрим полный советник пересечения скользящих средних, который объединяет все в себе, в комплекте с тестовым режимом для немедленной проверки. В заключение мы рассмотрим результаты тестирования, обсудим устранение распространенных неполадок и поделимся идеями о том, как еще больше расширить этот фундамент.

Независимо от того, являетесь ли вы опытным разработчиком MQL5 или только начинаете, эта статья познакомит вас с новым мощным инструментом, который сделает ваши советники более коммуникабельными, доступными и интеллектуальными. Давайте приступим.



Реализация

В этом разделе мы пошагово разработаем всю систему. Сначала мы настроим сервер Python TTS, который будет прослушивать входящие сообщения. Далее разработаем советник на MQL5, который использует функцию WebRequest для отправки этих сообщений. Мы используем советник, потому что WebRequest не может вызываться из индикатора. Приведенный в качестве примера советник представляет собой простое пересечение скользящих средних для демонстрации идеи, но вы можете легко адаптировать функцию Speak() к любому из существующих у вас советников.

Настройка окружения Python

У вас должен быть установлен Python (версии 3.7 или более поздней). Откроем терминал и установим необходимые библиотеки:

pip install flask pyttsx3

Flask будет служить нашим легким веб‑сервером, а pyttsx3 обеспечивает офлайн-синтез речи с использованием системных голосов.

Создание TTS-сервера

Мы напишем скрипт на Python, который запустит сервер Flask на локальном хосте, порт 5000. Он будет принимать POST-запросы с телом в формате JSON, содержащим текст для произнесения. Поскольку несколько сообщений могут приходить друг за другом (например, приветственное сообщение, за которым сразу следует тестовое сообщение), мы должны избегать конфликтов потоков. Сервер использует очередь и один рабочий поток для обработки сообщений одно за другим. Каждое сообщение создает новый экземпляр движка pyttsx3, чтобы предотвратить ошибку “цикл выполнения уже запущен”, которая преследовала нас на ранних этапах разработки.

Сервер преобразования текста в речь на Python

Сервер выступает в качестве связующего звена между нашим советником на MQL5 и движком преобразования текста в речь в Windows. Он прослушивает HTTP POST-запросы, ставит входящие сообщения в очередь и обрабатывает их одно за другим, используя фоновый поток. Такая конструкция гарантирует, что даже если несколько предупреждений поступают быстро, они озвучиваются последовательно, без наложения и сбоев.

1. Импорт необходимых модулей

Начинаем с импорта необходимых библиотек Python. Flask - это легкий веб-фреймворк для обработки HTTP-запросов. Queue предоставляет нам потокобезопасную очередь FIFO для управления входящими сообщениями. Многопоточность позволяет нам запускать синтез речи в фоновом режиме, поэтому веб-сервер никогда не блокирует работу. Модуль subprocess используется для запуска команд PowerShell, а shlex помогает с безопасной обработкой аргументов командной строки (хотя здесь это не обязательно, но включено для полноты картины).

Код Python

from flask import Flask, request, jsonify
import queue
import threading
import subprocess
import shlex

2. Инициализация приложения Flask и очереди сообщений

Мы создаем экземпляр приложения Flask и глобальную message_queue. В этой очереди будут храниться текстовые строки, которые необходимо произнести вслух. Производитель (конечная точка HTTP) помещает сообщения в очередь, а потребитель (рабочий поток) извлекает их и обрабатывает. Это отделяет входящие запросы от фактического синтеза речи, предотвращая любую задержку или блокировку веб-сервера.

Код Python

app = Flask(__name__)
message_queue = queue.Queue()

3. Функция синтеза речи PowerShell

Эта функция отвечает за преобразование текстовой строки в звуковую речь с использованием встроенных возможностей Windows. Сначала мы экранируем все двойные кавычки внутри текста, поскольку команда PowerShell будет заключена в одинарные кавычки. Команда PowerShell загружает сборку System.Speech, создает объект SpeechSynthesizer и вызывает его метод Speak. Затем мы запускаем эту команду в фоновом режиме с помощью subprocess.run(), перехватывая вывод (хотя мы его игнорируем). Использование PowerShell напрямую позволяет избежать проблем с многопоточностью и нестабильностью, с которыми мы столкнулись в pyttsx3.

Код Python

def powershell_speak(text):
    """Speak text using PowerShell's built-in speech synthesis."""
    # Escape double quotes inside the text
    text = text.replace('"', '`"')
    # Build PowerShell command
    ps_command = f"Add-Type -AssemblyName System.Speech; $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer; $synth.Speak('{text}')"
    # Run PowerShell silently
    subprocess.run(["powershell", "-Command", ps_command], capture_output=True)

4. Фоновый рабочий поток

Рабочий поток выполняет бесконечный цикл. Он ожидает появления сообщения в очереди (.get() блокируется, пока что-нибудь не станет доступно). Как только сообщение получено, он выводит подтверждение в консоль (для отладки), а затем вызывает powershell_speak() для фактического произнесения текста. Если во время синтеза речи возникает какое-либо исключение, оно перехватывается и выводится, но цикл продолжается. Наконец, .task_done() сигнализирует о том, что сообщение обработано, что полезно, если нам когда-либо потребуется дождаться опустошения очереди.

Код Python

def tts_worker():
    while True:
        text = message_queue.get()
        print(f"Speaking: {text}")
        try:
            powershell_speak(text)
        except Exception as e:
            print(f"TTS error: {e}")
        message_queue.task_done()

5. Запуск рабочего потока

Мы создаем новый поток-демон, который запускает функцию tts_worker. Флаг daemon=True означает, что поток автоматически завершится при выходе из основной программы. Это важно, поскольку позволяет остановить сервер с помощью Ctrl+C, не оставляя "осиротевших" потоков.

Код Python

# Start worker thread
threading.Thread(target=tts_worker, daemon=True).start()

6. Конечная точка HTTP для получения сообщений

Этот маршрут Flask прослушивает POST-запросы в маршрут /speak. Когда поступает запрос, он извлекает данные JSON и проверяет наличие текстового поля. Если поле отсутствует, он возвращает ошибку 400. В противном случае он помещает текст в очередь сообщений и немедленно возвращает ответ об успешном выполнении ({"status": "ok"}). Поскольку фактическая речь происходит в фоновом потоке, конечная точка очень быстрая и не заставляет советник ждать.

Код Python

@app.route('/speak', methods=['POST'])
def handle_speak():
    data = request.get_json()
    if not data or 'text' not in data:
        return jsonify({'error': 'Missing text'}), 400
    text = data['text']
    message_queue.put(text)
    return jsonify({'status': 'ok'})

7. Запуск сервера

Наконец, мы запускаем сервер разработки Flask. Привязываем его к 127.0.0.1 (localhost) на порту 5000. Параметр threaded=False гарантирует, что Flask сам по себе не создает дополнительных потоков, что делает нашу потоковую модель простой и предсказуемой. Этот сервер предназначен только для локального использования, поэтому сервер разработки прекрасно подходит.

Код Python

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=5000, threaded=False)

Подготовка стороны советника

В MetaEditor мы создадим новый советник. Ключевая функция — Speak(), которая формирует JSON-тело запроса и отправляет её через WebRequest. Необходимо убедиться, что URL-адрес “http://127.0.0.1:5000/speak” добавлен в список разрешенных URL-адресов в терминале MetaTrader 5 (Инструменты → Параметры → Советники → Разрешить WebRequest для указанных URL-адресов).

Webrequest setting

Рис. 2. Настройка серверного соединения

Разработка советника на пересечении в тестовом режиме

Для немедленной демонстрации работы системы мы включаем входной параметр “TestMode”. При включении советник будет произносить тестовое сообщение на каждом новом баре, содержащее текущий символ, цены bid/ask и время работы сервера. Это доказывает, что советник может получать доступ к оперативным данным и что конвейер TTS работает без ожидания сигнала о пересечении. Сама логика пересечения использует две скользящие средние и значение ATR для контекста; когда происходит пересечение, советник выдает подробное предупреждение, включающее направление сигнала, цену и ATR.

Советник реализует классическую стратегию пересечения скользящих средних и добавляет возможность передавать динамические сообщения через локальный сервер TTS на Python. Он включает тестовый режим для немедленной проверки, опциональную торговлю и надежную обработку ошибок для WebRequest. Код структурирован таким образом, чтобы быть понятным и легко адаптируемым к вашим стратегиям.

1. Заголовок советника и метаданные

Советник начинается со стандартных метаданных MQL5: авторских прав, ссылки, версии и краткого описания. Эта информация отображается в навигаторе и при прикреплении советника к графику. В описании четко указано, что этот советник поддерживает голосовую связь и включает в себя тестовый режим.

//+------------------------------------------------------------------+
//|                                          MA_Crossover_TTS_EA.mq5 |
//|                                Copyright 2025, Clemence Benjamin |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Clemence Benjamin"
#property link      "https://www.mql5.com"
#property version   "1.10"
#property description "Voice‑enabled MA Crossover EA with Test Mode"

2. Входные параметры

Все параметры, настраиваемые пользователем, отображаются в качестве входных параметров. Первая группа определяет логику торговли: периоды быстрой и медленной скользящей средней, период ATR для контекста и метод расчета. Вторая группа управляет голосовыми оповещениями и торговым поведением: включение голосовых оповещений, включение фактической торговли, размер лота и уникальное магическое число. Наконец, режим TestMode позволяет советнику произносить тестовое сообщение на каждом новом баре — это бесценно для немедленной проверки без ожидания пересечения.

// --- Input Parameters ---
input int      FastMAPeriod      = 9;           // Fast MA Period
input int      SlowMAPeriod      = 21;          // Slow MA Period
input int      ATRPeriod         = 14;          // ATR Period
input ENUM_MA_METHOD  MaMethod   = MODE_EMA;    // MA Method
input ENUM_APPLIED_PRICE PriceType = PRICE_CLOSE; // Price type

input bool     EnableVoiceAlerts = true;        // Enable spoken alerts
input bool     EnableTrading     = false;       // Set true to actually place trades
input double   LotSize           = 0.01;        // Only used if trading enabled
input int      MagicNumber       = 20250225;    // Unique EA identifier

input bool     TestMode          = false;       // If true, speak test info on every new bar

3. Глобальные переменные

Глобальные переменные используются для хранения хэндлов индикаторов и отслеживания состояния бара/сигнала по тикам. fastMA_handle, slowMA_handle и atr_handle содержат хэндлы технических индикаторов. Переменная lastBarTime хранит время открытия последнего обработанного бара, что позволяет нам обнаруживать новые бары. Переменная lastSignalBar предотвращает отправку советником дублирующих сигналов на одном и том же баре.

// --- Global Variables ---
int fastMA_handle, slowMA_handle, atr_handle;
datetime lastBarTime = 0;          // For new bar detection
ulong    lastSignalBar = 0;         // Prevent repeated signals on same bar

4. Инициализация—OnInit()

В OnInit() мы создаем хэндлы индикаторов для быстрой скользящей средней, медленной скользящей средней и ATR. Если создание какого-либо хэндла не удается, советник возвращает INIT_FAILED и выводит сообщение об ошибке. Если включены голосовые оповещения, мы немедленно отправляем приветственное сообщение на сервер TTS, подтверждающее, что конвейер работает с самого начала.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Create indicator handles
   fastMA_handle = iMA(_Symbol, _Period, FastMAPeriod, 0, MaMethod, PriceType);
   slowMA_handle = iMA(_Symbol, _Period, SlowMAPeriod, 0, MaMethod, PriceType);
   atr_handle    = iATR(_Symbol, _Period, ATRPeriod);

   if(fastMA_handle == INVALID_HANDLE || slowMA_handle == INVALID_HANDLE || atr_handle == INVALID_HANDLE)
   {
      Print("Failed to create indicator handles");
      return INIT_FAILED;
   }

   // Welcome message (optional)
   if(EnableVoiceAlerts)
      Speak("Moving average crossover expert advisor started on " + _Symbol);

   return INIT_SUCCEEDED;
}

5. OnDeinit()

После удаления советника с графика необходимо освободить все хэндлы индикаторов, чтобы освободить системные ресурсы. Это делается в OnDeinit() с помощью IndicatorRelease() для каждого хэндла. Это хорошая практика для предотвращения утечек памяти.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // Release handles
   if(fastMA_handle != INVALID_HANDLE) IndicatorRelease(fastMA_handle);
   if(slowMA_handle != INVALID_HANDLE) IndicatorRelease(slowMA_handle);
   if(atr_handle    != INVALID_HANDLE) IndicatorRelease(atr_handle);
}

6. Режим обнаружения новых баров и тестирования

Функция OnTick() вызывается на каждом тике. Первая задача — определить, сформировался ли новый бар. Это делается путём сравнения времени открытия текущего бара (iTime(_Symbol, _Period, 0)) с ранее сохраненным значением lastBarTime. Если они совпадают, мы немедленно завершаем работу — это ограничивает всю обработку одним разом на бар, что эффективно и предотвращает чрезмерное количество вызовов WebRequest.

Если обнаружен новый бар, мы обновляем lastBarTime, и, если включены TestMode и голосовые оповещения, мы вызываем SpeakTestInfo() для произнесения текущего символа, цены покупки/продажи и серверного времени. Это обеспечивает немедленную обратную связь о том, что советник активен и соединение TTS работает.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // --- New bar detection ---
   datetime currentBarTime = iTime(_Symbol, _Period, 0);
   if(currentBarTime == lastBarTime)
      return; // Same bar, nothing to do
   lastBarTime = currentBarTime;

   // --- Test Mode: speak current info on every new bar ---
   if(TestMode && EnableVoiceAlerts)
      SpeakTestInfo();

   // ... (crossover detection continues) ...
}

7. Получение значений индикаторов для обнаружения пересечения

После обработки нового бара мы получаем значения быстрой скользящей средней, медленной скользящей средней и ATR для предыдущего бара (индекс 1) и бара перед ним (индекс 2). Мы формируем массивы в виде серии, так что индекс 0 соответствует самым последним данным. Мы копируем два значения для скользящих средних и одно для ATR. Если какой-либо вызов CopyBuffer завершится неудачей, мы досрочно выходим из функции. Мы также получаем цену закрытия текущего (только что открытого) бара для использования в голосовом оповещении.

   // --- Fetch indicator values for the previous (just closed) bar and the bar before that ---
   double fast[], slow[], atr[];
   ArraySetAsSeries(fast, true);
   ArraySetAsSeries(slow, true);
   ArraySetAsSeries(atr, true);

   if(CopyBuffer(fastMA_handle, 0, 1, 2, fast) < 2) return;
   if(CopyBuffer(slowMA_handle, 0, 1, 2, slow) < 2) return;
   if(CopyBuffer(atr_handle,    0, 1, 1, atr) < 1) return;

   double currentClose = iClose(_Symbol, _Period, 0); // price of the newly opened bar

8. Обнаружение пересечений и обработка сигналов

Мы сравниваем значения быстрой и медленной скользящих средних для обнаружения пересечения. Если быстрая скользящая средняя пересекает медленную скользящую среднюю снизу (была ниже предыдущего бара, а теперь выше), мы устанавливаем сигнал на "BUY". Если она пересекает ее сверху, мы устанавливаем сигнал на "SELL". Если сигнал обнаружен, сначала убеждаемся, что это не дубликат для того же бара, используя lastSignalBar.

При появлении валидного сигнала мы формируем подробное голосовое сообщение, включающее направление сигнала, символ, цену и значение ATR. Это сообщение отправляется на сервер TTS с помощью функции Speak(). Если торговля включена, мы также вызываем функцию PlaceTrade() для исполнения рыночного ордера. Такой модульный подход делает код чистым и простым в сопровождении.

   // --- Crossover detection ---
   string signal = "";
   if(fast[1] < slow[1] && fast[0] > slow[0])
      signal = "BUY";
   else if(fast[1] > slow[1] && fast[0] < slow[0])
      signal = "SELL";

   if(signal != "")
   {
      // Avoid duplicate signals on same bar
      if(lastSignalBar == currentBarTime) return;
      lastSignalBar = currentBarTime;

      // --- Voice Alert ---
      if(EnableVoiceAlerts)
      {
         string message = StringFormat(
            "%s signal on %s at price %.*f. ATR is %.*f.",
            signal,
            _Symbol,
            _Digits,
            currentClose,
            _Digits,
            atr[0]
         );
         Speak(message);
      }

      // --- Trading (optional) ---
      if(EnableTrading)
      {
         PlaceTrade(signal);
      }
   }
}

9. Информация о тестовом режиме — SpeakTestInfo()

Эта вспомогательная функция вызывается при включении TestMode. Она получает текущие цены bid и ask с помощью SymbolInfoDouble(), получает текущее серверное время с помощью TimeCurrent(), форматирует время в удобочитаемую строку и формирует тестовое сообщение. Это сообщение далее отправляется на сервер TTS с помощью Speak(). Эта функция доказывает, что советник может получать доступ к рыночным данным в реальном времени и преобразовывать их в речь.

//+------------------------------------------------------------------+
//| Speak test information (symbol, price, time)                     |
//+------------------------------------------------------------------+
void SpeakTestInfo()
{
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   datetime now = TimeCurrent();
   string timeStr = TimeToString(now, TIME_DATE|TIME_MINUTES|TIME_SECONDS);
   string message = StringFormat(
      "Test on %s: Bid %.*f, Ask %.*f at %s",
      _Symbol,
      _Digits,
      bid,
      _Digits,
      ask,
      timeStr
   );
   Speak(message);
}

10. Основная речевая функция — Speak()

Функция Speak() является сердцем интеграции. Она формирует JSON-данные, содержащие текст сообщения, экранирует двойные кавычки (для сохранения корректности JSON) и отправляет HTTP POST-запрос на локальный TTS-сервер с помощью WebRequest().

Мы установили таймаут в 3 секунды — достаточно времени для локального соединения. Если WebRequest возвращает -1, мы перехватываем код ошибки с помощью GetLastError() и выводим его на экран. Распространенные ошибки: 4060 (URL-адрес не разрешен в настройках MetaTrader 5) и 4062 (соединение отклонено, сервер не запущен). Возвращая false при сбое, вызывающий код может решить, как обработать ошибку. Эту функцию можно напрямую скопировать в любой другой советник для добавления возможности голосового оповещения.

//+------------------------------------------------------------------+
//| Send text to TTS server via WebRequest                           |
//+------------------------------------------------------------------+
bool Speak(string message)
{
   // The TTS server must be running: python tts_server.py
   string url = "http://127.0.0.1:5000/speak";
   string headers = "Content-Type: application/json\r\n";

   // Escape double quotes in message (if any)
   StringReplace(message, "\"", "\\\"");

   // Build JSON payload
   string data = "{\"text\":\"" + message + "\"}";

   char post_data[];
   char result_data[];
   string result_headers;

   ArrayResize(post_data, StringToCharArray(data, post_data, 0, WHOLE_ARRAY) - 1);

   int timeout = 3000; // 3 seconds
   int res = WebRequest("POST", url, headers, timeout, post_data, result_data, result_headers);

   if(res == -1)
   {
      int err = GetLastError();
      Print("WebRequest error: ", err, " - Message: ", message);
      // Common errors:
      // 4060 - URL not allowed in MT5 options
      // 4062 - Connection refused (server not running)
      return false;
   }
   return true;
}

11. Опциональная торговля — PlaceTrade()

Если пользователь разрешает торговлю, эта функция исполняет рыночный ордер. Она заполняет структуру MqlTradeRequest необходимыми данными: действие, символ, объем, магическое число и отклонение. Цена устанавливается равной текущей цене Ask для ордера на покупку или цене Bid для ордера на продажу.

После отправки ордера с помощью OrderSend() мы проверяем результат. Если ордер не выполнен, выводим код возврата и, если включены голосовые оповещения, произносится сообщение об ошибке. Если ордер выполнен успешно, мы произносим подтверждение, включающее тип ордера и цену исполнения. Это демонстрирует, как та же система голосовых уведомлений может использоваться для постторговых уведомлений.

//+------------------------------------------------------------------+
//| Place a market order (optional)                                  |
//+------------------------------------------------------------------+
void PlaceTrade(string signal)
{
   MqlTradeRequest request = {};
   MqlTradeResult  result = {};

   request.action   = TRADE_ACTION_DEAL;
   request.symbol   = _Symbol;
   request.volume   = LotSize;
   request.magic    = MagicNumber;
   request.deviation = 10;

   if(signal == "BUY")
   {
      request.type   = ORDER_TYPE_BUY;
      request.price  = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   }
   else if(signal == "SELL")
   {
      request.type   = ORDER_TYPE_SELL;
      request.price  = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   }
   else return;

   if(!OrderSend(request, result))
   {
      Print("OrderSend failed: ", result.retcode);
      if(EnableVoiceAlerts)
         Speak("Trade failed, check terminal.");
   }
   else
   {
      if(EnableVoiceAlerts)
      {
         string msg = StringFormat(
            "%s order placed at %.*f",
            signal,
            _Digits,
            request.price
         );
         Speak(msg);
      }
   }
}
//+------------------------------------------------------------------+

Включение WebRequest и запуск

Перед прикреплением советника запустите сервер Python в терминале: python tts_server.py . Далее в MetaTrader 5 убедитесь, что URL-адрес разрешен. Подключите советник к любому графику (например, EURUSD M1) с параметрами TestMode=true и EnableVoiceAlerts=true. Вы должны слышать тестовое сообщение каждую минуту (только для быстрого тестирования; отключите, чтобы избежать непрерывных оповещений на каждом баре). Если произойдет пересечение, вы также услышите это оповещение.


Тестирование

Видеодемонстрация: На трех окнах отображаются сервер Python TTS (командная строка), терминал MetaTrader 5 с советником на XAUUSDmicro и MetaEditor во время перекомпиляции. После инициализации советник произносит тестовое сообщение с динамическими ценами bid/ask и серверным временем, подтверждая мгновенную работу конвейера TTS. В видео также демонстрируется работа советника на синтетическом индексе Boom 900, где он безупречно произносит ту же динамическую информацию. Это подтверждает совместимость с любым торговым инструментом. Несмотря на типичное время ожидания сигналов пересечения, советник эффективно передает множество признаков: он объявляет о пересечениях скользящих средних по мере их возникновения, размещает сделки, когда это включено, и предоставляет голосовую обратную связь в реальном времени о рыночной ситуации. 

Мы тщательно протестировали систему на демо-счете с XAUUSDmicro на 1-минутном графике. Первая реализация с использованием pyttsx3 с общим движком завершилась с ошибкой “цикл выполнения уже запущен” после второго сообщения. Переход к рабочему процессу на основе очереди, создающему новый движок для каждого сообщения, устранил сбои, но после нескольких сообщений речь прекратилась — в консоли отображалось только, что сообщения продолжают поступать. Это указывало на скрытую проблему с движком pyttsx3 в Windows.

Окончательное надежное решение использует встроенный в PowerShell синтез речи. Теперь сервер Python выполняет короткую команду PowerShell для каждого сообщения, которая вызывает System.Speech.Synthesis.SpeechSynthesizer. Этот подход абсолютно надежен: каждое сообщение произносится четко, одно за другим, без сбоев и отключения звука. В логе сервера отображается обработка каждого запроса, и система корректно озвучивает каждое тестовое сообщение и каждое оповещение о пересечении.

Мы также проверили корректность отображения кодов ошибок WebRequest. Если сервер не запущен, MetaTrader 5 возвращает ошибку 4062 (соединение отклонено). Если URL-адрес не разрешен, появляется ошибка 4060. Обе ошибки легко диагностировать и исправить.

Тестовый режим оказался бесценным для получения мгновенной обратной связи — через несколько секунд после подключения советника мы услышали: “Тест на XAUUSDmicro: Bid … Ask … at …”, что подтвердило, что извлечение данных, форматирование JSON и весь TTS-контур работают корректно. Через несколько минут произошло реальное пересечение, и советник объявил: “Сигнал на покупку XAUUSDmicro по цене … ATR равен…”. Вся система безупречно работала на нескольких инструментах, включая синтетические индексы, такие как индекс Boom 900, демонстрируя, что этот подход с функцией голосовых сообщений универсально применим к любой торговой паре.



Заключение

Мы успешно разработали торговую систему с поддержкой голосовых сообщений, при использовании Python, MQL5 и технологии преобразования текста в речь. Теперь советник может озвучивать любую динамическую информацию — цены, сигналы, состояние счета — в реальном времени, используя локальный TTS-сервер на Python. Основными результатами являются:

  • устранение необходимости в предварительно записанных звуковых ресурсах; советник может говорить что угодно;
  • преодоление проблемы многопоточности с рабочим процессом на основе очереди и, наконец, внедрили надежное решение на PowerShell;
  • обеспечение многоразовой функции Speak(), которую можно добавить в любой советник в MQL5; и
  • демонстрация концепции на примере полностью функционального советника на основе пересечения скользящих средних, который объявляет свои сигналы и может также озвучивать тестовую информацию на каждом баре.
Преимущества выходят далеко за рамки технической реализации. С помощью этой системы теперь можно:
  • Оставаться в курсе событий, не глядя на экран — вся критически важная информация передается вслух, позволяя вам отойти от терминала, оставаясь при этом в курсе рыночных процессов.
  • Обеспечивать подлинную доступность — трейдеры с нарушениями зрения, которые могут полноценно использовать аудиоканал, теперь могут получать информацию о рынке в реальном времени благодаря голосовым оповещениям. Это открывает им возможности для самостоятельной торговли.
  • Освоить многозадачность — ваши уши станут дополнительным каналом для получения информации. Анализируете ли вы графики, читаете новости или даже находитесь вдали от рабочего стола, советник будет информировать вас с помощью голосовых сообщений.
  • Устранить жесткие ограничения по звуку — больше не нужно искать или записывать WAV-файлы. Ваш советник может озвучивать любую цену, любое время, любую переменную — мгновенно и динамично.

В перспективе эта основа открывает множество возможностей. Мы можем расширить возможности Python-сервера, чтобы он принимал больше параметров (выбор голоса, скорость, громкость) или передавал аудиопоток на удаленные устройства. Мы можем интегрировать советника с серверами  MCP, чтобы обеспечить голосовые команды в обе стороны — трейдер говорит советнику, а советник отвечает. Тот же метод можно использовать для создания голосовых сводок о ежедневных результатах, оповещений о рисках или даже для чтения заголовков новостей.

Что дальше? Мы получили одностороннюю связь — советник говорит с вами. Следующий рубеж — это двустороннее голосовое взаимодействие, когда вы можете разговаривать со своим советником, а он будет понимать и выполнять ваши команды. Представьте, что вы говорите "Закрыть все убыточные позиции" или "Увеличить размер лота до 0,5", и ваш советник мгновенно реагирует. Это не научная фантастика — это естественная эволюция доступных торговых технологий.

Не пропустите следующую статью из этой серии, где мы раскроем больше секретов доступности с помощью технологий распознавания голоса и преобразования текста в речь. Будущее торговли — за голосом, и вы только что сделали первый шаг.

Надеюсь,  эта статья вдохновит вас сделать свои советники более доступными и интерактивными. Полный исходный код приведен ниже, и мы рекомендуем вам адаптировать его к своим торговым стратегиям. Удачного программирования, и пусть ваши советники говорят мудрые вещи!

Имя исходного файла Тип Версия Описание
tts_server.py серверный скрипт на Python 1 TTS-сервер на основе Flask, который получает текст по HTTP и озвучивает его с помощью встроенной функции синтеза речи PowerShell.
MA_Crossover_TTS_EA.mq5 Советник 1.10 Советник на пересечении скользящих средних с поддержкой речи и тестовым режимом. Отправляет динамические оповещения (сигналы, цены, время) на TTS-сервер.

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/21387

Прикрепленные файлы |
tts_server.py (1.32 KB)
Рыночные секреты Ларри Уильямса (Часть 5): Автоматизация стратегии волатильного пробоя на MQL5 Рыночные секреты Ларри Уильямса (Часть 5): Автоматизация стратегии волатильного пробоя на MQL5
В этой статье показано, как автоматизировать стратегию волатильного пробоя Ларри Уильямса в MQL5 с помощью практического пошагового подхода. Вы узнаете, как оценивать расширение дневного диапазона, определять уровни входа на покупку и продажу, управлять риском с помощью стопов на основе диапазона и целей по прибыли на основе соотношения риск/прибыль, а также разработать профессиональный советник для MetaTrader 5. Материал предназначен для трейдеров и разработчиков, которые хотят превратить торговые идеи Ларри Уильямса в полностью тестируемую и готовую к развертыванию автоматическую торговую систему.
Архитектура прибыльной торговли с усиленной многоуровневой защитой счёта Архитектура прибыльной торговли с усиленной многоуровневой защитой счёта
В этом материале мы представляем структурированную многоуровневую систему защиты, нацеленную на достижение амбициозных показателей прибыли при одновременном снижении риска катастрофических потерь. Основное внимание уделяется сочетанию агрессивной торговой логики с защитными механизмами на каждом этапе торгового процесса. Идея состоит в том, чтобы создать советника, который ведёт себя как «хищник, осознающий риск»: способен находить торговые возможности с высоким потенциалом, но всегда имеет несколько защитных слоёв, не позволяющих системе «ослепнуть» при внезапном рыночном стрессе.
От начального до среднего уровня: FileSave и FileLoad От начального до среднего уровня: FileSave и FileLoad
В сегодняшней статье рассмотрим некоторые способы работы с библиотечными функциями FileSave и FileLoad. Хотя многие считают их малоперспективными из-за некоторых ограничений или трудностей, которые они вызывают в определенных сценариях, правильное понимание того, как работают эти две функции, может сэкономить нам много работы в определенные моменты. Кроме того, они являются отличным способом работы с лог-файлами.
Рыночные секреты Ларри Уильямса (Часть 4): Автоматизация краткосрочных свинговых максимумов и минимумов в MQL5 Рыночные секреты Ларри Уильямса (Часть 4): Автоматизация краткосрочных свинговых максимумов и минимумов в MQL5
Освойте автоматизацию краткосрочных свинговых паттернов Ларри Уильямса с помощью MQL5. В этом руководстве мы разработаем полностью настраиваемого советника (Expert Advisor, EA), использующего неслучайные рыночные структуры. Мы рассмотрим, как интегрировать надежное управление рисками и гибкую логику выхода, создав прочную основу для системной разработки и бэктестирования торговых стратегий.