リソース

MQL5 プログラムでのグラフィック及び音声リソースの使用

MQL5 プログラムは音声及びグラフィックファイルの操作を可能にします。

 

PlaySound()

PlaySound() 関数呼び出しの例

//+------------------------------------------------------------------+
//| 標準的な OrderSend() を呼んで音を再生する                               |
//+------------------------------------------------------------------+
void OrderSendWithAudio(MqlTradeRequest  &request, MqlTradeResult &result)
 {
//--- サーバにリクエストを送信する
  OrderSend(request,result);
  //--- リクエストが受け入れられたら Ok.wav を再生する
  if(result.retcode==TRADE_RETCODE_PLACED) PlaySound("Ok.wav");
  //--- 失敗したら timeout.wav ファイルの警笛を鳴らす
  else PlaySound("timeout.wav");
 }

この例は標準端末パッケージに含まれている「Ok.wav」と 「timeout.wav」の音の再生の仕方を示します。これらのファイルは terminal_directory\Sounds フォルダに位置します。ここで terminal_directory は、MetaTrader 5 クライアント端末が起動されるフォルダです。terminal_directory の位置は、MQL5 プログラムから次のように 見つけることが出来ます。

//--- 端末データの格納フォルダ
  string terminal_path=TerminalInfoString(TERMINAL_PATH);

terminal_directory\Sounds フォルダだけでなくterminal_data_directory\MQL5 のサブフォルダの音声ファイルも利用可能です。端末データディレクトリは端末メニュの「ファイル」 -> 「データフォルダを開く」またはプログラムのメソッドを使用して見つけることが出来ます。

//--- 端末データの格納フォルダ
  string terminal_data_path=TerminalInfoString(TERMINAL_DATA_PATH);

例えば、Demo.wav 音声ファイルが terminal_data_directory\MQL5\Files に位置する場合、PlaySound() の呼び出しは次のように書かれるべきです。

//--- terminal_directory_data\MQL5\Files\Demo.wav を再生する
  PlaySound("\\Files\\Demo.wav");

コメントではファイルパスが「 \ 」バックスラッシュで書かれているのに比べ、関数では「 \\ 」が使用されているのにご注意ください。

単一のバックスラッシュはコンパイラがプログラムソースコードの定数文字列及び文字定数扱う際の制御シンボルであるため、パスの指定時は常にセパレータとして二重のバックスラッシュを使用します。

再生を停止するには PlaySound() 関数を NULL パラメータで呼び出します。

//--- PlaySound() の NULL パラメータトの呼び出しは再生を停止する
  PlaySound(NULL);

 

ObjectCreate()

ObjectCreate() 関数でグラフィックレベル(OBJ_BITMAP_LABEL)を作成するエキスパートアドバイザーの例

string label_name="currency_label";       // OBJ_BITMAP_LABEL オブジェクトの名称
string euro      ="\\Images\\euro.bmp";   // terminal_data_directory\MQL5\Images\euro.bmp ファイルへのパス
string dollar    ="\\Images\\dollar.bmp"; // terminal_data_directory\MQL5\Images\dollar.bmp ファイルへのパス
//+------------------------------------------------------------------+
//| エキスパート初期化に使用される関数                                        |
//+------------------------------------------------------------------+
int OnInit()
 {
//--- まだ作成されていなければ OBJ_BITMAP_LABEL ボタンを作成する
  if(ObjectFind(0,label_name)<0)
    {
    //--- OBJ_BITMAP_LABEL オブジェクト作成を試みる
    bool created=ObjectCreate(0,label_name,OBJ_BITMAP_LABEL,0,0,0);
    if(created)
       {
        //--- ボタンをチャートの左上にリンクする
        ObjectSetInteger(0,label_name,OBJPROP_CORNER,CORNER_RIGHT_UPPER);
        //--- オブジェクトプロパティを設定する
        ObjectSetInteger(0,label_name,OBJPROP_XDISTANCE,100);
        ObjectSetInteger(0,label_name,OBJPROP_YDISTANCE,50);
        //--- 直近エラーの値を 0 にリセットする
        ResetLastError();
        //--- ボタンの「押された」状態を示す画像をダウンロードする
        bool set=ObjectSetString(0,label_name,OBJPROP_BMPFILE,0,euro);
        //--- 結果をテストする
        if(!set)
          {
          PrintFormat("Failed to download image from file %s. Error code %d",euro,GetLastError());
          }
        ResetLastError();
        //--- ボタンの「押されていない」状態を示す画像をダウンロードする
        set=ObjectSetString(0,label_name,OBJPROP_BMPFILE,1,dollar);
       
        if(!set)
          {
          PrintFormat("Failed to download image from file %s. Error code %d",dollar,GetLastError());
          }
        //--- ティックがなくてもボタンが即時表示されるようにチャートにリフレッシュ指令を送る
        ChartRedraw(0);
       }
    else
       {
        //--- オブジェクト作成に失敗したので通知する
        PrintFormat("Failed to create object OBJ_BITMAP_LABEL. Error code %d",GetLastError());
       }
    }
//---
  return(INIT_SUCCEEDED);
 }
//+------------------------------------------------------------------+
//| エキスパート初期化解除に使用される関数                                    |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
 {
//--- チャートからオブジェクトを削除する
  ObjectDelete(0,label_name);
 }

OnInit() 関数で currency_label という名称のグラフィックオブジェクトが作成/設定されます。グラフィックファイルへのパスは euro 及び dollar グローバル変数 で設定され、二重のバックスラッシュが区切り文字として使用されます。

string euro      ="\\Images\\euro.bmp";   // terminal_dara_directory\MQL5\Images\euro.bmp ファイルへのパス
string dollar    ="\\Images\\dollar.bmp"; // terminal_dara_directory\MQL5\Images\dollar.bmp ファイルへのパス

ファイルは terminal_data_directory\MQL5\Images フォルダに位置します。

OBJ_BITMAP_LABEL オブジェクトは、実際にはボタンの状態(押されたまたは押されていない状態)に応じてeuro.bmp またはdollar.bmp を表示するボタンです。

OBJ_BITMAP_LABEL オブジェクトプロパティ

グラフィカルインターフェースとのボタンのサイズは自動的に画像の大きさに調整されます。画像は OBJ_BITMAP_LABEL オブジェクト上のマウスの左ボタンのクリックによって変更されます(プロパティで「選択を無効化」が設定されている必要があります)。OBJ_BITMAP オブジェクトは同じように作成されます。このオブジェクトは背景を必要な画像と作成するのに使用されます。

OBJ_BITMAP 及び OBJ_BITMAP_LABEL オブジェクトの外観を担当するOBJPROP_BMPFILE プロパティの値は動的に変更出来ます。これによって MQL5 プログラムのための様々なインタラクティブなユーザインタフェースの作成が出来ます。

 

MQL5 プログラムのコンパイル時の実行可能ファイルへのリソースの埋め込み

MQL5 プログラムはダウンロード可能な多くの映像と音声ファイルの形式のリソースを必要とする場合があります。MQL5 実行ファイルの移動時にこれらのファイルを転送する必要性をなくすには、コンパイラの #resource ディレクティブが使用されるべきです。

#resource path_to_resource_file

#resource コマンドはコンパイラに指定されたパス path_to_resource_file でのリソースが実行可能な EX5 ファイルを埋め込むように指令します。このように、別の端末上でプログラムを実行する場合、必要な画像や音声ファイルの全ては EX5 ファイルに直接配置することが出来るので、別途に転送される必要はありません。リソースはEX5 ファイルに埋め込むことができ、任意の EX5 プログラムは別の EX5 プログラムからのリソースを使用することが出来ます。

BMP 及び WAV 形式のファイルは EX5 ファイルに埋め込まれる前に自動的に圧縮されます。これは、グラフィックと音声を使用する場合にリソースを使用すると、MQL5 プログラムの通常の書き込みの方法に比べて必要なファイルの合計サイズを小さくすることが可能であることを意味します。

リソースファイルサイズは 16 MB を超えてはいけません。

 

コンパイラによる指定されたリソースの検索

リソースは #resource "< リソースファイルへのパス >" 指令を使用して挿入されます。

#resource "< リソースファイルへのパス >"

< リソースファイルへのパス > の定数文字列は 63 文字を超えてはいけません。

コンパイラはリソースを指定されたパスで次の順に探します。

  • (「\\」として書かれた)バックスラッシュ「\」がパスの始めにある場合、リソース検索は terminal_data_directory\MQL5\ ディレクトリに相対して行われます。
  • バックスラッシュがない場合、リソースが書かれたソースファイルと相対して検索が行われます。

リソースパスは「 ..\\ 」及び 「 :\\ 」を含むことが出来ません。

リソース埋め込みの例

//--- 正しいリソースの指定法
#resource "\\Images\\euro.bmp" // euro.bmp は terminal_data_directory\MQL5\Images\ に位置する
#resource "picture.bmp"       // picture.bmp はソースファイルと同じディレクトリに位置する
#resource "Resource\\map.bmp" // リソースは source_file_directory\Resource\map.bmp
 
//--- 不正なリソースの指定
#resource ":picture_2.bmp"     // 「 : 」を含む
#resource "..\\picture_3.bmp" // 「 .. 」を含む
#resource "\\Files\\Images\\Folder_First\\My_panel\\Labels\\too_long_path.bmp" // 63 記号以上

 

リソースの使用

リソース名

#resource ディレクティブでの宣言後、リソースはプログラムの任意の部分で使用出来ます。リソースの名称は、リソースへのパスを設定する行の先頭のバックスラッシュを付けないパスです。自分自身のリソースを使用するにはリソース名の前に「 :: 」特殊記号が加えられるべきです。

例:

//--- リソース指定とコメント内での名称の例
#resource "\\Images\\euro.bmp"         // リソース名 - Images\euro.bmp
#resource "picture.bmp"                 // リソース名 - picture.bmp
#resource "Resource\\map.bmp"           // リソース名 - Resource\map.bmp
#resource "\\Files\\Pictures\\good.bmp" // リソース名 - Files\Pictures\good.bmp
#resource "\\Files\\Demo.wav";         // リソース名 - Files\Demo.wav"
#resource "\\Sounds\\thrill.wav";       // リソース名 - Sounds\thrill.wav"
...                                  
 
//--- リソースの使用
ObjectSetString(0,bitmap_name,OBJPROP_BMPFILE,0,"::Images\\euro.bmp");
...
ObjectSetString(0,my_bitmap,OBJPROP_BMPFILE,0,"::picture.bmp");
...
set=ObjectSetString(0,bitmap_label,OBJPROP_BMPFILE,1,"::Files\\Pictures\\good.bmp");
...
PlaySound("::Files\\Demo.wav");
...
PlaySound("::Sounds\\thrill.wav");

リソースファイルの画像を OBJ_BITMAP and OBJ_BITMAP_LABEL オブジェクトに設定する場合、OBJPROP_BMPFILE プロパティ値は手動で変更出来ません。例えば OBJ_BITMAP_LABEL の作成には euro.bmp 及び dollar.bmp を使用します。

#resource "\\Images\\euro.bmp";   // euro.bmp は terminal_data_directory\MQL5\Images\ に位置する
#resource "\\Images\\dollar.bmp"; // dollar.bmp は terminal_data_directory\MQL5\Images\ に位置する

このオブジェクトのプロパティを表示する際、プロパティの「ビットマップファイル(オン)」と「ビットマップファイル(オフ)」が淡色表示されていて、手動変更が不可能だことがわかります。

using_resource

 

他の MQL5 プログラムのリソース使用

リソース使用には、MQL5 プログラムで別の EX5 ファイルのリソースを使用出来るというもう 1 つの利点があります。従って、1 つの EX5 ファイルのリソースは多くの MQL5 プログラムで使用することが出来ます。

別のファイルからのリソース名を使用するためには <path_EX5_file_name>::<resource_name> としての指定が必要です。例として Draw_Triangles_Script.mq5 スクリプトが triangle.bmp 画像ファイルのリソースを含むとします。

#resource "\\Files\\triangle.bmp"

スクリプト自体で使用されるためにはその名称は "Files\triangle.bmp" となり、それを使用するためには「 :: 」がリソース名に追加される必要があります。

//--- スクリプトでのリソースの使用
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"::Files\\triangle.bmp");

別のプログラム(例えばエキスパートアドバイザー)から同じリソースを使用する場合、リソース名に terminal_data_directory\MQL5\ に相対した EX5 ファイルのパスとEX5 ファイルの名称 - Draw_Triangles_Script.ex5を加える必要があります。スクリプトが terminal_data_directory\MQL5\Scripts\ 標準フォルダに位置する場合、呼び出しは次のように書かれるべきです。

//--- EA でのスクリプトのリソースの使用
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"\\Scripts\\Draw_Triangles_Script.ex5::Files\\triangle.bmp");

別の EX5 からのリソース呼び出しの際に実行可能ファイルへのパスが指定されていない場合は、実行可能ファイルは、リソースを呼び出すプログラムが含まれている同じフォルダで検索されます。つまり、エキスパートアドバイザーがDraw_Triangles_Script.ex5 のリソースをパスの指定なしにこのように呼び出す場合

//--- EA でパスの指定なしでスクリプトリソースを呼ぶ
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"Draw_Triangles_Script.ex5::Files\\triangle.bmp");

エキスパートアドバイザーが terminal_data_directory\MQL5\Experts\ に位置する場合、ファイルは terminal_data_directory\MQL5\で検索されます。

 

リソースとして含まれたカスタム指標の操作

MQL5 アプリケーションの動作には 1 つまたは複数のカスタム指標が必要であるかもしれません。それらの全ては、実行可能な MQL5 プログラムのコードに含めることが出来ます。指標をリソースとして含むことで、アプリケーションの配布が簡素化します。

下記はterminal_data_folder\MQL5\Indicators\ ディレクトリ位置する SampleIndicator.ex5 カスタム指標を含んで使用する例です。

//+------------------------------------------------------------------+
//|                                                     SampleEA.mq5 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                             https://www.MQL5.com |
//+------------------------------------------------------------------+
#resource "\\Indicators\\SampleIndicator.ex5"
int handle_ind;
//+------------------------------------------------------------------+
//| エキスパート初期化に使用される関数                                        |
//+------------------------------------------------------------------+
int OnInit()
 {
//---
  handle_ind=iCustom(_Symbol,_Period,"::Indicators\\SampleIndicator.ex5");
  if(handle_ind==INVALID_HANDLE)
    {
    Print("Expert: iCustom call: Error code=",GetLastError());
    return(INIT_FAILED);
    }
//--- ...
  return(INIT_SUCCEEDED);
 }

OnInit() 関数のカスタム指標が 1 つ以上の自己コピーをする場合、特別な考慮が必要です。リソースの指定は <path_EX5_file_name>::<resource_name> としてなされることにご注意下さい。

例えば SampleIndicator.ex5 指標が SampleEA.ex5 エキスパートアドバイザーに指標として含まれていて、カスタム指標の初期化関数で iCustom() が呼ばれる場合の位置表現は "\\Experts\\SampleEA.ex5::Indicators\\SampleIndicator.ex5" のようになります。このパスが明示的に設定されている場合、SampleIndicator.ex5 カスタム指標は厳格にSampleEA.ex5 エキスパートアドバイザーに接続されて、独立して動作する能力を失います。

自己のパスは GetRelativeProgramPath() 関数で受け取ることが出来ます。使用の例は下記の通りです。

//+------------------------------------------------------------------+
//|                                              SampleIndicator.mq5 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                             https://www.MQL5.com |
//+------------------------------------------------------------------+
#property indicator_separate_window
#property indicator_plots 0
int handle;
//+------------------------------------------------------------------+
//| カスタム指標を初期化する関数                                            |
//+------------------------------------------------------------------+
int OnInit()
 {
//--- 自己のリンクを提供する不正な方法
//--- 文字列パス ="\\Experts\\SampleEA.ex5::Indicators\\SampleIndicator.ex5";  
//--- 自己のリンクを受け取る正しい方法
string path=GetRelativeProgramPath();
//--- 指標バッファマッピング
  handle=iCustom(_Symbol,_Period,path,0,0);
  if(handle==INVALID_HANDLE)
    {
    Print("Indicator: iCustom call: Error code=",GetLastError());
    return(INIT_FAILED);
    }
  else Print("Indicator handle=",handle);
//---
  return(INIT_SUCCEEDED);
 }
///....
//+------------------------------------------------------------------+
//| GetRelativeProgramPath                                           |
//+------------------------------------------------------------------+
string GetRelativeProgramPath()
 {
  int pos2;
//--- アプリケーションへの絶対パスを取得する
  string path=MQLInfoString(MQL_PROGRAM_PATH);
//--- "\MQL5\" サブストリングのポジションを見つける
  int    pos =StringFind(path,"\\MQL5\\");
//--- サブストリングが見つからないので、エラー
  if(pos<0)
    return(NULL);
//--- "\MQL5" ディレクトリをとばす
  pos+=5;
//--- 余分な「 \ 」'記号をとばす
  while(StringGetCharacter(path,pos+1)=='\\')
     pos++;
//--- これがリソースならMQL5 ディレクトリに相対したパスを返す
  if(StringFind(path,"::",pos)>=0)
    return(StringSubstr(path,pos));
//--- MQL5\Indicators のような最初の MQL5 サブディレクトリの区切りを見つける
//--- 見つからない場合 MQL5 ディレクトリに相対したパスを返す
  if((pos2=StringFind(path,"\\",pos+1))<0)
    return(StringSubstr(path,pos));
//--- サブディレクトリ(例えば MQL5\Indicators )に相対したパスを返す
  return(StringSubstr(path,pos2+1));
 }
//+------------------------------------------------------------------+
//| カスタム指標の反復関数                                                |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
              const int prev_calculated,
              const int begin,        
              const double& price[])
 {
//--- 次の呼び出しのために prev_calculated の値を返す
  return(rates_total);
 }

リソース変数

リソースは、リソース変数を使用して宣言でき、それらが適切な型の変数と同様に扱われます。宣言の形式:

#resource path_to_the_resource_file as resource_variable_type resource_variable_name

宣言の例:

#resource "data.bin" as int ExtData[]             // data.binファイルからのデータを含む数値配列を宣言
#resource "data.bin" as MqlRates ExtData[]       // data.binファイルからのデータを含む単純構造体配列を宣言
//--- 文字列
#resource "data.txt" as string ExtCode           // data.txtファイルデータを含む文字列を宣言(ANSI、UTF-8、UTF-16 エンコードがサポートされる)
//--- グラフィックリソース
#resource "image.bmp" as bitmap ExtBitmap[]       // BMPファイルからのビットマップを含む1次元配列を宣言、array size = height * width
#resource "image.bmp" as bitmap ExtBitmap2[][]   // BMPファイルからビットマップを含む2次元配列を宣言、array size [height][width]

このような宣言の場合、リソースデータは 変数を介してのみのアドレス指定が可能で、" :: <rsource name>" のような自動アドレス指定は動作しません。

#resource "\\Images\\euro.bmp" as bitmap euro[][]
#resource "\\Images\\dollar.bmp"
//+------------------------------------------------------------------+
//| リソースを使ったOBJ_BITMAP_LABELオブジェクト作成関数                         |
//+------------------------------------------------------------------+
void Image(string name,string rc,int x,int y)
 {
  ObjectCreate(0,name,OBJ_BITMAP_LABEL,0,0,0);
  ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);
  ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);
  ObjectSetString(0,name,OBJPROP_BMPFILE,rc);
 }
//+------------------------------------------------------------------+
//| スクリプトプログラムを開始する関数                                          |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- ユーロリソース変数に格納されている画像サイズ[幅、高さ]を出力する
  Print(ArrayRange(euro,1),", ",ArrayRange(euro,0));
//--- ユーロで画像を変更する - 中央に赤い水平ストライプを描画する
  for(int x=0;x<ArrayRange(euro,1);x++)
     euro[ArrayRange(euro,1)/2][x]=0xFFFF0000;
//--- リソース変数を使用してグラフィカルリソースを作成する
  ResourceCreate("euro_icon",euro,ArrayRange(euro,0),ArrayRange(euro,1),0,0,ArrayRange(euro,1),COLOR_FORMAT_ARGB_NORMALIZE);
//---euro_iconリソースからの画像が設定されるユーログラフィカルラベルオブジェクトを作成する
  Image("Euro","::euro_icon",10,40);
//--- リソースを適用するあと一つのメソッド、それへの描画は不可能
  Image("USD","::Images\\dollar.bmp",15+ArrayRange(euro,1),40);
//--- euro.bmpリソースをアドレス指定する直接的な方法は、すでにユーロリソース変数<によって宣言されているため利用できない
  Image("E2","::Images\\euro.bmp",20+ArrayRange(euro,1)*2,40); // 実行時エラーが発生する
 }

スクリプト実行結果 – 3つのOBJ_BITMAP_LABELのうち2のみが作成されます。最初のオブジェクトの画像には、真ん中に赤いストライプがあります。

res_variables

リソースを適用することの重要な利点は、リソースファイルがコンパイル前に実行可能EX5ファイルに組み込まれる前に自動的に圧縮されることです。したがって、リソース変数を使用すると、実行可能なEX5ファイルにすべての必要なデータを直接入れることができ、MQL5プログラムを書く従来の方法と比較したファイルの数と合計サイズを減らすことができます。

リソース変数の使用はマーケットに製品を公開する場合に特に便利です。

機能

  • 特別なbitmapリソース変数タイプは、リソースが画像であることをコンパイラに通知します。そのような変数はuint型を受け取ります。
  • bitmap 型配列リソース変数は2次元を持つことができます。この場合、配列の大きさは [image_height ][ image_width ].で定義されます。1次元配列が指定されている場合、要素の数はimage_height * image_widthに等しくなります。
  • 24ビット画像のダウンロードではアルファチャネルコンポーネントは、すべての画像画素に対して255に設定されます。
  • アルファチャネルなしでの32ビット画像のダウンロードでは、アルファチャネルコンポーネントもすべての画像画素に対して255に設定されます。
  • アルファチャンネルを使用した32ビット画像のダウンロードでは、画素はまったく処理されません。
  • リソースファイルサイズは128MBを超えてはいけません。
  • 文字列ファイルに対してはBOM(ヘッダ)の存在による自動エンコード検出が実行されます。BOMが存在しない場合、エンコーディングはファイルの内容によって定義されます。ANSI、UTF-8およびUTF-16エンコーディングのファイルがサポートされています。すべての文字列は、ファイルからデータを読み込むときにUnicodeに変換されます。

OpenCLプログラム

ある種のプログラムの開発は、リソース文字列変数の使用によって大幅に容易になります。たとえばOpenCLプログラムのコードを別のCLファイルに書き込んだ後、文字列としてMQL5プログラムリソースに組み込むことが可能です。

#resource "seascape.cl" as string cl_program
...
int context;
if((cl_program=CLProgramCreate(context,cl_program)!=INVALID_HANDLE)
 {
  //--- OpenCLプログラムでさらなる行動を実行する
 }

リソース変数が使用されない場合、この例はcl_program コード全体の単一の大きな文字列としての記述が必要でした。

参照

ResourceCreate()ResourceSave()PlaySound()ObjectSetInteger()ChartApplyTemplate()ファイル関数