
MQL5 クックブック:MetaTrader 5トレードイベントへの音声通知
はじめに
本稿では Expert Advisor のファイルに音声ファイルをインクルードすること、それによりトレードイベントに音声通知を追加するなどの問題を考察します。事実、ファイルのインクルードが意味するところは Expert Advisor内に音声ファイルを入れるということです。よってコンパイルされた Expert Advisor (*.ex5) バージョンを他のユーザーに提供する際、音声ファイルは提供せずそれがどこの保存されるか説明する必要があるのです。
作成
テストのために先行記事"MQL5 Cookbook: Saving Optimization Results of an Expert Advisor Based on Specified Criteria"のExpert Advisor を取り込みます。ものごとをシンプルにするために今回のテーマに適さないことはすべて消去しました。
MQL5 のリソースを利用してトレードイベントに音声通知を追加するには関数Alert() および PlaySound()を使用します。Alert() 関数を選択するなら、それはつねに同じ音声通知を再生し、適切なメッセージのウィンドウを開きます。記事 "MQL5 Cookbook: Using Different Print Modes"でその動作を確認することができます。
警告音はターミナル設定でツール -> オプション または Ctrl+Oのように設定することができます。イベント タブで『有効』 オプションをチェックし、イベントに対する音声通知が有効であることを確認し、警告のドロップダウンリストから適切な音声を選択する必要があります。
図1 ターミナル設定の『イベント』タブ
ただし、カスタムプログラムイベントに対してはユニークな音声通知を設定することもできます。これには PlaySound() 関数を使用します。
Expert Advisorに音声通知を追加する前に、検証用 Expert Advisor を作成します。チャート上で Expert Advisor をロードするとき音声パネルを開くことを実装します。音声パネルはボタン(OBJ_BUTTON)のようなグラフィックオブジェクトから作成されます。ボタンはそれぞれ割り当てられたユニークな音声を持ち、クリックされるとその音声が再生されます。
私はオンライに行き *.wav 形式の異なる音声ファイルを25とおり見つけました(本稿末尾でダウンロード可能です)。それらは MetaTrader 5\MQL5\Files\Sounds フォルダに入れる必要があります。音声ファイル操作にはMQL5 ウィザードを用いて新しい Expert Advisor を作成します。まず最初に音声パネル上のボタン数(とタール26個のボタンがあります)に応じて配列サイズを指定します。
//--- Array size #define ARRAY_SIZE 26
それから Expert Advisorにリソースを提供するフォルダとファイル名を指定します。これは #resource 命令によって行います。この命令のあと、ダブルクオーテーションマークで囲んでファイル位置を指定します。
//--- Sound files #resource "\\Files\\Sounds\\alert.wav" #resource "\\Files\\Sounds\\AHOOGA.wav" #resource "\\Files\\Sounds\\APPLAUSE.wav" #resource "\\Files\\Sounds\\BONK.wav" #resource "\\Files\\Sounds\\CARBRAKE.wav" #resource "\\Files\\Sounds\\CASHREG.wav" #resource "\\Files\\Sounds\\CLAP.wav" #resource "\\Files\\Sounds\\CORKPOP.wav" #resource "\\Files\\Sounds\\DOG.wav" #resource "\\Files\\Sounds\\DRIVEBY.wav" #resource "\\Files\\Sounds\\DRUMROLL.wav" #resource "\\Files\\Sounds\\EXPLODE.wav" #resource "\\Files\\Sounds\\FINALBEL.wav" #resource "\\Files\\Sounds\\FROG.wav" #resource "\\Files\\Sounds\\GLASS.wav" #resource "\\Files\\Sounds\\GUNSHOT.wav" #resource "\\Files\\Sounds\\LASER.wav" #resource "\\Files\\Sounds\\LATNWHIS.wav" #resource "\\Files\\Sounds\\PIG.wav" #resource "\\Files\\Sounds\\RICOCHET.wav" #resource "\\Files\\Sounds\\RINGIN.wav" #resource "\\Files\\Sounds\\SIREN.wav" #resource "\\Files\\Sounds\\TRAIN.wav" #resource "\\Files\\Sounds\\UH_OH.wav" #resource "\\Files\\Sounds\\VERYGOOD.wav" #resource "\\Files\\Sounds\\WHOOSH.wav"
ここでリソースファイル位置、グラフィックオブジェクト名、グラフィックオブジェクト上に表示されるテキストを持つ文字列配列を3個作成します。ファイル位置を指定する際はダブルコロンを使うことに注意してください。それはリソースを名前で呼ぶための特殊な指示です。
//--- Sound file location string sound_paths[ARRAY_SIZE]= { "::Files\\Sounds\\alert.wav", "::Files\\Sounds\\AHOOGA.wav", "::Files\\Sounds\\APPLAUSE.wav", "::Files\\Sounds\\BONK.wav", "::Files\\Sounds\\CARBRAKE.wav", "::Files\\Sounds\\CASHREG.wav", "::Files\\Sounds\\CLAP.wav", "::Files\\Sounds\\CORKPOP.wav", "::Files\\Sounds\\DOG.wav", "::Files\\Sounds\\DRIVEBY.wav", "::Files\\Sounds\\DRUMROLL.wav", "::Files\\Sounds\\EXPLODE.wav", "::Files\\Sounds\\FINALBEL.wav", "::Files\\Sounds\\FROG.wav", "::Files\\Sounds\\GLASS.wav", "::Files\\Sounds\\GUNSHOT.wav", "::Files\\Sounds\\LASER.wav", "::Files\\Sounds\\LATNWHIS.wav", "::Files\\Sounds\\PIG.wav", "::Files\\Sounds\\RICOCHET.wav", "::Files\\Sounds\\RINGIN.wav", "::Files\\Sounds\\SIREN.wav", "::Files\\Sounds\\TRAIN.wav", "::Files\\Sounds\\UH_OH.wav", "::Files\\Sounds\\VERYGOOD.wav", "::Files\\Sounds\\WHOOSH.wav" }; //--- Names of graphical objects string sound_names[ARRAY_SIZE]= { "sound_button01","sound_button02", "sound_button03","sound_button04", "sound_button05","sound_button06", "sound_button07","sound_button08", "sound_button09","sound_button10", "sound_button11","sound_button12", "sound_button13","sound_button14", "sound_button15","sound_button16", "sound_button17","sound_button18", "sound_button19","sound_button20", "sound_button21","sound_button22", "sound_button23","sound_button24", "sound_button25","sound_button26" }; //--- Text displayed on graphical objects string sound_texts[ARRAY_SIZE]= { "ALERT","AHOOGA","APPLAUSE","BONK","CARBRAKE","CASHREG", "CLAP","CORKPOP","DOG","DRIVEBY","DRUMROLL","EXPLODE","FINALBEL", "FROG","GLASS","GUNSHOT","LASER","LATNWHIS","PIG", "RICOCHET","RINGIN","SIREN","TRAIN","UH_OH","VERYGOOD","WHOOSH" };
関数 CreateButton()を書きます。これは指定のプロパティを伴ってチャート上にグラフィックオブジェクトである『ボタン』を作成します。
//+------------------------------------------------------------------+ //| Creating the Button object | //+------------------------------------------------------------------+ void CreateButton(long chart_id, // chart id int sub_window, // window number string name, // object name string text, // displayed name ENUM_ANCHOR_POINT anchor, // anchor point ENUM_BASE_CORNER corner, // chart corner string font_name, // font int font_size, // font size color font_color, // font color color background_color, // background color color border_color, // border color int x_size, // width int y_size, // height int x_distance, // X-coordinate int y_distance, // Y-coordinate long z_order) // Z-order { //--- Creating an object if(ObjectCreate(chart_id,name,OBJ_BUTTON,sub_window,0,0)) { ObjectSetString(chart_id,name,OBJPROP_TEXT,text); // setting name ObjectSetString(chart_id,name,OBJPROP_FONT,font_name); // setting font ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color); // setting font color ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color); // setting background color ObjectSetInteger(chart_id,name,OBJPROP_BORDER_COLOR,border_color); // setting border color ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor); // setting anchor point ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner); // setting chart corner ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size); // setting font size ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size); // setting width X ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,y_size); // setting height Y ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance); // setting X-coordinate ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance); // setting Y-coordinate ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false); // cannot select the object if FALSE ObjectSetInteger(chart_id,name,OBJPROP_STATE,false); // button state (clicked/unclicked) ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order); // higher/lower Z-order ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n"); // no tooltip if "\n" } }
遊び心を持たせるため、ボタンの色はランダムに選択されるようにします。これを実装するにはシンプルな関数- GetRandomColor()を書きます。
//+------------------------------------------------------------------+ //| Returning a random color | //+------------------------------------------------------------------+ color GetRandomColor() { //--- Select a random color from 0 to 25 switch(MathRand()%26) { case 0 : return(clrOrange); break; case 1 : return(clrGold); break; case 2 : return(clrChocolate); break; case 3 : return(clrChartreuse); break; case 4 : return(clrLime); break; case 5 : return(clrSpringGreen); break; case 6 : return(clrMediumBlue); break; case 7 : return(clrDeepSkyBlue); break; case 8 : return(clrBlue); break; case 9 : return(clrSeaGreen); break; case 10 : return(clrRed); break; case 11 : return(clrSlateGray); break; case 12 : return(clrPeru); break; case 13 : return(clrBlueViolet); break; case 14 : return(clrIndianRed); break; case 15 : return(clrMediumOrchid); break; case 16 : return(clrCrimson); break; case 17 : return(clrMediumAquamarine); break; case 18 : return(clrDarkGray); break; case 19 : return(clrSandyBrown); break; case 20 : return(clrMediumSlateBlue); break; case 21 : return(clrTan); break; case 22 : return(clrDarkSalmon); break; case 23 : return(clrBurlyWood); break; case 24 : return(clrHotPink); break; case 25 : return(clrLightSteelBlue); break; //--- default : return(clrGold); } //--- return(clrGold); }
チャートに音声パネルを追加する関数- SetSoundPanel()を書きます。
//+------------------------------------------------------------------+ //| Adding the sound panel to the chart | //+------------------------------------------------------------------+ void SetSoundPanel() { int column_count =0; // Column counter int x_dist =10; // Indent from the left side of the chart int y_dist =15; // Indent from the top of the chart int x_size =100; // Button width int y_size =20; // Button height color button_color =clrNONE; // Button color //--- Set the objects for(int i=0; i<ARRAY_SIZE; i++) { //--- Increase the column counter column_count++; //--- Get the button color button_color=GetRandomColor(); //--- Draw a button CreateButton(0,0,sound_names[i],sound_texts[i], ANCHOR_LEFT_UPPER,CORNER_LEFT_UPPER,"Arial",8, clrWhite,button_color,button_color,x_size,y_size,x_dist,y_dist,1); //--- If two buttons have already been set in the same row if(column_count==2) { x_dist=10; // Move the X-coordinate to the initial position y_dist+=20; // Set the Y-coordinate for the next row column_count=0; // Zero out the counter } else //--- Set the X-coordinate for the next button x_dist+=x_size; } //--- Refresh the chart ChartRedraw(0); }
チャートからパネルを消去するには以下の関数を使用します。
//+------------------------------------------------------------------+ //| Deleting the info panel | //+------------------------------------------------------------------+ void DeleteSoundPanel() { //--- Delete position properties and their values for(int i=0; i<ARRAY_SIZE; i++) DeleteObjectByName(name_sound_object[i]); //--- Redraw the chart ChartRedraw(); } //+------------------------------------------------------------------+ //| Deleting objects by name | //+------------------------------------------------------------------+ void DeleteObjectByName(string name) { //--- If the object is found if(ObjectFind(ChartID(),name)>=0) { //--- If an error occurred when deleting, print the relevant message if(!ObjectDelete(ChartID(),name)) Print("Error ("+IntegerToString(GetLastError())+") when deleting the object!"); } }
Expert Advisorをロードするとき、パネルは OnInit() 関数からチャート上に設定され、OnDeinit() 関数によって Expert Advisor が消去されるときチャートから削除されます。
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ void OnInit() { //--- Set the sound panel SetSoundPanel(); } //+------------------------------------------------------------------+ //| Deinitialization function of the expert advisor | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Delete the sound panel DeleteSoundPanel(); }
ここでは特定のボタンがクリックされるとき適切な音声が再生されるようにパネルとの連携を実装するだけです。音声パネルボタンの一つが押されるときボタンの色が変わるようにし、操作をより楽しくします。これを実装するには以下に記述の ChangeColorsOnSoundPanel() 関数が必要です。
//+------------------------------------------------------------------+ //| Changing colors on the sound panel | //+------------------------------------------------------------------+ void ChangeColorsOnSoundPanel() { color clr=clrNONE; // Button color //--- Iterate over all buttons in a loop and change their color for(int i=0; i<ARRAY_SIZE; i++) { //--- Get the new color clr=GetRandomColor(); //--- Set the border color ObjectSetInteger(0,sound_names[i],OBJPROP_BGCOLOR,clr); //--- Set the background color ObjectSetInteger(0,sound_names[i],OBJPROP_BORDER_COLOR,clr); //--- Unclicked button ObjectSetInteger(0,sound_names[i],OBJPROP_STATE,false); //--- Refresh the chart ChartRedraw(0); //--- Wait for 20 ms (lag) Sleep(20); } }
そして最後に以下のコードを OnChartEvent() 関数に追加します。
//+------------------------------------------------------------------+ //| Event handler | //+------------------------------------------------------------------+ void OnChartEvent(const int id, // Event identifier const long& lparam, // Parameter of the event of type long const double& dparam, // Parameter of the event of type double const string& sparam) // Parameter of the event of type string { //--- If there was an event of left-clicking on the object if(id==CHARTEVENT_OBJECT_CLICK) { //--- If the object name contains "sound_button" if(StringFind(sparam,"sound_button",0)>=0) { //--- Play the sound based on the object name // 5019 - ERR_FILE_NOT_EXIST - The file does not exist if(!PlaySound(GetSoundPath(sparam))) Print("Error: ",GetLastError()); //--- Change colors of all buttons ChangeColorsOnSoundPanel(); } } }
上記コードで強調表示されている文字列は GetSoundPath() 関数を用いて音声ファイルの位置情報が PlaySound() 関数に渡されることを示しています。下記は GetSoundPath() 関数のコードです。
//+------------------------------------------------------------------+ //| Returning sound file location by the object name | //+------------------------------------------------------------------+ string GetSoundPath(string object_name) { //--- Iterate over all sound panel objects in a loop for(int i=0; i<ARRAY_SIZE; i++) { //--- If the name of the object clicked in the chart // matches one of those available on the panel, return the file location if(object_name==name_sound_object[i]) return(path_sound_object[i]); } //--- return(""); }
これですべて準備完了です。音声パネル(プログラムは本稿の添付からダウンロードできます)は Expert Advisor がチャートにアタッチされるとすぐに設定されます。
図2 チャート上の音声パネル
音声ファイルの操作原理はこれで明らかです。先行記事 "MQL5 Cookbook: Saving Optimization Results of an Expert Advisor Based on Specified Criteria" からの Expert Advisor に話を戻し、この Expert Advisorでどんな音声を使うか決めます。Resources.mqh を作成し、それを Expert Advisor のメインファイルにインクルードします。
//--- Include custom libraries #include "Include/Errors.mqh" #include "Include/Enums.mqh" #include "Include/Resources.mqh" #include "Include/TradeSignals.mqh" #include "Include/TradeFunctions.mqh" #include "Include/ToString.mqh" #include "Include/Auxiliary.mqh"
そしてここでメインのトレードイベントについてのファイルを選択します。
//--- Sound files #resource "\\Files\\Sounds\\AHOOGA.WAV" // Error #resource "\\Files\\Sounds\\CASHREG.WAV" // Position opening/position volume increase/pending order triggering #resource "\\Files\\Sounds\\WHOOSH.WAV" // Pending order/Stop Loss/Take Profit setting/modification #resource "\\Files\\Sounds\\VERYGOOD.WAV" // Position closing at profit #resource "\\Files\\Sounds\\DRIVEBY.WAV" // Position closing at loss //--- Sound file location string SoundError = "::Files\\Sounds\\AHOOGA.WAV"; string SoundOpenPosition = "::Files\\Sounds\\CASHREG.WAV"; string SoundAdjustOrder = "::Files\\Sounds\\WHOOSH.WAV"; string SoundCloseWithProfit= "::Files\\Sounds\\VERYGOOD.WAV"; string SoundCloseWithLoss = "::Files\\Sounds\\DRIVEBY.WAV";
リソースとして使用される音声ファイルのほか Expert Advisor にはインターフェース用の *.bmp 画像、テキストファイル、インディケータも格納することができることもお伝えします。MetaTrader 5 用EAは完全な機能を備えたアプリケーションであるとみなされています。これは複数ファイルの代わりにファイルを1件だけ渡せばよいという点でひじょうに便利です。
それでは続けましょう。音声を無効にする機能を持つため、外部パラメータに UseSound パラメータを追加する必要があります。
//--- External parameters of the Expert Advisor input int NumberOfBars =2; // Number of one-direction bars sinput double Lot =0.1; // Lot input double TakeProfit =100; // Take Profit input double StopLoss =50; // Stop Loss input double TrailingStop =10; // Trailing Stop input bool Reverse =true; // Position reversal sinput bool UseSound =true; // Sound notifications
Include\Enums.mqhに音声用の列挙 ENUM_SOUNDS を作成します。
//--- Sounds enum ENUM_SOUNDS { SOUND_ERROR =0, // Error SOUND_OPEN_POSITION = 1, // Position opening/position volume increase/pending order triggering SOUND_ADJUST_ORDER = 2, // Stop Loss/Take Profit/pending order setting SOUND_CLOSE_WITH_PROFIT = 3, // Position closing at profit SOUND_CLOSE_WITH_LOSS = 4 // Position closing at loss };
これら識別子はカスタム関数 PlaySoundByID()に対して必要となります。
//+------------------------------------------------------------------+ //| Playing sounds | //+------------------------------------------------------------------+ void PlaySoundByID(ENUM_SOUNDS id) { //--- If it is the real-time mode and sounds are enabled if(IsRealtime() && UseSound) { //--- Play the sound based on the identifier passed switch(id) { case SOUND_ERROR : PlaySound(SoundError); break; case SOUND_OPEN_POSITION : PlaySound(SoundOpenPosition); break; case SOUND_ADJUST_ORDER : PlaySound(SoundAdjustOrder); break; case SOUND_CLOSE_WITH_PROFIT : PlaySound(SoundCloseWithProfit); break; case SOUND_CLOSE_WITH_LOSS : PlaySound(SoundCloseWithLoss); break; } } }
Expert Advisorのトレード処理中、音声は適切なトレード関数から PlaySoundByID() を呼ぶことで再生されます。OpenPosition() 関数へのこれの実装方法を見ましょう。
//+------------------------------------------------------------------+ //| Opening a position | //+------------------------------------------------------------------+ void OpenPosition(double lot, ENUM_ORDER_TYPE order_type, double price, double sl, double tp, string comment) { //--- Set the magic number in the trading structure trade.SetExpertMagicNumber(0); //--- Set the slippage in points trade.SetDeviationInPoints(CorrectValueBySymbolDigits(10)); //--- The Instant Execution and Market Execution modes // *** Starting with build 803, Stop Loss and Take Profit *** // *** can be set upon opening a position in the SYMBOL_TRADE_EXECUTION_MARKET mode *** if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT || symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET) { //--- If the position failed to open if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment)) { //--- Play the error sound and print the relevant message PlaySoundByID(SOUND_ERROR); Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } //--- Otherwise play the position opening sound else PlaySoundByID(SOUND_OPEN_POSITION); } }
ただポジションがストップロス、テイクプロフィット、マニュアル、または別の方法でクローズになっていれば、このイベントは OnTrade() 関数内で監視される必要があります。これを実装するには、もう一つ関数を書きます。SoundNotification()がその関数で、これは必要な確認を行います。取り引き履歴が現シンボルに対して新しい取り引きを識別子 DEAL_ENTRY_OUT または DEAL_ENTRY_INOUT(ポジションの完全/部分的クローズまたはオープン) を使って表示しているか、プログラムがその取り引きが収益あるいは損失でクローズしているか適切な音声を再生しているかなど。
//+------------------------------------------------------------------+ //| Sound notification | //+------------------------------------------------------------------+ void SoundNotification() { //--- If it is the real-time mode and sounds are enabled if(IsRealtime() && UseSound) { ulong ticket =0; // Deal ticket int total =0; // Total deals static ulong last_ticket =0; // Last ticket prior to this check //--- Get the complete history if(!HistorySelect(0,TimeCurrent()+1000)) return; //--- Get the number of deals in the obtained list total=HistoryDealsTotal(); //--- In the obtained list, iterate over all deals from the last one to the first one for(int i=total-1; i>=0; i--) { //--- If the deal ticket by its position in the list has been obtained if((ticket=HistoryDealGetTicket(i))>0) { //--- get the symbol of the deal GetHistoryDealProperties(ticket,D_SYMBOL); //--- If the symbol of the deal and the current symbol are the same if(deal.symbol==_Symbol) { //--- get the direction of the deal GetHistoryDealProperties(ticket,D_ENTRY); //--- If it is position closing, volume decrease or reversal if(deal.entry==DEAL_ENTRY_OUT || deal.entry==DEAL_ENTRY_INOUT) { //--- If the ticket of the current deal from the list (the last deal for the symbol) is equal to the previous ticket // or this is the initialization of the ticket of the last deal if(ticket==last_ticket || last_ticket==0) { //--- Save the ticket and exit last_ticket=ticket; return; } //--- Get the result of the deal GetHistoryDealProperties(ticket,D_PROFIT); //--- In case of profit if(deal.profit>=0) { //--- Profit sound PlaySoundByID(SOUND_CLOSE_WITH_PROFIT); //--- Save the ticket number last_ticket=ticket; return; } //--- In case of loss if(deal.profit<0) { //--- Loss sound PlaySoundByID(SOUND_CLOSE_WITH_LOSS); //--- Save the ticket number last_ticket=ticket; return; } } } } } } }
SoundNotification() 関数は関数 OnInit() および OnTrade() に入れます。
//+------------------------------------------------------------------+ //| Initialization | //+------------------------------------------------------------------+ int OnInit() { //--- Initialize the new bar CheckNewBar(); //--- Initialize tickets of the last deals for the symbol SoundNotification(); //--- Initialization completed successfully return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Monitoring trade events | //+------------------------------------------------------------------+ void OnTrade() { //--- Sound notification SoundNotification(); }
音声通知はまたトレーリングストップレベルを変更するとき ModifyTrailingStop() 関数の末尾に追加されました。
おわりに
それでおしまいです。検証用ファイルはすべて本稿の添付からダウンロードすることができます。ターミナル内の音声については、コードベースでCMIDI (Integerにより)という名前で入手可能なおもしろいソリューションに注意を向けたいと思います。それでMetaTrader 5のファイル MIDI を再生することができます。グッドラック!
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/748





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索