English Русский Deutsch
preview
MQL5取引ツールのアクセシビリティ課題を克服する(第2回):Pythonのテキスト読み上げエンジンでEAを音声対応にする

MQL5取引ツールのアクセシビリティ課題を克服する(第2回):Pythonのテキスト読み上げエンジンでEAを音声対応にする

MetaTrader 5 |
21 0
Clemence Benjamin
Clemence Benjamin

内容


はじめに

SF映画では、ロボットが話す場面をよく目にします。そして、それは自然に感じられます。音声によるやり取りによって、人間とロボットの相互作用は直感的になります。ユーザーは、機械が何をしているのかを、聞くだけで簡単に理解できます。今日の目的は、トレーダーとそのエキスパートアドバイザー(EA)パートナーの間に存在する大きなギャップを解決することです。これまでのシステムが提供してきた支援は非常に優れていますが、多くの場合、ビープ音、ポップアップ通知、またはテキストログの記録という形に限定され、柔軟性に欠けています。現在および将来のシステムをより効率的で利用しやすいものにするためには、より広い可能性を考え、システムをさらに進化させる必要があります。

アクセシビリティは、多くのトレードツールにおける課題です。視覚的な情報を十分に確認できるユーザーであっても、そうでないユーザーであっても同じです。すべてのユーザーが、EAが現在何をしているのか、または過去に何をしたのかを確認するために、常にログやジャーナルを開く時間があるわけではありません。重要なイベントをシステムが直接音声で伝えてくれる方が、はるかに効率的な場合があります。既存の解決策もありますが、その多くは固定的です。つまり、事前録音されたWAVファイルを使用する方式であり、市場状況の変化に応じて内容を変更することはできません。2020年11月11日、Alexander FedosovはMQL5における音声通知についての記事を公開しました。この内容は詳細に説明されています。しかし、この方式に残る課題の1つは柔軟性です。それぞれの音声を事前に準備する必要があり、EAは録音されていない内容を話すことができません。今回はTTS技術を活用し、EAが変化する市場状況について動的に話せるようにします。これにより、より大きな柔軟性を得ることができます。

この開発の主な利点を整理すると、以下のようになります。

  1. WAVファイルなどの音声リソースを作成する代わりにTTS技術を利用することで、開発時間を短縮できる
  2. 音声通知の硬直性を減らし、動的で状況に応じた通知を可能にする
  3. EAは、単純な内部アラートよりもはるかに詳細な情報を音声で提供できる
  4. ユーザーとEAの高度な対話への道を開く(例:音声による確認、音声サマリー)

以下は、この仕組みと開発コンセプトを示すフロー図です。

図1:音声フロー

上記の図は、このアプローチのシンプルな構造を示しています。MetaTrader 5内で動作するEAは、市場イベントを検出する頭脳として機能します。対象となるイベントは、移動平均線のクロス、テイクプロフィット到達、証拠金警告などです。固定されたWAVファイルを再生する代わりに、EAは現在価格、銘柄名、正確な時刻、その他選択した変数など、リアルタイム情報を含む動的なテキストメッセージを作成します。このテキストメッセージは、MQL5のWebRequest関数を使用したHTTP POSTリクエストによって、同じコンピュータ上で動作するローカルPythonサーバーへ送信されます。Pythonサーバーは音声合成処理を担当し、受信したテキストをテキスト読み上げエンジンで処理し、コンピュータのスピーカーから即座に音声として再生します。一連の処理は数ミリ秒で完了します。その結果、重要なタイミングで、必要な情報を平易な英語で伝えてくれるトレードパートナーを実現できます。

このアーキテクチャの強みは、役割分担が明確である点です。EAは、市場監視、ロジック実行、意味のあるアラート生成という、本来得意とする処理に集中します。Pythonサーバーは、MQL5単体では実現が難しい音声合成処理を担当します。単純なHTTPインターフェースによって2つの技術を接続することで、両方の利点を活用できます。MQL5の取引ターミナルとの密接な統合と、強力なTTSエンジンを含むPythonの豊富なライブラリエコシステムです。さらに、この設計は完全にローカルで動作します。データがコンピュータ外部へ送信されることはなく、プライバシーとセキュリティを確保しながら、遅延も排除できます。

コンセプトを理解したところで、実際の構築に進みます。次の実装セクションでは、以下の手順を順番に説明します。まず、Python環境を設定し、TTSサーバーを作成します。次に、再利用可能なSpeak()関数を備えたMQL5 EAを開発します。そして、WebRequestを有効化し、MetaTrader 5でローカルHTTP通信を設定します。その後、すべてを統合した移動平均クロスEAを確認します。このEAには、すぐに動作確認できるテストモードも含まれています。最後に、テスト結果、一般的な問題の解決方法、そしてこの基盤をさらに発展させるためのアイデアについて説明します。

経験豊富なMQL5開発者であっても、これから始める方であっても、本記事はEAをより対話的で、利用しやすく、インテリジェントなものにするための新しいツールを提供します。では始めます。



実装

このセクションでは、完全なシステムを段階的に構築していきます。まず、受信メッセージを待機するPython TTSサーバーを設定します。次に、WebRequest関数を使用してそれらのメッセージを送信するMQL5 EAを開発します。EAを使用する理由は、WebRequestがインジケータから呼び出せないためです。例として使用するEAは、アイデアを説明するための単純な移動平均クロスオーバーEAですが、Speak()関数は既存のEAにも簡単に適用できます。

Python環境の準備

Pythonをインストールする必要があります(バージョン3.7以降)。ターミナルを開き、必要なライブラリをインストールします。

pip install flask pyttsx3

Flaskは軽量なWebサーバーとして使用し、pyttsx3はシステムの音声を利用したオフラインのテキスト読み上げを提供します。

TTSサーバーの作成

localhostのポート5000でFlaskサーバーを実行するPythonスクリプトを作成します。このサーバーは、読み上げるテキストを含むJSON形式のPOSTリクエストを受け取ります。複数のメッセージが短時間に連続して到着する可能性があります(例:ウェルカムメッセージの直後にテストメッセージが送信される場合)。そのため、スレッド間の競合を避ける必要があります。このサーバーでは、キューと単一のワーカースレッドを使用して、メッセージを1つずつ処理します。各メッセージでは、新しいpyttsx3エンジンインスタンスを作成します。これは、初期の試行で発生した「run loop already started」エラーを防ぐためです。

Python TTSサーバー

このサーバーは、MQL5 EAとWindowsのテキスト読み上げエンジンの間を接続する役割を持ちます。HTTP POSTリクエストを待機し、受信したメッセージをキューに追加し、バックグラウンドスレッドを使用して1つずつ処理します。この設計により、複数のアラートが短時間に到着した場合でも、重複やクラッシュを発生させることなく、順番に読み上げることができます。

1. 必要なモジュールのインポート

まず、必要なPythonライブラリをインポートします。FlaskはHTTPリクエストを処理するための軽量Webフレームワークです。Queueは、受信メッセージを管理するためのスレッドセーフなFIFOキューを提供します。Threadingは、Webサーバーを停止させることなく音声合成をバックグラウンドスレッドで実行するために使用します。SubprocessはPowerShellコマンドの実行に使用し、Shlexは安全なコマンドライン引数処理を補助します(ここでは必須ではありませんが、完全性のために含めています)。

Pythonコード

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

2. Flaskアプリケーションとメッセージキューの初期化

Flaskアプリケーションのインスタンスと、グローバルなmessage_queueを作成します。このキューには、読み上げる必要があるテキスト文字列が保存されます。プロデューサー(HTTPエンドポイント)はメッセージをキューへ追加し、コンシューマー(ワーカースレッド)はキューからメッセージを取得して処理します。これにより、受信リクエストと実際の音声合成処理が分離され、Webサーバーの遅延やブロックを防ぎます。

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_workertts_worker関数を実行するデーモンスレッドを作成します。daemon=Trueを設定すると、メインプログラム終了時にスレッドも自動的に終了します。これにより、Ctrl+Cでサーバーを停止した際に、不要なスレッドが残ることを防ぎます。

Pythonコード

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

6. メッセージ受信用HTTPエンドポイント

このFlaskルートは、/speakパスでPOSTリクエストを待機します。リクエストを受信すると、JSONデータを取得し、textフィールドが存在するか確認します。フィールドが存在しない場合は400エラーを返します。存在する場合、テキストをメッセージキューへ追加し、即座に成功レスポンス({"status": "ok"})を返します。実際の音声処理はバックグラウンドスレッドでおこなわれるため、このエンドポイントは高速に動作し、EAを待機させません。

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)

EA側の準備

MetaEditorで、新しいEAを作成します。中心となる関数はSpeak()です。この関数はJSONペイロードを作成し、WebRequestを使用して送信します。MetaTrader 5ターミナルで、URL「http://127.0.0.1:5000/speak」を許可URLリストへ追加する必要があります。([ツール]→[オプション]→[エキスパートアドバイザ]→[WebRequestを許可するURLリスト])。

Webリクエスト設定

図2:サーバーリンクの設定

テストモード付きクロスオーバーEAの構築

システムをすぐに確認できるように、「TestMode」入力項目を追加します。このモードを有効にすると、EAは新しいバーごとに、現在の銘柄、Bid/Ask価格、サーバー時刻を含むテストメッセージを音声で読み上げます。これにより、EAがリアルタイムデータへアクセスできること、そしてクロスオーバーシグナルを待つことなくTTSパイプラインが正常に動作することを確認できます。クロスオーバーロジック自体は、2本の移動平均線とATR値を使用して状況を判断します。クロスオーバーが発生すると、EAはシグナル方向、価格、ATRを含む詳細なアラートを音声で通知します。

このEAは、一般的な移動平均クロスオーバー戦略を実装し、ローカルPython TTSサーバーを介して動的なメッセージを音声で伝える機能を追加しています。また、即時確認のためのテストモード、任意の売買機能、WebRequestに対する堅牢なエラー処理も含まれています。コードは分かりやすく構成されており、自分自身の戦略へ簡単に適用できるよう設計されています。

1. EAヘッダーとメタデータ

EAは、標準的なMQL5メタデータから開始します。これには、著作権、リンク、バージョン、簡単な説明が含まれます。この情報は、ナビゲータ上やEAをチャートへ適用した際に表示されます。説明文には、このEAが音声対応であり、テストモードを含んでいることが明確に示されています。

//+------------------------------------------------------------------+
//|                                          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期間、そして計算方法が含まれます。2つ目のグループでは、音声通知と売買動作を制御します。ここでは、音声機能の有効化、実際の取引の有効化、ロットサイズ、固有のマジックナンバーを設定します。最後に、TestModeでは、EAが新しいバーごとにテストメッセージを音声で読み上げるように設定できます。これは、クロスオーバーシグナルを待つことなく、すぐに動作確認をおこなうために非常に有効です。

// --- 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は、同じバー上でEAが重複したシグナルを発生させることを防ぎます。

// --- 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のインジケータハンドルを作成します。いずれかのハンドル作成に失敗した場合、EAは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()

EAがチャートから削除された場合、システムリソースを解放するために、すべてのインジケータハンドルを解放する必要があります。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を比較することでおこないます。両者が同じ場合は、すぐに処理を終了します。これにより、すべての処理は1バーにつき1回だけ実行され、効率が向上するとともに、過剰なWebRequest呼び出しを防ぎます。

新しいバーが検出された場合、lastBarTimeを更新します。そして、TestModeと音声通知が有効になっている場合は、SpeakTestInfo()を呼び出して、現在の銘柄、Bid/Ask価格、サーバー時刻を音声で通知します。これにより、EAが稼働していること、そして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. クロスオーバー検出のためのインジケータ値取得

新しいバーの処理後、直前のバー(インデックス1)と、その前のバー(インデックス2)について、短期移動平均線、長期移動平均線、ATRの値を取得します。配列は系列形式として設定し、インデックス0が最新データを示すようにします。移動平均線については2つの値をコピーし、ATRについては1つの値をコピーします。いずれかの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値を含む詳細な音声メッセージを作成します。このメッセージはSpeak()を通じてTTSサーバーへ送信されます。取引が有効になっている場合は、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が有効になっているときに呼び出されます。SymbolInfoDouble()を使用して現在のBid価格とAsk価格を取得し、TimeCurrent()によって現在のサーバー時刻を取得します。取得した時刻は、読みやすい形式の文字列に変換され、その後テストメッセージを作成します。作成されたメッセージは、Speak()を通じてTTSサーバーへ送信されます。この関数により、EAがリアルタイムの市場データへアクセスし、それを音声へ変換できることを確認できます。

//+------------------------------------------------------------------+
//| 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形式を維持するためにダブルクォートをエスケープします。その後、WebRequest()を使用してローカルTTSサーバーへHTTP POSTリクエストを送信します。

タイムアウトは3秒に設定します。これはローカル接続に対して十分な時間です。WebRequest()が-1を返した場合は、GetLastError()を使用してエラーコードを取得し、表示します。一般的なエラーには、MetaTrader 5の設定でURLが許可されていない場合のエラー4060とサーバーが起動していない場合の接続拒否エラー4062があります。失敗時にはfalseを返すことで、呼び出し元のコード側でエラー処理方法を決定できます。この関数は、音声機能を追加するために、他のEAへそのままコピーして使用できます。

//+------------------------------------------------------------------+
//| 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構造体に、必要な情報を設定します。これには、アクション、銘柄、数量、マジックナンバー、許容スリッページが含まれます。価格は、BUY注文の場合は現在のAsk価格、SELL注文の場合は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の有効化と実行

EAを適用する前に、ターミナルでPythonサーバーを起動します。:python tts_server.py。その後、MetaTrader 5でURLが許可されていることを確認します。EAを任意のチャート(例:EURUSD M1)へ適用し、TestMode=trueおよびEnableVoiceAlerts=trueに設定します。毎分、テストメッセージが音声で再生されるはずです(これは動作確認用です。すべてのバーで継続的に通知されるため、通常使用では無効にしてください)。クロスオーバーが発生した場合は、そのアラートも音声で通知されます。


テスト

ビデオデモ:動画デモでは、Python TTSサーバー(コマンドプロンプト)、XAUUSDmicroへEAを適用したMetaTrader 5ターミナル、再コンパイル中のMetaEditorの3つのウィンドウを表示しています。初期化時、EAは動的なBid/Ask価格とサーバー時刻を含むテストメッセージを音声で通知します。これにより、TTSパイプラインが即座に動作することを確認できます。動画では、合成Boom 900インデックス上でEAを動作させる例も示しています。同じ動的情報を問題なく音声で通知しており、あらゆる取引銘柄との互換性を確認できます。クロスオーバーシグナルを待つ通常の時間があるにもかかわらず、EAは複数の機能を効率的に伝達します。具体的には、移動平均クロスオーバーが発生すると通知する機能、有効化されている場合は取引を実行する機能、市場状況についてリアルタイムの音声フィードバックを提供する機能です。

システムは、XAUUSDmicroを使用した1分足チャートのデモ口座で広範囲にテストしました。最初の実装では、共有したpyttsx3エンジンを使用していましたが、2回目のメッセージ後に「run loop already started」というエラーで停止しました。その後、各メッセージごとに新しいエンジンを作成するキュー方式のワーカーへ変更したことでクラッシュは解決しました。しかし、数回メッセージを処理すると音声が停止し、コンソール上ではメッセージを受信し続けている状態になりました。これは、Windows環境におけるpyttsx3エンジン内部の問題を示していました。

最終的な安定した解決策では、PowerShellに組み込まれている音声合成機能を使用します。現在のPythonサーバーは、各メッセージごとに短いPowerShellコマンドを実行し、System.Speech.Synthesis.SpeechSynthesizerを呼び出します。この方式は非常に安定しています。すべてのメッセージが明確に順番通り読み上げられ、クラッシュや無音状態は発生しません。サーバーログでは各リクエストが正常に処理され、スピーカーからすべてのテストメッセージとクロスオーバーアラートが正常に再生されます。

また、WebRequestのエラーコードが正しく表示されることも確認しました。サーバーが起動していない場合、MetaTrader 5はエラー4062(接続拒否)を返します。URLが許可されていない場合、エラー4060が表示されます。どちらも簡単に原因を確認し、修正できます。

テストモードは、即時確認のために非常に有効でした。EAを適用して数秒以内に、「Test on XAUUSDmicro: Bid … Ask … at …」という音声を聞くことができ、データ取得、JSON形式への変換、TTSパイプラインがすべて正常に動作していることを確認できました。数分後には実際のクロスオーバーが発生し、EAは、「BUY signal on XAUUSDmicro at price … ATR is …」と通知をしました。このシステムは、複数の取引銘柄で問題なく動作しました。Boom 900インデックスのような合成インデックスでも確認でき、この音声対応アプローチがあらゆる取引ペアに適用可能であることを示しています。



結論

Python、MQL5、そしてテキスト読み上げ(TTS)技術を活用し、音声対応のトレードシステムを構築することに成功しました。このEAは現在、ローカルPython TTSサーバーを使用して、価格、シグナル、口座状況など、あらゆる動的情報をリアルタイムで音声通知できます。主な成果は以下のとおりです。

  • 事前録音された音声リソースが不要になり、EAは任意の内容を話すことができるようになった。
  • キューベースのワーカーによってスレッド問題を解決し、最終的に非常に安定したPowerShell方式を採用した。
  • どのMQL5 EAにも組み込める再利用可能なSpeak()関数を提供した。
  • シグナルを音声通知し、さらに各バーでテスト情報を読み上げることができる、完全に動作する移動平均クロスオーバーEAによって、この概念を実証した。
このシステムの利点は、単なる技術的な達成を超えています。この仕組みにより、以下が可能になります。
  • 画面を常に見続ける必要がなくなる:重要な情報はすべて音声で届けられるため、ターミナルから離れていても市場の動きを把握できます。
  • 真のアクセシビリティを実現できる:完全な音声対応により、視覚に制限があるトレーダーも、音声通知を通じてリアルタイムの市場情報を理解でき、取引の自立性を高めることができます。
  • マルチタスク能力を向上できる:耳が追加の情報チャネルになります。チャート分析中、ニュースを読んでいる時、またはデスクから離れている時でも、EAが音声によって情報を提供し続けます。
  • 固定的な音声制限をなくす:WAVファイルを探したり録音したりする必要はありません。EAは、任意の価格、任意のタイミング、任意の変数を即座に動的に読み上げることができます。

今後、この基盤には多くの可能性があります。Pythonサーバーを拡張し、音声選択、読み上げ速度、音量などの追加パラメータを受け取れるようにしたり、音声をリモートデバイスへストリーミングしたりできます。また、EAをMCPサーバーと統合することで、双方向の音声コマンドも実現できます。トレーダーがEAへ話しかけ、EAが応答する仕組みです。同じ技術を利用して、日次パフォーマンスの音声サマリー、リスク通知、ニュースヘッドラインの読み上げなども作成できます。

次の段階は何でしょうか。今回達成したのは、一方向のコミュニケーションです。つまり、EAがあなたに話しかける仕組みです。次の段階は、双方向の音声対話です。そこでは、あなたがEAに話しかけ、EAが内容を理解してコマンドを実行できるようになります。たとえば、「すべての含み損ポジションを閉じて」または「ロットサイズを0.5に増やして」と言うだけで、EAが即座に応答することを想像してください。これはもはやSFの話ではありません。これは、アクセシブルなトレーディング技術が自然に進化していく方向です。

次回の記事では、音声認識とTTS技術を使用したアクセシビリティ向上のさらなる可能性について紹介します。トレードの未来は音声によって操作されるものへ向かっており、あなたは今、その最初の一歩を踏み出しました。

この記事が、ご自身のEAをより利用しやすく、より対話的なものへ発展させるきっかけになることを願っています。完全なソースコードは以下に提供されています。ぜひ自身のトレーディング戦略へ適用してください。楽しいコーディングを。そして、あなたのEAが賢く語ってくれますように。

ソースファイル名 種別 バージョン 説明
tts_server.py Pythonサーバースクリプト 1 HTTP経由でテキストを受信し、PowerShell標準の音声合成機能を使用して読み上げるFlaskベースのTTSサーバー
MA_Crossover_TTS_EA.mq5 EA 1.10 テストモードを備えた音声対応移動平均クロスオーバーEA。シグナル、価格、時刻などの動的アラートをTTSサーバーへ送信する

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/21387

添付されたファイル |
tts_server.py (1.32 KB)
取引規律をコードに組み込む(第2回):MQL5で口座全体の全取引に対応する日次取引制限エンフォーサーを構築する 取引規律をコードに組み込む(第2回):MQL5で口座全体の全取引に対応する日次取引制限エンフォーサーを構築する
取引ルールを遵守できるようにするため、1日の取引制限を強制するシステムを開発しました。このシステムは、口座全体で実行されたすべての取引を監視し、設定された制限に到達すると自動的に介入して、それ以降の取引活動を防止します。制御機能をプラットフォームに直接組み込むことで、市場からのプレッシャーが高まった状況でも、規律を維持できるようにします。
ラリー・ウィリアムズの『市場の秘密』(第13回):隠れスマッシュデー反転パターンの自動化 ラリー・ウィリアムズの『市場の秘密』(第13回):隠れスマッシュデー反転パターンの自動化
ラリー・ウィリアムズの隠れスマッシュデー反転を対象とした、透明性の高いMQL5エキスパートアドバイザー(EA)を構築します。シグナルは新しいバーの開始時のみ生成されます。まずセットアップバーを判定し、その次のセッションがその極値の外側でクローズしたことを確認してからシグナルを確定します。リスク管理では、ATRベースまたはストラクチャーベースのストップロスを選択でき、あらかじめ定義したリスクリワード比に基づいて利益確定を設定します。ポジションサイズは固定ロットまたは口座残高に対する割合から算出でき、さらに売買方向フィルタと「同時保有は1ポジションのみ」というルールを組み合わせることで、再現性の高いバックテストを実現します。
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
共和分株式による統計的裁定取引(最終回):特化型データベースを用いたデータ分析 共和分株式による統計的裁定取引(最終回):特化型データベースを用いたデータ分析
統計的裁定取引のデータ処理において、SQLite (OLTP)とDuckDB (OLAP)を組み合わせて活用する方法を紹介します。DuckDBのカラム指向エンジン、ASOF JOIN、配列関数を利用することで、気配値と約定の時点対応付けやRWEC (Rolling Windows Eigenvector Comparison)などの中核処理を高速化できます。実際の測定では、入力データが大きくなるにつれて、SQLiteと比較して2倍から23倍の高速化が確認されました。これにより、クエリはよりシンプルになり、分析処理も高速化される一方で、実際の取引執行は引き続きSQLiteに任せることができます。