取引イベントおよびシグナルの音声通知システム
目次
はじめに
MetaTrader 5取引ターミナルは、音声アラートの使用を可能にするオプションを備えています。11のイベントに対して、個別の音声アラートを割り当てることができます。ただし、取引システムのシグナルの出現や、ポジションを開く、決済する、変更するなどのエキスパートアドバイザーのアクションなど、ユーザが音声通知を受信する必要がある状況はさらに多くあります。今日では、ナビゲーター、音声検索、翻訳ツールがよく使用され、音声アシスタントは人間の生活において重要な役割を果たしています。このアイデアは、MetaTrader5ターミナルで取引するときに使用できます。本稿では、さまざまな取引イベント、市場の状態、取引シグナルによって生成されるシグナルに対するシンプルでユーザフレンドリーな音声通知システムの開発を試みます。
音声通知システムの開発
システムの作成を開始する前に付け加えたいのですが、音声通知を実装するために選択したイベントは、デモ目的のみで選択されています。このセットでは不十分な場合は、独自のイベントと関連する音声アラートを追加してください。本稿をお読みになれば、MQL5に関する幅広い知識がなくても、システムの拡張とカスタマイズは非常に簡単です。
このシステムは、インクルードファイルでCSoundsLibクラスとして実装されます。MQL5/Includeフォルダを開いてSoundsLibフォルダを作成し、中にSoundsLib.mqhファイルを作成してください。クラスを作成する前に、音声アラートの操作にさらに使用される2つの列挙を紹介しましょう。1番目は、アラート言語の選択に使用されるLANGUAGEです。英語とロシア語の2つの言語をサポートします。
//+------------------------------------------------------------------+ //| Enumeration for switching the notification language | //+------------------------------------------------------------------+ enum LANGUAGE { RUSSIAN, // Russian ENGLISH // English };
2番目の列挙体には、デモ目的で選択した一連のイベントが含まれています。さらに本稿では、指標、エキスパートアドバイザー、クイック取引ツールキットなど、さまざまな既製のシステムにそれらを組み込む方法を示します。列挙体はMESSAGEと呼ばれています。
//+------------------------------------------------------------------+ //| List of voice alerts | //+------------------------------------------------------------------+ enum MESSAGE { STATUS_ON, // Status of enabled voice alerts SIGNAL_BUY, // A Buy signal SIGNAL_SELL, // A Sell signal BUY_ORDER_SET, // A Buy order has been placed SELL_ORDER_SET, // A Sell order has been placed BUYLIMIT_ORDER_SET, // A Limit Buy order has been placed BUYSTOP_ORDER_SET, // A Stop Buy order has been placed SELLLIMIT_ORDER_SET, // A Limit Sell order has been placed SELLSTOP_ORDER_SET, // A Stop Sell order has been placed BUYLIMIT_ORDER_DELETE, // A Limit Buy order has been deleted BUYSTOP_ORDER_DELETE, // A Stop Buy order has been deleted SELLLIMIT_ORDER_DELETE, // A Limit Sell order has been deleted SELLSTOP_ORDER_DELETE, // A Stop Sell order has been deleted BUY_ORDER_CLOSE_PROFIT, // A Buy order has closed with a profit BUY_ORDER_CLOSE_LOSS, // A Buy order has closed with a loss SELL_ORDER_CLOSE_PROFIT, // A Sell order has closed with a profit SELL_ORDER_CLOSE_LOSS, // A Sell order has closed with a loss BUY_ORDER_CLOSE_TP, // A Buy order has been closed by Take Profit BUY_ORDER_CLOSE_SL, // A Buy order has been closed by Stop Loss SELL_ORDER_CLOSE_TP, // A Sell order has been closed by Take Profit SELL_ORDER_CLOSE_SL, // A Sell order has been closed by Stop Loss MARKET_CLOSE, // Market is closed AUTO_TRADING_ON, // Automated trading is allowed AUTO_TRADING_OFF, // Automated trading is prohibited };
基本セットには24個のアラートが含まれています。それらのほとんどは、ポジションと未決注文の操作とステータスに関連しています。一部のアラートは取引環境の通知に使用されます。最後の3つの通知は、一般的なイベントに関連しています。有効な音声アラートシステムのステータスに関する通知、および買いシグナルまたは売りシグナルの出現に関する通知は、手動または半自動の取引エキスパートアドバイザーを使用する場合、または単純な指標や取引戦略の一部として利用可能な指標を使用する場合に便利です。
CSoundsLibクラスを作成して、作業に必要なメソッドを追加しましょう。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CSoundsLib { private: LANGUAGE m_language; bool m_activity_status; public: CSoundsLib(void); ~CSoundsLib(void); //--- Set the notification language void Language(LANGUAGE lang); //--- Set/get the status of the voice alerts system void IsActive(bool flag); bool IsActive(void); //--- Play the specified notification bool Message(MESSAGE msg); };
privateセクションには2つのアラート(m_language and m_activity_status)があります。これらは、Language()メソッドとIsActive()メソッドで必要です。そのため、音声アラートの言語を設定したり、システムアクティビティステータスを取得/設定したりするために使用されます。上記のアラートの実装は次のとおりです。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CSoundsLib::Language(LANGUAGE lang) { m_language=lang; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CSoundsLib::IsActive(void) { return(m_activity_status); }
後1つのメソッドはMessage()です。これは、MESSAGE列挙から選択された通知を再生します。 このメソッドの実装も理解しやすいです。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CSoundsLib::Message(MESSAGE msg) { if(!m_activity_status) return(false); string name=(m_language==RUSSIAN ? EnumToString(msg)+"_RU" : EnumToString(msg)+"_EN"); if(PlaySound("\\Files\\SoundsLib\\"+name+".wav")) return(true); else { if(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian") Print("Файл не найден"); else Print("File not found"); return(false); } }
次の重要な点に注意してください。これらは、独自の音声通知を追加してシステムをさらに正しく拡張するのに役立ちます。1番目の点は、音声ファイルを保存する正しい場所です。デフォルトでは、音声ファイルは MQL5/Files/SoundsLibフォルダにあります。SoundsLibフォルダを作成してください。2番目は、作成したフォルダで適切な名前と音声ファイル形式を設定することです。これらのコード行に注意してください。ここでは、_RUまたは_ENサフィックスがMESSAGE型の列挙に追加されます。そのため、たとえば、買いシグナルアラートSIGNAL_BUYに対応するファイル名は、ロシア語と英語の音声アラートの2つの音声ファイル(SIGNAL_BUY_RUとSIGNAL_BUY_EN)に関連付けられます。また、システム関数PlaySound()は*.WAV形式のファイルしか再生できないため、 SoundsLibフォルダでの拡張子付きの完全なファイル名は、次のようになります。
図1 音声ファイルの完全な名前と拡張子
したがって、MESSAGE列挙の24のイベントのセットに対して48の音声ファイルがあります。イベントごとに異なる言語の2つのファイルです。次に、音声アラートを作成するための独自の方法を示します。それでも、任意の方法を使用できます。この記事では、テキストを音声に変換するために無料サービスを使用しました。
図2 テキストを音声に変換するサービス
このサービスは、必要なタスクを実装するための優れた機能を提供します。言語、および必要な形式のタイプを選択できます。ただし、WAV形式は英語ではサポートされていません。ここでは、オンラインコンバーターまたはその他のソフトウェアを使用してmp3をwavに変換できます。システムに必要なすべてのファイルを準備し、MESSAGE列挙と言語サフィックスに従って正しい形式と名前でMQL5\Files\SoundsLibフォルダに保存しました。結果のリストは次のとおりです。
図3 音声アラート用の音声ファイルの完全なリスト
以下は、独自の音声通知を作成する方法の手順を追ったガイドです。
手順1:音声イベントをシステムに追加します。
SoundsLib.mqhファイルを開いて、MESSAGE列挙体を見つけます。意味のある名前でイベントを追加します。命名例を図3と上記のコードに示します。
手順2: 音声アラート用の音声ファイルを作成します。
サービスに移動して(好きなサービスを利用できます)、必要なパラメータを構成し(図2を参照)、言語に応じて「MESSAGE列挙のイベント名」+ _RU(_EN)という名前のMQL5\Files\SoundsLibの下にWAV形式でファイルを保存します。すべての手順が正しく完了すると、新しい音声ファイルは手順1で追加された新しいイベントにリンクされ、使用できるようになります。
指標での実用的な適用
次に、さまざまな例を使用して、それがどのように機能するかを見てみましょう。以下の表で説明されている2つの指標シグナルに基づいて複合指標を作成しましょう。
パラメータ | 説明 |
---|---|
使用される指標 | ADXCloud |
使用される指標 | ColorZerolagRVI |
時間枠の選択 | 任意 |
買いの条件 | ADXCloudクラウドが緑で、ColorZerolagRVIクラウドが赤から緑のゾーンに移動する |
売りの条件 | ADXCloudクラウドが緑で、ColorZerolagRVIクラウドが赤から緑に移動する |
指標シグナルに基づくエントリの例を図4に示します。これらは、非常に単純です。チャート上に矢印として市場エントリポイントを表示する複合シグナル指標を作成するための基礎として使用します。
図4 指標シグナルによるエントリ条件
//+------------------------------------------------------------------+ //| Example.mq5 | //| Alex2356 | //| https://www.mql5.com/en/users/alex2356 | //+------------------------------------------------------------------+ #property copyright "Alex2356" #property link "https://www.mql5.com/en/users/alex2356" #property version "1.00" #property indicator_chart_window //--- two buffers are used for calculating and drawing the indicator #property indicator_buffers 2 //--- used graphic constructions #property indicator_plots 2 #property indicator_label1 "Buy Signal" #property indicator_type1 DRAW_ARROW //--- #property indicator_label2 "Sell Signal" #property indicator_type2 DRAW_ARROW //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ input group "ADX Cloud Parameters" input int ADXPeriod = 8; input double Alpha1 = 0.25; input double Alpha2 = 0.25; input group "RVI Color Parameters" input uint Smoothing = 15; //---- input double Weight1 = 0.05; input int RVI_period1 = 8; //---- input double Weight2 = 0.10; input int RVI_period2 = 21; //---- input double Weight3 = 0.16; input int RVI_period3 = 34; //---- input double Weight4 = 0.26; input int RVI_period4 = 55; //---- input double Weight5 = 0.43; input int RVI_period5 = 89; //--- double BuySignal[],SellSignal[],ADXCloud[],FastRVI[],SlowRVI[]; int ADX_Handle,RVI_Hadnle,min_rates_total; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- SetIndexBuffer(0,BuySignal,INDICATOR_DATA); SetIndexBuffer(1,SellSignal,INDICATOR_DATA); //--- PlotIndexSetInteger(0,PLOT_ARROW,233); PlotIndexSetInteger(1,PLOT_ARROW,234); //--- PlotIndexSetInteger(0,PLOT_LINE_COLOR,clrDodgerBlue); PlotIndexSetInteger(1,PLOT_LINE_COLOR,clrCrimson); //--- ArraySetAsSeries(SellSignal,true); ArraySetAsSeries(BuySignal,true); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE); PlotIndexSetInteger(0,PLOT_ARROW_SHIFT,20); PlotIndexSetInteger(1,PLOT_ARROW_SHIFT,-20); //--- ADX_Handle=iCustom(Symbol(),PERIOD_CURRENT,"adxcloud",ADXPeriod,Alpha1,Alpha2); if(ADX_Handle==INVALID_HANDLE) { Print(" Failed to create indicator handle"); return(INIT_FAILED); } //--- RVI_Hadnle=iCustom(Symbol(),PERIOD_CURRENT,"colorzerolagrvi", Smoothing, Weight1,RVI_period1, Weight2,RVI_period2, Weight3,RVI_period3, Weight4,RVI_period4, Weight5,RVI_period5 ); if(RVI_Hadnle==INVALID_HANDLE) { Print(" Failed to create indicator handle"); return(INIT_FAILED); } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| 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[]) { //--- c if(BarsCalculated(ADX_Handle)<rates_total || BarsCalculated(RVI_Hadnle)<rates_total || rates_total<min_rates_total) return(0); //--- int limit,to_copy,i; //--- ArraySetAsSeries(ADXCloud,true); ArraySetAsSeries(FastRVI,true); ArraySetAsSeries(SlowRVI,true); ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); //--- if(prev_calculated>rates_total || prev_calculated<=0) limit=rates_total-2; else limit=rates_total-prev_calculated; to_copy=limit+2; //--- if(CopyBuffer(ADX_Handle,0,0,to_copy,ADXCloud)<=0) return(0); //--- if(CopyBuffer(RVI_Hadnle,0,0,to_copy,FastRVI)<=0) return(0); if(CopyBuffer(RVI_Hadnle,1,0,to_copy,SlowRVI)<=0) return(0); //--- for(i=limit-1; i>=0 && !IsStopped(); i--) { if(ADXCloud[i+1]>0 && FastRVI[i+1]>SlowRVI[i+1] && FastRVI[i+2]<SlowRVI[i+2]) { BuySignal[i]=low[i]; SellSignal[i]=EMPTY_VALUE; } else if(ADXCloud[i+1]<0 && FastRVI[i+1]<SlowRVI[i+1] && FastRVI[i+2]>SlowRVI[i+2]) { SellSignal[i]=high[i]; BuySignal[i]=EMPTY_VALUE; } else { BuySignal[i]=EMPTY_VALUE; SellSignal[i]=EMPTY_VALUE; } } //--- return value of prev_calculated for the next call return(rates_total); } //+------------------------------------------------------------------+
結果の実装を図5に示します。次に、音声通知のシステムを実装する必要があります。
図5 2つの指標に基づく矢印指標
まず、SoundsLib.mqhファイルを指標とリンクします。
#include <SoundsLib/SoundsLib.mqh>
音声通知クラスのインスタンスを作成します。
CSoundsLib Notify;
OnInit()初期化関数で、通知言語を設定します。ここでは英語にします。実際には、英語はデフォルトで設定されているため、追加で設定する必要はありません。ここでの設定は、デモ目的です。
Notify.Language(ENGLISH);
矢印指標は市場のエントリポイントまたは売買シグナルのみを表示するため、MESSAGE列挙からの2つの音声通知を使用します。
SIGNAL_BUY, // A Buy signal SIGNAL_SELL, // A Sell signal
通知システムを指標に組み込む場合、アラートは履歴全体で生成されるのではなく、現在のバーでのみ生成されます。したがって、シグナル検索ループを次のように変更します。
//--- for(i=limit-1; i>=0 && !IsStopped(); i--) { if(ADXCloud[i+1]>0 && FastRVI[i+1]>SlowRVI[i+1] && FastRVI[i+2]<SlowRVI[i+2]) { BuySignal[i]=low[i]; SellSignal[i]=EMPTY_VALUE; if(i==0) Notify.Message(SIGNAL_BUY); } else if(ADXCloud[i+1]<0 && FastRVI[i+1]<SlowRVI[i+1] && FastRVI[i+2]>SlowRVI[i+2]) { SellSignal[i]=high[i]; BuySignal[i]=EMPTY_VALUE; if(i==0) Notify.Message(SIGNAL_SELL); } else { BuySignal[i]=EMPTY_VALUE; SellSignal[i]=EMPTY_VALUE; } }
ここでは、ゼロバーにシグナルがあるかどうかを確認し、ある場合は、ターミナルユーザに通知します。
取引エキスパートアドバイザーでの実用的な適用
通常、指標には2種類の音声アラートで十分です。さらに、アラートを実装して、オシレータの買われ過ぎゾーンに入る値、ボリンジャーバンドのチャネルブレイクアウトなどについて通知することができます。エキスパートアドバイザーでは、さらに多くのアラートを使用できます。それでは、市場へのエントリシグナルについて通知するだけでなく、どのポジションタイプが開かれているかなどのさらなるアクションについてもコメントするテスト自動売買ロボットを作成しましょう。まず、エキスパートアドバイザーのエントリ戦略を定義しましょう。
パラメータ | 説明 |
---|---|
使用される指標 | ColorStDev |
使用される指標 | 3つのTironeレベル |
時間枠の選択 | 任意 |
買いの条件 | ColorStdDevヒストグラムは赤(強い動向)で、現在の価格がTironeの上限レベルよりも高い |
売りの条件 | ColorStdDevヒストグラムは赤(強い動向)で、現在の価格がTironeの下限レベルよりも低い |
エグジット条件 | テイクプロフィット/ストップロス |
市場へのエントリポイントは図6にあるように表示されます。
図6 この戦略での市場へのエントリの例
MetaTrader 5向けに戦略を実装しましょう。一部のイベントでは音声アラートが使用されます。
//+------------------------------------------------------------------+ //| VoiceNotify.mq5 | //| Alex2356 | //| https://www.mql5.com/en/users/alex2356 | //+------------------------------------------------------------------+ #property copyright "Alex2356" #property link "https://www.mql5.com/en/users/alex2356" #property version "1.00" #include <SoundsLib/SoundsLib.mqh> #include <DoEasy25/Engine.mqh> //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ input uint InpStopLoss = 150; // Stop Loss, in pips input uint InpTakeProfit = 250; // Take Profit, in pips input double InpLot = 0.1; // Take Profit, in pips input ulong InpDeviation = 10; // Deviation input int InpMagic = 2356; // Magic number input LANGUAGE NotifyLanguage = ENGLISH; // Notification Language //--- ColorStDev indicator parameters input int StDevPeriod = 12; // Smoothing period StDev input ENUM_MA_METHOD MA_Method = MODE_EMA; // Histogram smoothing method input ENUM_APPLIED_PRICE applied_price = PRICE_CLOSE; // Applied price input int MaxTrendLevel = 90; // Maximum trend level input int MiddLeTrendLevel = 50; // Middle trend level input int FlatLevel = 20; // Flat level //--- Tirone Levels indicator parameters input int TironePeriod = 13; // Tirone Period //--- CEngine trade; CSoundsLib notify; int Handle1,Handle2; double stdev[],tirone_b[],tirone_s[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) notify.Message(AUTO_TRADING_OFF); //--- OnInitTrading(); //--- Get the handle of the ColorStDev indicator Handle1=iCustom(Symbol(),PERIOD_CURRENT,"ArticleVoiceNotify\\colorstddev", StDevPeriod, MA_Method, applied_price, MaxTrendLevel, MiddLeTrendLevel, FlatLevel ); if(Handle1==INVALID_HANDLE) { Print("Failed to get colorstddev handle"); Print("Handle = ",Handle1," error = ",GetLastError()); return(INIT_FAILED); } //--- Getting the handle of the Tirone Levels indicator Handle2=iCustom(Symbol(),PERIOD_CURRENT,"ArticleVoiceNotify\\tirone_levels_x3",TironePeriod,0); if(Handle2==INVALID_HANDLE) { Print("Failed to get Tirone Levels handle"); Print("Handle = ",Handle2," error = ",GetLastError()); return(INIT_FAILED); } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- If there are no market positions if(ExistPositions(Symbol(),-1,InpMagic)<1) { //--- Getting data for calculations if(!GetIndValue()) return; //--- Open an order if there is a buy signal if(BuySignal()) { notify.Message(SIGNAL_BUY); if(trade.OpenBuy(InpLot,Symbol(),InpMagic,InpStopLoss,InpTakeProfit)) { Sleep(1400); notify.Message(BUY_ORDER_SET); } } //--- Opening an order if there is a sell signal if(SellSignal()) { notify.Message(SIGNAL_SELL); if(trade.OpenSell(InpLot,Symbol(),InpMagic,InpStopLoss,InpTakeProfit)) { Sleep(1400); notify.Message(SELL_ORDER_SET); } } } } //+------------------------------------------------------------------+ //| Buy conditions | //+------------------------------------------------------------------+ bool BuySignal() { return(tirone_b[1]>iClose(Symbol(),PERIOD_CURRENT,1) && stdev[0]>FlatLevel)?true:false; } //+------------------------------------------------------------------+ //| Sell conditions | //+------------------------------------------------------------------+ bool SellSignal() { return(tirone_b[1]<iClose(Symbol(),PERIOD_CURRENT,1) && stdev[0]>FlatLevel)?true:false; } //+------------------------------------------------------------------+ //| Getting the current values of indicators | //+------------------------------------------------------------------+ bool GetIndValue() { return(CopyBuffer(Handle1,0,0,2,stdev)<=0 || CopyBuffer(Handle2,0,0,2,tirone_b)<=0 || CopyBuffer(Handle2,2,0,2,tirone_s)<=0 )?false:true; } //+----------------------------------------------------------------------------+ //| Returns the number of open orders | //+----------------------------------------------------------------------------+ //| Parameters: | //| op - operation (-1 - any position) | //| mn - MagicNumber (-1 - any magic number) | //+----------------------------------------------------------------------------+ int ExistPositions(string sy,int op=-1,int mn=-1) { int pos=0; uint total=PositionsTotal(); //--- for(uint i=0; i<total; i++) { if(SelectByIndex(i)) if(PositionGetString(POSITION_SYMBOL)==sy) if(op<0 || PositionGetInteger(POSITION_TYPE)==op) if(mn<0 || PositionGetInteger(POSITION_MAGIC)==mn) pos++; } return(pos); } //+------------------------------------------------------------------+ //| Select a position on the index | //+------------------------------------------------------------------+ bool SelectByIndex(const int index) { ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); //--- if(margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) { ulong ticket=PositionGetTicket(index); if(ticket==0) return(false); } else { string name=PositionGetSymbol(index); if(name=="") return(false); } //--- return(true); } //+------------------------------------------------------------------+ //| Trading Environment Initialization | //+------------------------------------------------------------------+ void OnInitTrading() { string array_used_symbols[]; //--- Fill in the array of used symbols CreateUsedSymbolsArray(SYMBOLS_MODE_CURRENT,"",array_used_symbols); //--- Set the type of the used symbol list in the symbol collection and fill in the list of symbol timeseries trade.SetUsedSymbols(array_used_symbols); //--- Pass all existing collections to the trading class trade.TradingOnInit(); trade.TradingSetMagic(InpMagic); trade.TradingSetLogLevel(LOG_LEVEL_ERROR_MSG); //--- Set synchronous passing of orders for all used symbols trade.TradingSetAsyncMode(false); //--- Set correct order expiration and filling types to all trading objects trade.TradingSetCorrectTypeExpiration(); trade.TradingSetCorrectTypeFilling(); } //+------------------------------------------------------------------+
音声アラートの使用法の観点から、このコードをより詳細に検討してみましょう。自動売買ロボット初期化関数には、取引システムがターミナルでの取引を許可されているかどうかの確認が含まれています。このオプションを無効にすると、適切な音声アラートが再生され、ユーザに通知されます。次に、OnTick()関数で、目的の取引シグナルが見つかった場合、EAは目的の買いまたは売りシグナルが見つかったことを通知します。シグナルに従ってポジションを開こうとします。成功すると、別の音声アラートが再生され、ポジションが開かれたことをユーザに通知します。
ユーザがターミナルの[エキスパート]タブのテキストアラートを見逃す可能性があるため、これらの通知ははるかに効率的です。標準の音声アラートに関しては、指標とエキスパートアドバイザーで異なる場合があり、音声の意味が常に明確であるとは限りません。音声通知は正確な情報を提供するため、はるかに便利です。
クイック取引ツールでの実用的な適用
以前の記事では、手動トレーダー向けのツールキットを開発しました。このツールキットは、独立して市場へのエントリを検索し、手動で注文し、ポジションを管理して決済します。デモ目的で、このツールキットに音声通知のシステムを追加したいと思います。これは、音声アラート機能を任意のツールに簡単に追加できることも示しています。基礎として、この記事の添付ファイルを使用します。まず、音声アラートを追加するアクションとイベントのリストを定義しましょう。
- 買いポジションまたは売りポジションを開くのに成功した
- 未決注文の出すのと削除するのに成功した
- エキスパートアドバイザーを使用して注文できるかどうかの確認
音声通知の統合を開始する前に、関連するライブラリをこのプロジェクトに関連付けます。Program.mqhを開いて次を冒頭に追加します。
//+------------------------------------------------------------------+ //| Program.mqh | //| Alex2356 | //| https://www.mql5.com/en/users/alex2356/ | //+------------------------------------------------------------------+ #include <EasyAndFastGUI\WndEvents.mqh> #include <DoEasy25\Engine.mqh> #include "Defines.mqh" #include <SoundsLib/SoundsLib.mqh>
CFastTradingクラスのprivateセクションに移動し、CSoundsLibクラスインスタンス変数を作成します。
//---
CSoundsLib m_notify;
また、ツールキットに2つの新しいパラメータを設定します。これにより、通知の有効化/無効化と言語の選択が可能になります。SimpleTrading.mq5を開いて、EAのInput Parametersセクションに新しいパラメータを追加します。
//+------------------------------------------------------------------+ //| Expert Advisor input parameters | //+------------------------------------------------------------------+ input int Inp_BaseFont = 10; // Base FontSize input color Caption = C'0,130,225'; // Caption Color input color Background = clrWhite; // Back color input LANG Language = ENGLISH; // Interface language input ulong MagicNumber = 1111; // Magic Number //--- input bool UseVoiceNotify = true; // Use Voice Notify input LANGUAGE NotifyLanguage = ENGLISH; // Notification Language
CSoundsLibクラスインスタンスm_notifyに渡すには、CFastTrading基本クラスのpublicセクションに2つのメソッドを作成して実装します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::SetNotifyLanguage(LANGUAGE lang) { m_notify.Language(lang); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::UseVoiceNotify(bool state) { m_notify.IsActive(state); } //+------------------------------------------------------------------+
SimpleTrading.mq5のOnInit()関数に実装し、入力パラメータを新しく作成したメソッドに渡します。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- tick_counter=GetTickCount(); //--- Initialize class variables program.FontName("Trebuchet MS"); program.FontSize(Inp_BaseFont); program.BackgroundColor(Background); program.CaptionColor(Caption); program.SetLanguage(Language); program.SetMagicNumber(MagicNumber); program.UseVoiceNotify(UseVoiceNotify); program.SetNotifyLanguage(NotifyLanguage); //--- Set up the trading panel if(!program.CreateGUI()) { Print(__FUNCTION__," > Failed to create graphical interface!"); return(INIT_FAILED); } program.OnInitEvent(); //--- return(INIT_SUCCEEDED); }
このようにして、音声通知システムの主な入力パラメータを設定しました。ここで、売買市場のポジションを設定するメソッドを見つけます。これらは、CFastTrading基本クラスのSetBuyOrder()およびSetSellOrder()メソッドです。 買い注文を出すメソッドの本体を開き、ポジションが正常に開かれたかどうかの確認が実行される部分を見つけます。そこに適切な音声アラートBUY_ORDER_SETを追加します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::SetBuyOrder(int id,long lparam) { if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_buy_execute.Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_B)) { //--- double lot; if(m_switch_button[0].IsPressed()) lot=LotPercent(Symbol(),ORDER_TYPE_BUY,SymbolInfoDouble(Symbol(),SYMBOL_ASK),StringToDouble(m_lot_edit[0].GetValue())); else lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[0].GetValue())); if(m_switch_button[1].IsPressed() && m_switch_button[2].IsPressed()) { double tp=double(m_tp_edit[0].GetValue()); double sl=double(m_sl_edit[0].GetValue()); if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(BUY_ORDER_SET); return(true); } } else if(!m_switch_button[1].IsPressed() && !m_switch_button[2].IsPressed()) { int tp=int(m_tp_edit[0].GetValue()); int sl=int(m_sl_edit[0].GetValue()); if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(BUY_ORDER_SET); return(true); } } else if(m_switch_button[1].IsPressed() && !m_switch_button[2].IsPressed()) { double tp=double(m_tp_edit[0].GetValue()); int sl=int(m_sl_edit[0].GetValue()); if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(BUY_ORDER_SET); return(true); } } else if(!m_switch_button[1].IsPressed() && m_switch_button[2].IsPressed()) { int tp=int(m_tp_edit[0].GetValue()); double sl=double(m_sl_edit[0].GetValue()); if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(BUY_ORDER_SET); return(true); } } } return(false); }
売りポジションを開くメソッドについても同じ変更を加えます。使用する音声アラートはSELL_ORDER_SETです。
bool CFastTrading::SetSellOrder(int id,long lparam) { if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_sell_execute.Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_S)) { //--- double lot; if(m_switch_button[3].IsPressed()) lot=LotPercent(Symbol(),ORDER_TYPE_SELL,SymbolInfoDouble(Symbol(),SYMBOL_BID),StringToDouble(m_lot_edit[1].GetValue())); else lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[1].GetValue())); //--- if(m_switch_button[4].IsPressed() && m_switch_button[5].IsPressed()) { double tp=double(m_tp_edit[1].GetValue()); double sl=double(m_sl_edit[1].GetValue()); if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(SELL_ORDER_SET); return(true); } } else if(!m_switch_button[4].IsPressed() && !m_switch_button[5].IsPressed()) { int tp=int(m_tp_edit[1].GetValue()); int sl=int(m_sl_edit[1].GetValue()); if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(SELL_ORDER_SET); return(true); } } else if(!m_switch_button[4].IsPressed() && m_switch_button[5].IsPressed()) { int tp=int(m_tp_edit[1].GetValue()); double sl=double(m_sl_edit[1].GetValue()); if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(SELL_ORDER_SET); return(true); } } else if(m_switch_button[4].IsPressed() && !m_switch_button[5].IsPressed()) { double tp=double(m_tp_edit[1].GetValue()); int sl=int(m_sl_edit[1].GetValue()); if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp)) { m_notify.Message(SELL_ORDER_SET); return(true); } } } return(false); }
未決注文に移ります。ツールキットは4つのタイプをサポートし、それぞれに個別のメソッドがあります。
bool SetBuyStopOrder(int id,long lparam); bool SetSellStopOrder(int id,long lparam); bool SetBuyLimitOrder(int id,long lparam); bool SetSellLimitOrder(int id,long lparam);
それぞれに個別の音声通知を設定する必要があります。これはBuyStop注文の例ですが、他の注文も同様の方法で設定されます。以下のコードからわかるように、BUYSTOP_ORDER_SET通知が使用されます。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::SetBuyStopOrder(int id,long lparam) { if(!m_orders_windows[1].IsVisible()) return(false); if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_buystop_execute.Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_1)) { //--- double lot; if(m_p_switch_button[0].IsPressed()) lot=LotPercent(Symbol(),ORDER_TYPE_BUY,SymbolInfoDouble(Symbol(),SYMBOL_ASK),StringToDouble(m_lot_edit[2].GetValue())); else lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[2].GetValue())); //--- double pr=double(m_pr_edit[0].GetValue()); //--- if(m_p_switch_button[1].IsPressed() && m_p_switch_button[2].IsPressed()) { double tp=double(m_tp_edit[2].GetValue()); double sl=double(m_sl_edit[2].GetValue()); if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number)) { m_notify.Message(BUYSTOP_ORDER_SET); return(true); } } else if(!m_p_switch_button[1].IsPressed() && !m_p_switch_button[2].IsPressed()) { int tp=int(m_tp_edit[2].GetValue()); int sl=int(m_sl_edit[2].GetValue()); if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number)) { m_notify.Message(BUYSTOP_ORDER_SET); return(true); } } else if(m_p_switch_button[1].IsPressed() && !m_p_switch_button[2].IsPressed()) { double tp=double(m_tp_edit[2].GetValue()); int sl=int(m_sl_edit[2].GetValue()); if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number)) { m_notify.Message(BUYSTOP_ORDER_SET); return(true); } } else if(!m_p_switch_button[1].IsPressed() && m_p_switch_button[2].IsPressed()) { int tp=int(m_tp_edit[2].GetValue()); double sl=double(m_sl_edit[2].GetValue()); if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number)) { m_notify.Message(BUYSTOP_ORDER_SET); return(true); } } } return(false); }
これで、未決注文の通知の準備ができたら、以前に行った注文の削除の通知を追加する必要があります。RemoveOrder()メソッドは、テーブル内の未決注文のどれを選択するかを決定します。選択した注文は、変更または削除できます。ここでは、[削除]ボタンをクリックして注文を削除します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::RemoveOrder(long lparam) { //--- Check the element ID if(lparam==m_small_button[3].Id()) { //--- Get index and symbol if(m_table_orders.SelectedItem()==WRONG_VALUE) return(false); int row=m_table_orders.SelectedItem(); ulong ticket=(ulong)m_table_orders.GetValue(0,row); //--- if(OrderSelect(ticket)) { string position_symbol=OrderGetString(ORDER_SYMBOL); // symbol ulong magic=OrderGetInteger(ORDER_MAGIC); // order MagicNumber ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); // order type if(type==ORDER_TYPE_BUY_STOP) m_notify.Message(BUYSTOP_ORDER_DELETE); else if(type==ORDER_TYPE_SELL_STOP) m_notify.Message(SELLSTOP_ORDER_DELETE); else if(type==ORDER_TYPE_BUY_LIMIT) m_notify.Message(BUYLIMIT_ORDER_DELETE); else if(type==ORDER_TYPE_SELL_LIMIT) m_notify.Message(SELLLIMIT_ORDER_DELETE); //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- set the operation parameters request.action=TRADE_ACTION_REMOVE; // trading operation type request.order = ticket; // order ticket //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) return(true); else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } //--- return(false); }
メソッド本体の変更について詳しく考えてみましょう。選択した注文のチケットが決定されると、MqlTradeRequest構造に入力し、OrderSend()メソッドを呼び出すことにより、注文の削除をリクエストするために必要なデータを受け取ります。テーブルで選択された未決注文のタイプは、type変数に基づいて決定されます。変数値に基づいて、Message()メソッドで適切な音声通知を設定します。
実装する最後のタスクは、MetaTrader5ターミナルで自動取引が無効になっている場合に音声通知を追加することです。ツールキットは実際にはエキスパートアドバイザーです。ユーザは手動で注文しますが、ターミナルとブローカーはそれらを自動取引として認識します。自動取引かどうかの確認を追加するには、基本クラスに移動し、OnEvent()ハンドラ->ON_END_CREATE_GUIセクションを見つけ、適切な音声通知で確認を追加します。
// --- GUI creation completion if(id==CHARTEVENT_CUSTOM+ON_END_CREATE_GUI) { //--- SetButtonParam(m_switch_button[0],LOT); SetButtonParam(m_switch_button[1],POINTS); SetButtonParam(m_switch_button[2],POINTS); SetButtonParam(m_switch_button[3],LOT); SetButtonParam(m_switch_button[4],POINTS); SetButtonParam(m_switch_button[5],POINTS); //--- SetButtonParam(m_p_switch_button[0],LOT); SetButtonParam(m_p_switch_button[1],POINTS); SetButtonParam(m_p_switch_button[2],POINTS); SetButtonParam(m_p_switch_button[3],LOT); SetButtonParam(m_p_switch_button[4],POINTS); SetButtonParam(m_p_switch_button[5],POINTS); SetButtonParam(m_p_switch_button[6],LOT); SetButtonParam(m_p_switch_button[7],POINTS); SetButtonParam(m_p_switch_button[8],POINTS); SetButtonParam(m_p_switch_button[9],LOT); SetButtonParam(m_p_switch_button[10],POINTS); SetButtonParam(m_p_switch_button[11],POINTS); //--- if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) m_notify.Message(AUTO_TRADING_OFF); }
以下のビデオは、クイック取引ツールキットで音声通知がどのように機能するかを示しています。このツールキットでは、アラートが市場ポジションと未決注文に使用されます。
終わりに
添付されたアーカイブには、リストされたすべてのファイルが含まれています。これらのファイルは、適切なフォルダにあります。正しく動作させるためには、MQL5フォルダをターミナルフォルダに保存するだけです。MQL5フォルダのあるルートディレクトリを開くには、MetaTrader 5ターミナルでCtrl+Shift+Dキーの組み合わせを押すか、下記の図7にあるようにコンテキストメニューを使用します。
図7 MetaTrader 5ターミナルルートでMQL5フォルダを開く
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/8111
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索