見出し画像

MQLでMT4・MT5の全体キャプチャを利用する方法



実装イメージ

今回はMT4・MT5の全体画像の活用を考えます。今回は下記のようにLINE通知・Discord通知で送る際の問題点に関して考えてみます。

※通知を送るところまでの実装方法は記載しません。

🔺イメージ画像
(例:Discord通知に全体画像を送付)

チャート1枚分の画像通知であれば、関数を使えば可能なんですが、MT4・MT5全体の画像をキャプチャできる関数って無いんですよね。。。((+_+))

手動であればもちろん可能ですが、どうせプログラミングの知識があるなら意地でも自動化したいじゃないですか。

ということで、Windowsのスクリーンショット機能を内蔵することで可能にさせました。

(Winキー + ALTキー + PrintScreenキー)でキャプチャしたものをLine・Discordに送ることにしました。

①キーボードのキー操作を利用しよう

まず、MQL内に(Winキー + ALTキー + PrintScreenキー)でキャプチャする機能を実装します。

Yahoo知恵袋を参考にさせていただきました。

キー操作をする関数は以下の通りです。("#"は半角に直してください。

"#"include <WinUser32.mqh>
"#"define VK_SNAPSHOT 0x2C
"#"define VK_LWIN 0x5B

void ScreenShot(void)
{
 keybd_event(VK_LWIN, 0, 0, NULL);//左Windowsキーを押す
 keybd_event(VK_SNAPSHOT, 0, 0, NULL);//PrintScreenキーを押す
 keybd_event(18, 0, 0, 0); //Altキーを押す
 keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_KEYUP, NULL);//PrintScreenキーを離す
 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, NULL);//左Windowsキーを離す
 keybd_event(18, 0, KEYEVENTF_KEYUP, 0); //Altキーを離す
}

キー操作を行う場合は定義されたキーコードを指定すればOKです。
キーコードの一覧は下記を参照しましょう。

上記で作成した関数「ScreenShot()」を実行すればスクリーンショットを撮ることができるようになります。

別途ショートカットキーの機能を実装して、そこから「ScreenShot()」を実行すればショートカットキーでスクリーンショットを撮ることもできますね。

ただし、このままだとアクティブウィンドウ化されません。
アクティブ化せずに実行する場合は別のスクリーンショットが作成されるので注意が必要です。
(別作業中での実行はアクティブウィンドウ化する必要あります。)

👉画面のアクティブ化

作業PCにて、アラート時にスクリーンショットを撮りたい場合は、下記の方法でアクティブ化しましょう。("#"は半角に直してください。

"#"import "user32.dll"
int  BringWindowToTop(int hWnd);
int  GetParent(int hWnd);
void SwitchToThisWindow(int hWnd,bool flag);
int ShowWindow(int hWnd,int nCmdShow);
int  GetForegroundWindow();
int IsZoomed(int hWnd);
"#"import

void ChartActivate(bool MT4Activate = true)
  {
   int hwnd = GetParent(WindowHandle(Symbol(),Period()));
   if(MT4Activate)
     {
      int htop = GetParent(GetParent(hwnd));
      if(GetForegroundWindow() !=htop)
         SwitchToThisWindow(htop,true);
      if(!IsZoomed(htop))
         ShowWindow(htop,1);
     }
   BringWindowToTop(hwnd);//MDI内でのアクティブ化
  }

下記を参考にさせていただきました。

②ファイルを送信しよう

更にLINE通知・Discord通知に利用したいって話になるとファイルを送信する機能が必要になります。

上記で撮ったスクリーンショットを送る部分の関数を作成すればOKですが、送信方法はcurlで送る方法以外、自分はよくわからないので以下の内容に関してはcurlを使うことを前提とします。

とはいえ、画像ファイルパスを指定してcurlを実行すれば良いだけなのですが、、、問題にぶつかりました。

👉問題点について

(問題点)
・デフォルトの保存場所はMQLからは基本的に参照できない
・デフォルトのファイル名がプログラミング的に非常に易しくない

この辺にピンとくる人なら、ここまでの内容で大丈夫だと思います。

以下は自分と同じ問題にぶつかった人向けにヒントですが、

スクリーンショットがデフォルトで保存される場所はあらかじめ設定されてますが、セキュリティの観点から特定の範囲(MQLx¥Files配下)以外を参照しようとしてもMQLではできないみたいです。

デフォルトのファイル名に関しては「アクティブウィンドウの名称」+「タイムスタンプ」になってます。規則的と言えば一応規則的ですが、これは正直なところ開発者目線には全く易しくない・・・どころか、そのままだと使えるファイル名と使えないファイル名がごちゃ混ぜになります。

例えばですが、
全角文字/半角文字の混在
文字数が不定
ファイル名の先頭文字に使えない文字が入る
、などなど・・・

👉突破方法について

上記問題をどうクリアするか、結果として自分が思いついた突破方法は下記のとおりです。

(突破方法)
・参照できる場所に変更する
・ファイル名を変更する
・変更したファイル名を使用する

普通っちゃ普通のことなんですが、この普通のことができるようになるまで時間を要しました。突破方法は実装するうえで必要なSTEPになりますので、以下解説していきます。

🔻step1. 参照できる場所に変更する

(Winキー + ALTキー + PrintScreenキー)で保存されるデフォルトの保存先を変更する必要があります。

デフォルトの保存先ですが、特にいじってないのでしたら下記になるかと思います。(※OneDriveへ保存している方は連携を切る必要があります‼)

>> C:\Users\(自分のPC名)\Videos\Captures

この[Captures]のパスを下記🔽のように変更する必要があります。

>> C:\Users\(自分のPC名)\~\Terminal\xxxxxxx\MQL4\Files\Captures

保存先を変更する方法は以下の通り。

保存先の「キャプチャ」フォルダを特定し、
①「右クリック」⇒「プロパティ」選択
②「場所」タブよりパス名を編集できます。

🔺上記の箇所を先のパスの形に書き換える

当たり前ですが、パスを書き換えた後、スクリーンショットはここへ保存されていきますので忘れないようにしましょう‼‼

🔻step2. ファイル名を変更する

保存されていくスクリーンショット名は以下のイメージです。

🔺イメージ

こんな感じで「アクティブウィンドウの名称+タイムスタンプ」という名称で保存されていきます。

MT4・MT5を稼働させている場合、イメージ画像のように口座番号が頭についていることが多く、その場合ファイル名称の頭が数字から始まってしまいます。

また半角スペースも混ざりますので、その辺を考慮した作りが必要になってきます。

必要なければ無いで良いですが、ファイル名称を変更した方が色々と都合が良かったので自分は変更することにしました。

下記の関数で変更します。

bool  FileMove(
   const string  src_file_name,    // 移動するファイル名
   int           common_flag,      // 場所フラグ
   const string  dst_file_name,    // 移動後のファイル名
   int           mode_flags        // アクセスモード
   );

引数の「xxxx_flag」に関しては必要があればセットしてください。必要なければ下記のように「0」で機能します。

FileMove(source_filename,0,target_filename,0);

引数1(source_filename)でスクリーンショットのファイル名、引数3(target_filename)に変更後の扱いやすい名前を入れてあげればOKです。

スクリーンショットのファイル名の特定の仕方ですが、末尾のタイムスタンプを利用すれば良いかと思います。

少し面倒くさいというか力業ですが、こんな感じです。

datetime StringToDatetime(string filename)
  {
   datetime timestamp;
   int len_1;
   int len_2;

   if(TimeHour(TimeLocal()) > 9)
     {
      len_1 = StringLen(filename) - 23;
      string filename_timestamp = StringSubstr(filename,len_1,23);
      timestamp = StringToTime(StringSubstr(filename_timestamp,0,4) + "."
                               + StringSubstr(filename_timestamp,5,2) + "."
                               + StringSubstr(filename_timestamp,8,5) + ":"
                               + StringSubstr(filename_timestamp,14,2) + ":"
                               + StringSubstr(filename_timestamp,17,2));
     }
   else
     {
      len_2 = StringLen(filename) - 22;
      string filename_timestamp = StringSubstr(filename,len_2,22);
      timestamp = StringToTime(StringSubstr(filename_timestamp,0,4) + "."
                               + StringSubstr(filename_timestamp,5,2) + "."
                               + StringSubstr(filename_timestamp,8,3) + "0"
                               + StringSubstr(filename_timestamp,11,1) + ":"
                               + StringSubstr(filename_timestamp,13,2) + ":"
                               + StringSubstr(filename_timestamp,16,2));
     }
   return(timestamp);
  }

パターンが2つあるのは、タイムスタンプが常に(YYYY_MM_DD HH_MM_SS)の形にはならないからということです。

「TimeHour(TimeLocal()) > 9」が答えですが、0時~9時の場合、「00~09」の表記ではなく「0~9」の表記になってます。桁数が変わるので注意が必要です‼️

この関数を実行してあげれば、スクリーンショットのタイムスタンプを(YYYY:MM:DD HH:MM:SS)の形に統一できます。

後は、変更したファイル名を指定してFILE送信とかすればLINE通知・Discord通知へ活用することが可能になります。

送る方法は下記を参考にしてみてください。

curl箇所はLINEしか載せてないですが、実装方法はDiscordも同じです。
(パラメータはDiscord用のcurlに直す必要あり。)

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