[FX] MT5に喋らせる

MT4,MT5には、設定した価格に到達した、売買を行ったなどで、アラート音を出す機能は標準でついてます。
さまざまな音を出すには、インストール先のSounds フォルダ内に好みのwavファイルを入れて、PlaySoundで音を出すこともできます。
しかし、いちいちwavファイルを作成するのは面倒になったので、もう少し柔軟な方法がないか、いろいろネットで調べてみたら、比較的簡単な方法で実現できました。
まあ、ちょっと強引な方法ですが……

参考にしたのは、ここです
https://qiita.com/Pavaux/items/e51ebe991d8a8297a93d

Windowsについている、SAPI.SpVoice を使います。
スクリプトを作成しておいて呼び出す、というものですが、これをそのまま流用して、しゃべらせます。

手順としては、
1.スクリプトファイルを作成する
2.スクリプトを呼び出す
これだけです。

スクリプトはあらかじめ作成してどこかに置いても良いのですが、それも面倒なので、OnInit()内でファイルを作成して置くことにしました

まず、必要なdllをimportします

#import "kernel32.dll"
   int CreateFileW(string, uint, int, int, int, int, int);
//   int GetFileSize(int, int);
//   int ReadFile(int, uchar&[], int, int&[], long);
   int WriteFile(int, uchar&[], int, int&[], long);
   int CloseHandle(int);
//   bool DeleteFileA(string);
//   bool GetFileTime(int, ulong&, ulong&, ulong&);
#import

#import "shell32.dll"
int ShellExecuteW(int hwnd,string Operation,string File,string Parameters,string Directory,int ShowCmd);
#import

設定するパラメーターを指定します

input string SoundScriptFileDirectory = "c:\\Temp"; //スクリプトファイルを置く場所
input string Filename = "saysignal.js"; //スクリプトファイル名
input int Language = 411; //言語 411:Japanese 409:English
input double Speed = 0.7; //速度
input int Volume = 20; //音量
input int Gender = 0; //性別 0:male 1:female

次にOninit()内で実行するスクリプトファイルを作成し、
音が出るかテストします
全部まとめたものは以下になります。

//+------------------------------------------------------------------+
//|                                                    VoiceTest.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window


#import "kernel32.dll"
   int CreateFileW(string, uint, int, int, int, int, int);
//   int GetFileSize(int, int);
//   int ReadFile(int, uchar&[], int, int&[], long);
   int WriteFile(int, uchar&[], int, int&[], long);
   int CloseHandle(int);
//   bool DeleteFileA(string);
//   bool GetFileTime(int, ulong&, ulong&, ulong&);
#import

#import "shell32.dll"
int ShellExecuteW(int hwnd,string Operation,string File,string Parameters,string Directory,int ShowCmd);
#import

input string SoundScriptFileDirectory = "c:\\Temp"; //スクリプトファイルを置く場所
input string Filename = "saysignal.js"; //スクリプトファイル名
input int Language = 411; //言語 411:Japanese 409:English
input double Speed = 0.7; //速度
input int Volume = 20; //音量
input int Gender = 0; //性別 0:male 1:female



void OnInit()
  {
   //......
   MakeScriptFile();
   if( Language==411 )
      VoiceOut("この音量で流れます"); //音が出るかテストする
   else
      VoiceOut("It plays at this volume");
   //......
  }
  
void MakeScriptFile()
  {
   string MaleFemale;
   if( Gender==0 )//&& Language!=411 )
      MaleFemale = "Male";
   else
      MaleFemale = "FeMale";

   string commandString = "var args = [];\r\n";
   commandString += "for (var i = 0; i < WScript.Arguments.length; i++) {\r\n";
   commandString += "  args.push(WScript.Arguments.Item(i));\r\n";
   commandString += "}\r\n";
   commandString += "try {\r\n";
   commandString += "  var sapi = new ActiveXObject('SAPI.SpVoice');\r\n";
   commandString += " sapi.Volume = "+IntegerToString(Volume)+";\r\n";
   commandString += "  sapi.Rate = "+DoubleToString(Speed,1)+";\r\n";
   commandString += " sapi.Voice = sapi.GetVoices(\"Language="+IntegerToString(Language)+"; Gender="+MaleFemale+"\")(0)\r\n";
   commandString += " sapi.Speak(args.join(' '));\r\n";
   commandString += "} catch (e) {\r\n";
   commandString += "// WScript.Echo(\"Error: \" + e.message);\r\n";
   commandString += "} finally {\r\n";
   commandString += " sapi = null;\r\n";
   commandString += " WScript.Sleep(100);\r\n";
   commandString += "}\r\n";

   string fn = SoundScriptFileDirectory + "\\" + Filename;

   int Handle = CreateFileW(fn, 0x40000000 /*GENERIC_WRITE*/, 3 /*SHARE READ|WRITE*/, 0, 2 /*CREATE_ALWAYS*/, 0, 0);

   if( Handle>=0 ) {
      string writeString = commandString;
      uchar buffer[];
      int size = StringToCharArray(writeString,buffer,0,-1,0);
      
      int write[1];
      WriteFile(Handle,buffer,size-1,write,0);
   
      if( (size-1)!=write[0] )
        {
         Print("File Write Error ",fn); 
         CloseHandle(Handle);
         return;
        }
    
      CloseHandle(Handle);
   }     
  }

void VoiceOut(string s)
{
   string command;
   command = SoundScriptFileDirectory + "\\" + Filename + " " + s;
   ShellExecuteW(0,"open","wscript",command,"",2);
}


//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

かなり強引です。。
スクリプトの内容は上記のそのままです。
もっとエレガントな方法がないか?と思っていて、
良い方法があれば知りたいです。

スクリプトファイルは、好きな場所においてください。
但しMT5のフォルダ内に置くと動作しません。なぜなのか?理由はわかりません(調べてないです)

Windowsの環境に依るのかもしれませんが、言語や性別によって、しゃべらない組み合わせもあるので、いろいろ試してみてください。
いくつかのPCで試したところ、確実にしゃべるのは日本語(411)、英語(409)の女性(Female)でした。

MT4では、
int WriteFile(int, uchar&[], int, int&[], long);
の最後のlongをintにすれば動作するようです。
int WriteFile(int, uchar&[], int, int&[], int);

プログラミングの専門家ではないので、コードに見苦しいところがあるかと思いますが、ご容赦ください。


いいなと思ったら応援しよう!